From d1f76f0b4a1fe9d0f2adcb751c5f4315c3ec0cb4 Mon Sep 17 00:00:00 2001 From: Sears Russell Date: Thu, 24 Jun 2004 21:10:31 +0000 Subject: [PATCH] Initial revision --- AUTHORS | 4 + COPYING | 45 + ChangeLog | 0 Makefile.am | 9 + NEWS | 3 + NOTES | 160 + README | 31 + autoscan.log | 2 + bootstrap | 11 + clean.sh | 10 + config.h | 188 + configure.in | 72 + libdfa/Makefile | 197 + libdfa/Makefile.am | 0 libdfa/libdfa.h | 160 + libdfa/messages.h | 130 + libdfa/rw.h | 91 + libdfa/smash.h | 84 + libdfa/statemachine.h | 163 + lladd.prj | 306 + lladd.pws | 78 + lladd/Makefile | 197 + lladd/Makefile.am | 0 lladd/bufferManager.h | 288 + lladd/common.h | 105 + lladd/config.h.in | 178 + lladd/constants.h | 126 + lladd/logger.h | 126 + lladd/logger/logEntry.h | 129 + lladd/logger/logHandle.h | 115 + lladd/logger/logWriter.h | 158 + lladd/logger/logger2.h | 123 + lladd/operations.h | 179 + lladd/operations/alloc.h | 11 + lladd/operations/decrement.h | 65 + lladd/operations/increment.h | 68 + lladd/operations/lladdhash.h | 78 + lladd/operations/prepare.h | 71 + lladd/operations/set.h | 62 + lladd/page.h | 150 + lladd/recovery2.h | 9 + lladd/stamp-h.in | 0 lladd/stamp-h1 | 1 + lladd/transactional.h | 186 + mkinstalldirs | 40 + pbl/Makefile | 197 + pbl/Makefile.am | 0 pbl/jbhash.h | 176 + pbl/pbl.h | 549 ++ reconf | 11 + src/2pc/2pc.c | 285 + src/2pc/2pc.h | 153 + src/2pc/Makefile.am | 4 + src/Makefile.am | 1 + src/apps/Makefile.am | 1 + src/apps/cht/Makefile.am | 5 + src/apps/cht/cht.c | 652 ++ src/apps/cht/cht.h | 140 + src/apps/cyrus/.deps/cyrusdb_lladd.Po | 1 + src/apps/cyrus/.deps/libcyrusdb_lladd.Po | 1 + src/apps/cyrus/Makefile | 371 + src/apps/cyrus/Makefile.am | 5 + src/apps/cyrus/cyrusdb_lladd.c | 492 ++ src/libdfa/Makefile.am | 4 + src/libdfa/callbacks.c | 88 + src/libdfa/callbacks.h | 75 + src/libdfa/libdfa.c | 765 ++ src/libdfa/messages.c | 318 + src/libdfa/monotree.c | 354 + src/libdfa/monotree.h | 92 + src/libdfa/rw.c | 157 + src/libdfa/smash.c | 226 + src/lladd/1 | 4 + src/lladd/Makefile.am | 8 + src/lladd/bufferManager.c | 439 ++ src/lladd/linkedlist.c | 162 + src/lladd/linkedlist.h | 97 + src/lladd/logger/.deps/logger.Po | 129 + src/lladd/logger/.deps/logparser.Po | 107 + src/lladd/logger/.deps/logstreamer.Po | 92 + src/lladd/logger/Makefile.am-old | 3 + src/lladd/logger/logEntry.c | 132 + src/lladd/logger/logHandle.c | 125 + src/lladd/logger/logWriter.c | 203 + src/lladd/logger/logger.c | 142 + src/lladd/logger/logger2.c | 112 + src/lladd/logger/logparser.c | 316 + src/lladd/logger/logparser.h | 206 + src/lladd/logger/logstreamer.c | 148 + src/lladd/logger/logstreamer.h | 135 + src/lladd/operations.c | 113 + src/lladd/operations/.deps/decrement.Po | 122 + src/lladd/operations/.deps/increment.Po | 122 + src/lladd/operations/.deps/lladdhash.Po | 127 + src/lladd/operations/.deps/prepare.Po | 125 + src/lladd/operations/.deps/set.Po | 123 + src/lladd/operations/Makefile.am-old | 3 + src/lladd/operations/alloc.c | 69 + src/lladd/operations/decrement.c | 69 + src/lladd/operations/increment.c | 68 + src/lladd/operations/lladdhash.c | 456 ++ src/lladd/operations/prepare.c | 116 + src/lladd/operations/set.c | 63 + src/lladd/page.c | 826 +++ src/lladd/recovery.c | 460 ++ src/lladd/recovery.h | 65 + src/lladd/recovery2.c | 270 + src/lladd/transactional.c | 182 + src/lladd/transactional2.c | 136 + src/pbl/ISAM0001.TST | 1366 ++++ src/pbl/ISAM0002.TST | 177 + src/pbl/ISAM0003.TST | 86 + src/pbl/ISAM0004.TST | 406 + src/pbl/ISAM0005.TST | 322 + src/pbl/Makefile.am | 4 + src/pbl/README.DOC | 7 + src/pbl/classFooter.inc | 3 + src/pbl/classHeader.inc | 3 + src/pbl/doc/AIntroduction.html | 90 + src/pbl/doc/BFiles.html | 53 + src/pbl/doc/CErrorcodes.html | 41 + .../doc/DDefinitionsforKeyFileParameters.html | 28 + .../doc/EDefinitionsforISAMParameters.html | 26 + src/pbl/doc/General.html | 19 + src/pbl/doc/PBLDATALENGTH.html | 25 + src/pbl/doc/PBLKEYLENGTH.html | 24 + src/pbl/doc/PBL_FREE.html | 24 + src/pbl/doc/PBL_LIST_.html | 23 + src/pbl/doc/PBL_LIST_APPEND.html | 23 + src/pbl/doc/PBL_LIST_PUSH.html | 23 + src/pbl/doc/PBL_LIST_UNLINK.html | 23 + src/pbl/doc/gifs.db | 0 src/pbl/doc/icon1.gif | Bin 0 -> 326 bytes src/pbl/doc/icon2.gif | Bin 0 -> 326 bytes src/pbl/doc/index.html | 108 + src/pbl/doc/pblHashTable_t.html | 24 + src/pbl/doc/pblHtCreate.html | 26 + src/pbl/doc/pblHtCurrent.html | 28 + src/pbl/doc/pblHtDelete.html | 30 + src/pbl/doc/pblHtFirst.html | 40 + src/pbl/doc/pblHtInsert.html | 35 + src/pbl/doc/pblHtLookup.html | 30 + src/pbl/doc/pblHtNext.html | 40 + src/pbl/doc/pblHtRemove.html | 61 + src/pbl/doc/pblISAMFILE_TestFrame.html | 74 + src/pbl/doc/pblIsamClose.html | 30 + src/pbl/doc/pblIsamCommit.html | 40 + src/pbl/doc/pblIsamDelete.html | 37 + src/pbl/doc/pblIsamFile_t.html | 24 + src/pbl/doc/pblIsamFind.html | 66 + src/pbl/doc/pblIsamFlush.html | 29 + src/pbl/doc/pblIsamGet.html | 62 + src/pbl/doc/pblIsamInsert.html | 52 + src/pbl/doc/pblIsamOpen.html | 40 + src/pbl/doc/pblIsamReadData.html | 32 + src/pbl/doc/pblIsamReadDatalen.html | 28 + src/pbl/doc/pblIsamReadKey.html | 46 + src/pbl/doc/pblIsamSetCompareFunction.html | 43 + src/pbl/doc/pblIsamStartTransaction.html | 32 + src/pbl/doc/pblIsamUpdateData.html | 34 + src/pbl/doc/pblIsamUpdateKey.html | 34 + src/pbl/doc/pblKEYFILE_TestFrame.html | 142 + src/pbl/doc/pblKeyFile_t.html | 24 + src/pbl/doc/pblKfClose.html | 30 + src/pbl/doc/pblKfCommit.html | 39 + src/pbl/doc/pblKfCreate.html | 38 + src/pbl/doc/pblKfDelete.html | 40 + src/pbl/doc/pblKfFind.html | 68 + src/pbl/doc/pblKfFirst.html | 23 + src/pbl/doc/pblKfFlush.html | 29 + src/pbl/doc/pblKfGetAbs.html | 48 + src/pbl/doc/pblKfGetRel.html | 49 + src/pbl/doc/pblKfInit.html | 28 + src/pbl/doc/pblKfInsert.html | 46 + src/pbl/doc/pblKfLast.html | 23 + src/pbl/doc/pblKfNext.html | 23 + src/pbl/doc/pblKfOpen.html | 42 + src/pbl/doc/pblKfPrev.html | 23 + src/pbl/doc/pblKfRead.html | 39 + src/pbl/doc/pblKfRestorePosition.html | 28 + src/pbl/doc/pblKfSavePosition.html | 27 + src/pbl/doc/pblKfSetCompareFunction.html | 38 + src/pbl/doc/pblKfStartTransaction.html | 31 + src/pbl/doc/pblKfThis.html | 23 + src/pbl/doc/pblKfUpdate.html | 43 + src/pbl/doc/pbl_BufToLong.html | 26 + src/pbl/doc/pbl_BufToShort.html | 26 + src/pbl/doc/pbl_LongSize.html | 26 + src/pbl/doc/pbl_LongToBuf.html | 25 + src/pbl/doc/pbl_LongToVarBuf.html | 25 + src/pbl/doc/pbl_ShortToBuf.html | 25 + src/pbl/doc/pbl_VarBufSize.html | 26 + src/pbl/doc/pbl_VarBufToLong.html | 27 + src/pbl/doc/pbl_errno.html | 23 + src/pbl/doc/pbl_errstr.html | 23 + src/pbl/doc/pbl_malloc.html | 28 + src/pbl/doc/pbl_malloc0.html | 28 + src/pbl/doc/pbl_mem2dup.html | 31 + src/pbl/doc/pbl_memcmp.html | 31 + src/pbl/doc/pbl_memcmplen.html | 29 + src/pbl/doc/pbl_memdup.html | 29 + src/pbl/doc/pbl_memlcpy.html | 29 + src/pbl/gpl2.txt | 340 + src/pbl/hierFooter.inc | 3 + src/pbl/hierHeader.inc | 4 + src/pbl/indexFooter.inc | 3 + src/pbl/indexHeader.inc | 4 + src/pbl/jbhash.c | 295 + src/pbl/lgpl2_1.txt | 504 ++ src/pbl/license.txt | 504 ++ src/pbl/makefile-old | 64 + src/pbl/pbl.c | 723 ++ src/pbl/pbl.dxx | 81 + src/pbl/pblhash.c | 532 ++ src/pbl/pblhttst | Bin 0 -> 45923 bytes src/pbl/pblhttst.c | 174 + src/pbl/pblhttstdeb.dsp | 89 + src/pbl/pblhttstdeb.dsw | 29 + src/pbl/pbliftst | Bin 0 -> 165295 bytes src/pbl/pbliftst.c | 982 +++ src/pbl/pbliftst.log | 406 + src/pbl/pbliftstdeb.dsp | 93 + src/pbl/pbliftstdeb.dsw | 29 + src/pbl/pbliftstdeb.ncb | Bin 0 -> 99327 bytes src/pbl/pbliftstdeb.opt | Bin 0 -> 55808 bytes src/pbl/pbliftstdeb.plg | 45 + src/pbl/pblisam.c | 3399 +++++++++ src/pbl/pblkf.c | 6523 +++++++++++++++++ src/pbl/pblkfblockprint | Bin 0 -> 110601 bytes src/pbl/pblkfblockprint.c | 74 + src/pbl/pblkfblockprint.dsp | 93 + src/pbl/pblkfblockprint.dsw | 29 + src/pbl/pblkftst | Bin 0 -> 130359 bytes src/pbl/pblkftst.c | 818 +++ src/pbl/pblkftstdeb.dsp | 93 + src/pbl/pblkftstdeb.dsw | 29 + src/pbl/pbltest.c | 124 + src/timing/Makefile.am | 3 + src/timing/README | 31 + src/timing/getTimeOfDay.c | 55 + .../plotting-test-case/FOO-Berkeley DB.dat | 9 + src/timing/plotting-test-case/FOO-LLADD.dat | 9 + src/timing/plotting-test-case/FOO.def | 3 + src/timing/plotting-test-case/FOO.ps | 380 + src/timing/plotting.pl | 162 + src/timing/t-distribution.tbl | 48 + src/timing/timer.pl | 116 + src/timing/timer.pl-old | 91 + src/timing/timer.pl-olf | 117 + stamp-h.in | 1 + test/2pc/Makefile.am | 4 + test/2pc/always_commit.c | 151 + test/2pc/always_commit_script | 2 + test/Makefile.am | 11 + test/README.coredumps | 5 + test/check_check.c | 96 + test/check_includes.h | 11 + test/check_setup.h | 56 + test/cht/Makefile.am | 4 + test/cht/cht_server.c | 126 + test/cht/simple.c | 168 + test/dfa/Makefile.am | 3 + test/dfa/fork_bomb.c | 193 + test/dfa/ping_pong_dfa.c | 162 + test/dfa/star.c | 160 + test/lladd-old/Makefile | 197 + test/lladd-old/Makefile.am | 0 test/lladd-old/TAbort.c | 94 + test/lladd-old/TGet.c | 83 + test/lladd-old/TInsert.c | 128 + test/lladd-old/TInsertSequential.c | 93 + test/lladd-old/TUpdate.c | 113 + test/lladd-old/abort-speed.c | 101 + test/lladd-old/abort.c | 116 + test/lladd-old/commit-speed.c | 92 + test/lladd-old/db41/dbAbort.c | 225 + test/lladd-old/db41/dbGet.c | 233 + test/lladd-old/db41/dbInsert.c | 251 + test/lladd-old/db41/dbInsertSequential.c | 225 + test/lladd-old/db41/dbUpdate.c | 227 + test/lladd-old/db41/jbhashmany.c | 199 + test/lladd-old/db41/jbhashsimple.c | 127 + test/lladd-old/inc_dec.c | 155 + test/lladd-old/interleaved.c | 101 + test/lladd-old/jbhashdisk.c | 84 + test/lladd-old/jbhashmany.c | 84 + test/lladd-old/jbht-speed.c | 95 + test/lladd-old/jbhtsimple.c | 89 + test/lladd-old/lhmany.c | 85 + test/lladd-old/lhpackingfactor.c | 98 + test/lladd-old/lhpackingfactor.script | 9 + test/lladd-old/lladdHashTest.c | 179 + test/lladd-old/logvals.c | 142 + test/lladd-old/loop.c | 73 + test/lladd-old/nontrans.c | 67 + test/lladd-old/prepare_1.c | 101 + test/lladd-old/prepare_2.c | 80 + test/lladd-old/prepare_3.c | 77 + test/lladd-old/rand_str.c | 91 + test/lladd-old/rand_str.h | 43 + test/lladd-old/recover.c | 54 + test/lladd-old/strings.c | 129 + test/lladd-old/test.c | 60 + test/lladd-old/test.h | 52 + test/lladd-old/test0.c | 52 + test/lladd-old/test1.c | 99 + test/lladd-old/test2.c | 99 + test/lladd-old/test3.c | 126 + test/lladd-old/twentyfour.c | 87 + test/lladd-old/twentyfour2.c | 127 + test/lladd/Makefile.am | 11 + test/lladd/check_lht.c | 383 + test/lladd/check_logEntry.c | 192 + test/lladd/check_logWriter.c | 186 + test/lladd/check_operations.c | 168 + test/lladd/check_recovery.c | 509 ++ test/lladd/check_transactional2.c | 106 + test/messages/Makefile.am | 0 test/messages/ping_pong.c | 94 + test/monotree/Makefile.am | 4 + test/monotree/binary_search.c | 77 + test/monotree/bit_arithmetic.c | 67 + test/monotree/soundness.c | 190 + 323 files changed, 46021 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 NOTES create mode 100644 README create mode 100644 autoscan.log create mode 100755 bootstrap create mode 100755 clean.sh create mode 100644 config.h create mode 100644 configure.in create mode 100644 libdfa/Makefile create mode 100644 libdfa/Makefile.am create mode 100644 libdfa/libdfa.h create mode 100644 libdfa/messages.h create mode 100644 libdfa/rw.h create mode 100644 libdfa/smash.h create mode 100644 libdfa/statemachine.h create mode 100644 lladd.prj create mode 100644 lladd.pws create mode 100644 lladd/Makefile create mode 100644 lladd/Makefile.am create mode 100644 lladd/bufferManager.h create mode 100644 lladd/common.h create mode 100644 lladd/config.h.in create mode 100644 lladd/constants.h create mode 100644 lladd/logger.h create mode 100644 lladd/logger/logEntry.h create mode 100644 lladd/logger/logHandle.h create mode 100644 lladd/logger/logWriter.h create mode 100644 lladd/logger/logger2.h create mode 100644 lladd/operations.h create mode 100644 lladd/operations/alloc.h create mode 100644 lladd/operations/decrement.h create mode 100644 lladd/operations/increment.h create mode 100644 lladd/operations/lladdhash.h create mode 100644 lladd/operations/prepare.h create mode 100644 lladd/operations/set.h create mode 100644 lladd/page.h create mode 100644 lladd/recovery2.h create mode 100644 lladd/stamp-h.in create mode 100644 lladd/stamp-h1 create mode 100644 lladd/transactional.h create mode 100755 mkinstalldirs create mode 100644 pbl/Makefile create mode 100644 pbl/Makefile.am create mode 100644 pbl/jbhash.h create mode 100644 pbl/pbl.h create mode 100755 reconf create mode 100644 src/2pc/2pc.c create mode 100644 src/2pc/2pc.h create mode 100644 src/2pc/Makefile.am create mode 100644 src/Makefile.am create mode 100644 src/apps/Makefile.am create mode 100644 src/apps/cht/Makefile.am create mode 100644 src/apps/cht/cht.c create mode 100644 src/apps/cht/cht.h create mode 100644 src/apps/cyrus/.deps/cyrusdb_lladd.Po create mode 100644 src/apps/cyrus/.deps/libcyrusdb_lladd.Po create mode 100644 src/apps/cyrus/Makefile create mode 100644 src/apps/cyrus/Makefile.am create mode 100644 src/apps/cyrus/cyrusdb_lladd.c create mode 100644 src/libdfa/Makefile.am create mode 100644 src/libdfa/callbacks.c create mode 100644 src/libdfa/callbacks.h create mode 100644 src/libdfa/libdfa.c create mode 100644 src/libdfa/messages.c create mode 100644 src/libdfa/monotree.c create mode 100644 src/libdfa/monotree.h create mode 100644 src/libdfa/rw.c create mode 100644 src/libdfa/smash.c create mode 100644 src/lladd/1 create mode 100644 src/lladd/Makefile.am create mode 100644 src/lladd/bufferManager.c create mode 100644 src/lladd/linkedlist.c create mode 100644 src/lladd/linkedlist.h create mode 100644 src/lladd/logger/.deps/logger.Po create mode 100644 src/lladd/logger/.deps/logparser.Po create mode 100644 src/lladd/logger/.deps/logstreamer.Po create mode 100644 src/lladd/logger/Makefile.am-old create mode 100644 src/lladd/logger/logEntry.c create mode 100644 src/lladd/logger/logHandle.c create mode 100644 src/lladd/logger/logWriter.c create mode 100644 src/lladd/logger/logger.c create mode 100644 src/lladd/logger/logger2.c create mode 100644 src/lladd/logger/logparser.c create mode 100644 src/lladd/logger/logparser.h create mode 100644 src/lladd/logger/logstreamer.c create mode 100644 src/lladd/logger/logstreamer.h create mode 100644 src/lladd/operations.c create mode 100644 src/lladd/operations/.deps/decrement.Po create mode 100644 src/lladd/operations/.deps/increment.Po create mode 100644 src/lladd/operations/.deps/lladdhash.Po create mode 100644 src/lladd/operations/.deps/prepare.Po create mode 100644 src/lladd/operations/.deps/set.Po create mode 100644 src/lladd/operations/Makefile.am-old create mode 100644 src/lladd/operations/alloc.c create mode 100644 src/lladd/operations/decrement.c create mode 100644 src/lladd/operations/increment.c create mode 100644 src/lladd/operations/lladdhash.c create mode 100644 src/lladd/operations/prepare.c create mode 100644 src/lladd/operations/set.c create mode 100644 src/lladd/page.c create mode 100644 src/lladd/recovery.c create mode 100644 src/lladd/recovery.h create mode 100644 src/lladd/recovery2.c create mode 100644 src/lladd/transactional.c create mode 100644 src/lladd/transactional2.c create mode 100644 src/pbl/ISAM0001.TST create mode 100644 src/pbl/ISAM0002.TST create mode 100644 src/pbl/ISAM0003.TST create mode 100644 src/pbl/ISAM0004.TST create mode 100644 src/pbl/ISAM0005.TST create mode 100644 src/pbl/Makefile.am create mode 100644 src/pbl/README.DOC create mode 100644 src/pbl/classFooter.inc create mode 100644 src/pbl/classHeader.inc create mode 100755 src/pbl/doc/AIntroduction.html create mode 100755 src/pbl/doc/BFiles.html create mode 100755 src/pbl/doc/CErrorcodes.html create mode 100755 src/pbl/doc/DDefinitionsforKeyFileParameters.html create mode 100755 src/pbl/doc/EDefinitionsforISAMParameters.html create mode 100755 src/pbl/doc/General.html create mode 100755 src/pbl/doc/PBLDATALENGTH.html create mode 100755 src/pbl/doc/PBLKEYLENGTH.html create mode 100755 src/pbl/doc/PBL_FREE.html create mode 100755 src/pbl/doc/PBL_LIST_.html create mode 100755 src/pbl/doc/PBL_LIST_APPEND.html create mode 100755 src/pbl/doc/PBL_LIST_PUSH.html create mode 100755 src/pbl/doc/PBL_LIST_UNLINK.html create mode 100755 src/pbl/doc/gifs.db create mode 100755 src/pbl/doc/icon1.gif create mode 100755 src/pbl/doc/icon2.gif create mode 100755 src/pbl/doc/index.html create mode 100755 src/pbl/doc/pblHashTable_t.html create mode 100755 src/pbl/doc/pblHtCreate.html create mode 100755 src/pbl/doc/pblHtCurrent.html create mode 100755 src/pbl/doc/pblHtDelete.html create mode 100755 src/pbl/doc/pblHtFirst.html create mode 100755 src/pbl/doc/pblHtInsert.html create mode 100755 src/pbl/doc/pblHtLookup.html create mode 100755 src/pbl/doc/pblHtNext.html create mode 100755 src/pbl/doc/pblHtRemove.html create mode 100755 src/pbl/doc/pblISAMFILE_TestFrame.html create mode 100755 src/pbl/doc/pblIsamClose.html create mode 100755 src/pbl/doc/pblIsamCommit.html create mode 100755 src/pbl/doc/pblIsamDelete.html create mode 100755 src/pbl/doc/pblIsamFile_t.html create mode 100755 src/pbl/doc/pblIsamFind.html create mode 100755 src/pbl/doc/pblIsamFlush.html create mode 100755 src/pbl/doc/pblIsamGet.html create mode 100755 src/pbl/doc/pblIsamInsert.html create mode 100755 src/pbl/doc/pblIsamOpen.html create mode 100755 src/pbl/doc/pblIsamReadData.html create mode 100755 src/pbl/doc/pblIsamReadDatalen.html create mode 100755 src/pbl/doc/pblIsamReadKey.html create mode 100755 src/pbl/doc/pblIsamSetCompareFunction.html create mode 100755 src/pbl/doc/pblIsamStartTransaction.html create mode 100755 src/pbl/doc/pblIsamUpdateData.html create mode 100755 src/pbl/doc/pblIsamUpdateKey.html create mode 100755 src/pbl/doc/pblKEYFILE_TestFrame.html create mode 100755 src/pbl/doc/pblKeyFile_t.html create mode 100755 src/pbl/doc/pblKfClose.html create mode 100755 src/pbl/doc/pblKfCommit.html create mode 100755 src/pbl/doc/pblKfCreate.html create mode 100755 src/pbl/doc/pblKfDelete.html create mode 100755 src/pbl/doc/pblKfFind.html create mode 100755 src/pbl/doc/pblKfFirst.html create mode 100755 src/pbl/doc/pblKfFlush.html create mode 100755 src/pbl/doc/pblKfGetAbs.html create mode 100755 src/pbl/doc/pblKfGetRel.html create mode 100755 src/pbl/doc/pblKfInit.html create mode 100755 src/pbl/doc/pblKfInsert.html create mode 100755 src/pbl/doc/pblKfLast.html create mode 100755 src/pbl/doc/pblKfNext.html create mode 100755 src/pbl/doc/pblKfOpen.html create mode 100755 src/pbl/doc/pblKfPrev.html create mode 100755 src/pbl/doc/pblKfRead.html create mode 100755 src/pbl/doc/pblKfRestorePosition.html create mode 100755 src/pbl/doc/pblKfSavePosition.html create mode 100755 src/pbl/doc/pblKfSetCompareFunction.html create mode 100755 src/pbl/doc/pblKfStartTransaction.html create mode 100755 src/pbl/doc/pblKfThis.html create mode 100755 src/pbl/doc/pblKfUpdate.html create mode 100755 src/pbl/doc/pbl_BufToLong.html create mode 100755 src/pbl/doc/pbl_BufToShort.html create mode 100755 src/pbl/doc/pbl_LongSize.html create mode 100755 src/pbl/doc/pbl_LongToBuf.html create mode 100755 src/pbl/doc/pbl_LongToVarBuf.html create mode 100755 src/pbl/doc/pbl_ShortToBuf.html create mode 100755 src/pbl/doc/pbl_VarBufSize.html create mode 100755 src/pbl/doc/pbl_VarBufToLong.html create mode 100755 src/pbl/doc/pbl_errno.html create mode 100755 src/pbl/doc/pbl_errstr.html create mode 100755 src/pbl/doc/pbl_malloc.html create mode 100755 src/pbl/doc/pbl_malloc0.html create mode 100755 src/pbl/doc/pbl_mem2dup.html create mode 100755 src/pbl/doc/pbl_memcmp.html create mode 100755 src/pbl/doc/pbl_memcmplen.html create mode 100755 src/pbl/doc/pbl_memdup.html create mode 100755 src/pbl/doc/pbl_memlcpy.html create mode 100644 src/pbl/gpl2.txt create mode 100644 src/pbl/hierFooter.inc create mode 100644 src/pbl/hierHeader.inc create mode 100644 src/pbl/indexFooter.inc create mode 100644 src/pbl/indexHeader.inc create mode 100644 src/pbl/jbhash.c create mode 100644 src/pbl/lgpl2_1.txt create mode 100644 src/pbl/license.txt create mode 100644 src/pbl/makefile-old create mode 100644 src/pbl/pbl.c create mode 100644 src/pbl/pbl.dxx create mode 100644 src/pbl/pblhash.c create mode 100755 src/pbl/pblhttst create mode 100644 src/pbl/pblhttst.c create mode 100644 src/pbl/pblhttstdeb.dsp create mode 100755 src/pbl/pblhttstdeb.dsw create mode 100755 src/pbl/pbliftst create mode 100644 src/pbl/pbliftst.c create mode 100644 src/pbl/pbliftst.log create mode 100644 src/pbl/pbliftstdeb.dsp create mode 100755 src/pbl/pbliftstdeb.dsw create mode 100755 src/pbl/pbliftstdeb.ncb create mode 100755 src/pbl/pbliftstdeb.opt create mode 100755 src/pbl/pbliftstdeb.plg create mode 100644 src/pbl/pblisam.c create mode 100644 src/pbl/pblkf.c create mode 100755 src/pbl/pblkfblockprint create mode 100644 src/pbl/pblkfblockprint.c create mode 100644 src/pbl/pblkfblockprint.dsp create mode 100755 src/pbl/pblkfblockprint.dsw create mode 100755 src/pbl/pblkftst create mode 100644 src/pbl/pblkftst.c create mode 100644 src/pbl/pblkftstdeb.dsp create mode 100755 src/pbl/pblkftstdeb.dsw create mode 100644 src/pbl/pbltest.c create mode 100644 src/timing/Makefile.am create mode 100644 src/timing/README create mode 100644 src/timing/getTimeOfDay.c create mode 100644 src/timing/plotting-test-case/FOO-Berkeley DB.dat create mode 100644 src/timing/plotting-test-case/FOO-LLADD.dat create mode 100644 src/timing/plotting-test-case/FOO.def create mode 100644 src/timing/plotting-test-case/FOO.ps create mode 100755 src/timing/plotting.pl create mode 100644 src/timing/t-distribution.tbl create mode 100755 src/timing/timer.pl create mode 100755 src/timing/timer.pl-old create mode 100755 src/timing/timer.pl-olf create mode 100644 stamp-h.in create mode 100644 test/2pc/Makefile.am create mode 100644 test/2pc/always_commit.c create mode 100644 test/2pc/always_commit_script create mode 100644 test/Makefile.am create mode 100644 test/README.coredumps create mode 100644 test/check_check.c create mode 100644 test/check_includes.h create mode 100644 test/check_setup.h create mode 100644 test/cht/Makefile.am create mode 100644 test/cht/cht_server.c create mode 100644 test/cht/simple.c create mode 100644 test/dfa/Makefile.am create mode 100644 test/dfa/fork_bomb.c create mode 100644 test/dfa/ping_pong_dfa.c create mode 100644 test/dfa/star.c create mode 100644 test/lladd-old/Makefile create mode 100644 test/lladd-old/Makefile.am create mode 100644 test/lladd-old/TAbort.c create mode 100644 test/lladd-old/TGet.c create mode 100644 test/lladd-old/TInsert.c create mode 100644 test/lladd-old/TInsertSequential.c create mode 100644 test/lladd-old/TUpdate.c create mode 100644 test/lladd-old/abort-speed.c create mode 100644 test/lladd-old/abort.c create mode 100644 test/lladd-old/commit-speed.c create mode 100644 test/lladd-old/db41/dbAbort.c create mode 100644 test/lladd-old/db41/dbGet.c create mode 100644 test/lladd-old/db41/dbInsert.c create mode 100644 test/lladd-old/db41/dbInsertSequential.c create mode 100644 test/lladd-old/db41/dbUpdate.c create mode 100644 test/lladd-old/db41/jbhashmany.c create mode 100644 test/lladd-old/db41/jbhashsimple.c create mode 100644 test/lladd-old/inc_dec.c create mode 100644 test/lladd-old/interleaved.c create mode 100644 test/lladd-old/jbhashdisk.c create mode 100644 test/lladd-old/jbhashmany.c create mode 100644 test/lladd-old/jbht-speed.c create mode 100644 test/lladd-old/jbhtsimple.c create mode 100644 test/lladd-old/lhmany.c create mode 100644 test/lladd-old/lhpackingfactor.c create mode 100644 test/lladd-old/lhpackingfactor.script create mode 100644 test/lladd-old/lladdHashTest.c create mode 100644 test/lladd-old/logvals.c create mode 100644 test/lladd-old/loop.c create mode 100644 test/lladd-old/nontrans.c create mode 100644 test/lladd-old/prepare_1.c create mode 100644 test/lladd-old/prepare_2.c create mode 100644 test/lladd-old/prepare_3.c create mode 100644 test/lladd-old/rand_str.c create mode 100644 test/lladd-old/rand_str.h create mode 100644 test/lladd-old/recover.c create mode 100644 test/lladd-old/strings.c create mode 100644 test/lladd-old/test.c create mode 100644 test/lladd-old/test.h create mode 100644 test/lladd-old/test0.c create mode 100644 test/lladd-old/test1.c create mode 100644 test/lladd-old/test2.c create mode 100644 test/lladd-old/test3.c create mode 100644 test/lladd-old/twentyfour.c create mode 100644 test/lladd-old/twentyfour2.c create mode 100644 test/lladd/Makefile.am create mode 100644 test/lladd/check_lht.c create mode 100644 test/lladd/check_logEntry.c create mode 100644 test/lladd/check_logWriter.c create mode 100644 test/lladd/check_operations.c create mode 100644 test/lladd/check_recovery.c create mode 100644 test/lladd/check_transactional2.c create mode 100644 test/messages/Makefile.am create mode 100644 test/messages/ping_pong.c create mode 100644 test/monotree/Makefile.am create mode 100644 test/monotree/binary_search.c create mode 100644 test/monotree/bit_arithmetic.c create mode 100644 test/monotree/soundness.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..6a7056d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Jason Bayer bayer@xcf.berkeley.edu +Jim Blomo jim@xcf.berkeley.edu +Jimmy Kittiyachavalit jkit@xcf.berkeley.edu +Russell Sears sears@cs.berkeley.edu \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..27e9ff2 --- /dev/null +++ b/COPYING @@ -0,0 +1,45 @@ +/* + +LLADD LICENSE TERMS - (TCL/TK License) + +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +*/ \ No newline at end of file diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6bd87a7 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,9 @@ +EXTRA_DIST = reconf +SUBDIRS = src test +AM_CFLAGS = -g -Wall -pedantic + +docs: + doxygen doc/Doxyfile-api + doxygen doc/Doxyfile-developers + +.PHONY: docs \ No newline at end of file diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..1ae9694 --- /dev/null +++ b/NEWS @@ -0,0 +1,3 @@ +Jun 9, 2004: + + Set version number to 0.5, retired old directory structure, and added autoconf / unit testing framework. diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..1cbb956 --- /dev/null +++ b/NOTES @@ -0,0 +1,160 @@ +create new record + get a page with enough free space + check existing pages for free space + create a new emtpy page + alloc a record on that page + increment number of records on this page + update free space pointer +write to record + load the page into memory + find the page on disk + put the page in memory + lock the page + get the memory address of the record + look up the record offset in the slot directory + write to that record + update log + update lsn on page + +read record + load the page into memory + get the address of the record + read that record + + +begin xaction + +commit xaction + flush + unlock + +abort xaction + delete page from memory + unlock + +================================================================================ + +recordid memory.ralloc(int xid, size_t size) { + for each page in the page table // page table are pages in RAM + if locked, continue + // context switch here SUCKS + lock page + break if freeSpace(page) >= size + free page + if no free page + create a new page and lock and load + + + + return (recordid) page.recordAllocate(page, size) + +} + + +void page.writeRecord(recordid rid, void *data) { + + assert page locked and loaded + if xid and recordid is in hash table, do nothing + else make shadow record + memcpy() + +} + + +void *page.readRecord(recordid rid, void *buff) { + make sure page is loaded + memcpy() + return pointer +} + +commitXaction(int xid) { + for each page that this xid has locked + unlock page + if pin count of page == 0 + flush + + +} + + +abortXaction(int xid) { + for each locked page + restore shadow records + unlock page + +} + + +================================================================================ + +transactional.c + Tread + Tbegin + Tcommit + Tabort +operations.h + Tset + Tdec + Tinc + +struct page { + void *memAddr + long lsn + semaphore lock +} + +bufferManager.c + struct page loadPage(pageid) + flushPage(struct page) // maybe take pageid + dropPage(struct page) // maybe take pageid + bufTransCommit(xid) // call flush and dropPage on page buffer + bufTransAbort(xid) // call flush and dropPage on page buffer + pin + unpin + +page.c + rid ralloc(int size) // depends on bufferManager + writeRecord(rid, data) + readRecord(rid, buff) + +recovery.c +logger.c +constants.h + + + + + + + + + +============================== + +buffer needs + xid => ( pages ) + (dirty pages) + page, first write LSN + +page needs + xid => ( recordids ) + xid,recordid => data + + +================ +Testing + +in main.c we can write something to the effect of + +begin + +write + +for(;;) + printf("looping"); + +commit + +this way, when we see that "looping is printing, we can purposefully crash the program with control-c + +not sure that this is anydifferent than having main.c {begin, write, exit} diff --git a/README b/README new file mode 100644 index 0000000..1ba5ce2 --- /dev/null +++ b/README @@ -0,0 +1,31 @@ +LLADD is an experimental Lightweight Library for Atomicity and Durability of Data. + +Please see the COPYING file for licensing information. + +To build, do: + +./configure +make +make check +make install + +To build the API and internals documentation, run: + +make docs + +after configure. + +'make check' requires the GNU check library, 'make doc' requires Doxygen. + +We haven't tested make install. ;) + +This package contains a copy of Peter Graf's Program Base Library, PBL, which is +distributed under the terms of the LGPL. + +The original version can be found at: + +http://mission.base.com/peter/source/ + +LLADD's version of the package adds the jbhash.* files, and compiles PBL using +LLADD's make files. Currently, LLADD's hash table implementations are based upon +code from PBL, and pbl is used in a number of places throughout LLADD. diff --git a/autoscan.log b/autoscan.log new file mode 100644 index 0000000..1dfb7b6 --- /dev/null +++ b/autoscan.log @@ -0,0 +1,2 @@ +autoscan: warning: missing AC_PROG_RANLIB wanted by: + ltmain.sh:6370 diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..7f8ead3 --- /dev/null +++ b/bootstrap @@ -0,0 +1,11 @@ +#! /bin/sh + +set -x + +## aclocal warns way too much! +aclocal-1.8 2>&1 | grep -v '.usr.share.aclocal.' +# -I config +autoheader +automake-1.8 --add-missing --copy +#automake +autoconf diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..06b9f2e --- /dev/null +++ b/clean.sh @@ -0,0 +1,10 @@ +#! /bin/sh +make distclean +rm -rf Makefile.in aclocal.m4 autom4te.cache config.h.in configure depcomp hello.c install-sh missing doc/api doc/developers +find . | grep \~$ | xargs rm -f +find . | perl -ne 'print if (/\/core(\.\d+)?$/)' | xargs rm -f +find . | perl -ne 'print if (/\/Makefile.in$/)' | xargs rm -f +find . | perl -ne 'print if (/\/storefile.txt$/)' | xargs rm -f +find . | perl -ne 'print if (/\/logfile.txt$/)' | xargs rm -f +find . | perl -ne 'print if (/\/blob._file.txt$/)' | xargs rm -f + diff --git a/config.h b/config.h new file mode 100644 index 0000000..d25d6a8 --- /dev/null +++ b/config.h @@ -0,0 +1,188 @@ +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the `bzero' function. */ +#define HAVE_BZERO 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdatasync' function. */ +#define HAVE_FDATASYNC 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `inet_ntoa' function. */ +#define HAVE_INET_NTOA 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have a working `mmap' system call. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the `munmap' function. */ +#define HAVE_MUNMAP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if you have the `strstr' function. */ +#define HAVE_STRSTR 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Name of package */ +#define PACKAGE "hello" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "sears@cs.berkeley.edu" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "PACKAGE" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "PACKAGE VERSION" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "package" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "VERSION" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Version number of package */ +#define VERSION "0.1" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned' if does not define. */ +/* #undef size_t */ diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..f25ac89 --- /dev/null +++ b/configure.in @@ -0,0 +1,72 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +PACKAGE=LLADD +VERSION=0.1 +AC_PREREQ(2.59) +AC_INIT(PACKAGE, VERSION, sears@cs.berkeley.edu) +AM_INIT_AUTOMAKE(hello,0.1) +AC_CONFIG_SRCDIR([config.h.in]) +AC_CONFIG_HEADER([config.h]) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +## Need AC_PROG_LIBTOOL +AC_PROG_LIBTOOL +#AC_PROG_RANLIB + +# Checks for libraries. + +AM_PATH_CHECK(,[have_check="yes"], + AC_MSG_WARN([Check not found; cannot run unit tests!]) + [have_check="no"]) +AM_CONDITIONAL(HAVE_CHECK, test x"$have_check", "xyes") + +# Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h memory.h netdb.h netinet/in.h stddef.h stdlib.h string.h strings.h sys/socket.h sys/time.h syslog.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_FUNC_MMAP +AC_FUNC_STAT +AC_CHECK_FUNCS([bzero fdatasync getcwd gettimeofday inet_ntoa memmove memset mkdir munmap socket strchr strdup strerror strrchr strstr strtoul]) + +AC_CHECK_LIB(pthread, pthread_create) + +AC_CONFIG_FILES([Makefile + libdfa/Makefile + lladd/Makefile + pbl/Makefile + src/2pc/Makefile + src/Makefile + src/apps/Makefile + src/apps/cht/Makefile + src/apps/cyrus/Makefile + src/libdfa/Makefile + src/lladd/Makefile + src/pbl/Makefile + src/timing/Makefile + test/2pc/Makefile + test/Makefile + test/cht/Makefile + test/dfa/Makefile + test/lladd/Makefile + test/lladd-old/Makefile + test/messages/Makefile + test/monotree/Makefile]) +AC_OUTPUT diff --git a/libdfa/Makefile b/libdfa/Makefile new file mode 100644 index 0000000..550c2d5 --- /dev/null +++ b/libdfa/Makefile @@ -0,0 +1,197 @@ +# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = .. + +prefix = /usr/local +exec_prefix = ${prefix} + +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 +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/hello +pkglibdir = $(libdir)/hello +pkgincludedir = $(includedir)/hello + +top_builddir = .. + +ACLOCAL = aclocal-1.4 +AUTOCONF = autoconf +AUTOMAKE = automake-1.4 +AUTOHEADER = autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL} +transform = s,x,x, + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = +host_triplet = i686-pc-linux-gnu +AR = ar +AS = @AS@ +CC = gcc +CHECK_CFLAGS = +CHECK_LIBS = -lcheck +CPP = gcc -E +CXX = g++ +CXXCPP = g++ -E +DLLTOOL = @DLLTOOL@ +ECHO = echo +EGREP = grep -E +EXEEXT = +F77 = g77 +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +HAVE_LIB = @HAVE_LIB@ +LIB = @LIB@ +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LN_S = ln -s +LTLIB = @LTLIB@ +MAKEINFO = makeinfo +OBJDUMP = @OBJDUMP@ +OBJEXT = o +PACKAGE = hello +RANLIB = ranlib +RC = @RC@ +STRIP = strip +VERSION = 0.1 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../[config.h] +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu libdfa/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = libdfa + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu libdfa/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libdfa/Makefile.am b/libdfa/Makefile.am new file mode 100644 index 0000000..e69de29 diff --git a/libdfa/libdfa.h b/libdfa/libdfa.h new file mode 100644 index 0000000..67f58de --- /dev/null +++ b/libdfa/libdfa.h @@ -0,0 +1,160 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + + +#ifndef _LIBDFA_H +#define _LIBDFA_H +#include +/*#include "monotree.h"*/ +#include +#include +#include + +/** + Maximum number of concurrent state machines. +*/ +#define DFA_MACHINE_COUNT 100 + + +/** TODO: Add transitions and states to dfaSet? */ +typedef struct dfaSet { + /* MonoTree monoTree; */ + smash_t * smash; + NetworkSetup networkSetup; + State * states; + state_name state_count; + Transition * transitions; + state_name transition_count; + /** + The locking scheme for libdfa currently works as follows: + + There is a single, per process, read/write lock. When a writer + (either the main loop, or a worker thread that is deallocating + its machine) holds the lock, then none of the worker threads may + make progress. When any reader holds the lock, all worker + threads obtain an implicit write lock on their statemachine. + + One final note: Since a writer can change the in-memory location + of state machines, the readers must re-initialize their state + machine pointer each time they obtain a read lock. This is one + of the primary barriers to finer grained locking. (See below for + a straightforward, improved, locking scheme.) + + Performance issues: + + Finer grained locking may be necessary, as all of the + user-defined callbacks are executed in the main loop while it + holds the global write lock. A better scheme might work as + follows: + + Workers obtain a pointer to their state machine, and that + pointer is immutable over the lifetime of the worker. + + The global write lock is only held when the main loop is + allocating or deallocating machines; the global read lock is + only used when the main loop needs to lookup a machine to + service a request, or when creating new worker threads. + + Each machine has a pthreads_mutex associated with it, and + worker threads obtain that mutex whenever they access the + machine. (Therefore user supplied callbacks only would block + progress on the machine that they are running against.) + + */ + rwl * lock; + void * app_setup; +} DfaSet; + + +/** + Clears DfaSet, and establishes a new empty set of state machines in + its place. Also zeroes out the callback tables. Does not + initialize transient state such as network sockets. +*/ +void dfa_initialize_new(DfaSet * dfaSet, unsigned short port, int count); +/** +*/ +int dfa_start (DfaSet *dfaSet, + Transition transitions[], int transition_count, + State states[], state_name state_count); +/** + + Establishes all of the transient state of DfaSet, such as network + connections and callback tables. Should be called after dfa_initialize_new + (or, upon recovery, without dfa_initialize_new) + + Returns -1 on error. + +*/ +int dfa_reinitialize (DfaSet *dfaSet, char * localhost, + Transition transitions[], int transition_count, + State states[], state_name state_count); + + +/** + Spawns a new thread to handle incoming requests. (There should + only be one such thread per dfaSet.) + + @see main_loop, which does the same thing, but blocks indefinitely. +*/ + +pthread_t spawn_main_thread(DfaSet * dfaSet); +/** + Use the current thread as the worker thread for state machine machine_id. Returns when the machine is freed. + + Should be called after spawn_main_thread (Could be called after main_loop if the application manually manages threads.) + + @return TODO (Not sure what this returns / should return.) +*/ + +void * request(DfaSet * dfaSet, state_name start_state, char * recipient_addr, state_machine_id recipient_machine_id, Message * message); + +/** + Runs an infinite loop to handle network requests. +*/ +void* main_loop(DfaSet *dfaSet); + +DfaSet * dfa_malloc(int count, short port, + char *** broadcast_lists, + int broadcast_lists_count, + int * broadcast_list_host_count); +#endif diff --git a/libdfa/messages.h b/libdfa/messages.h new file mode 100644 index 0000000..4d55ab9 --- /dev/null +++ b/libdfa/messages.h @@ -0,0 +1,130 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#ifndef _MESSAGES_H +#define _MESSAGES_H + +#include + +typedef unsigned long state_machine_id; + +/* Maximum size of a message payload, in bytes. Should be a multiple of the system word length.*/ +#define MAX_PAYLOAD 800 +/** + Note that message_type UCHAR_MAX is reserved for the NULL (stop) state, and 0 is reserved for the + start state. +*/ +#define MAX_MESSAGE_TYPE (UCHAR_MAX) +#define MAX_MESSAGE_COUNT (UCHAR_MAX+1) +typedef unsigned char message_name; + +/** +"xxx.xxx.xxx.xxx:yyyyy" is 21 characters, and is as long as the +longest valid ip:port string we will ever encounter or produce +*/ + +#define MAX_ADDRESS_LENGTH 21 + + +/** + Message structs are the in-memory representation of network + messages. Everything except for the payload is translated to and + from network byte order automatically, and the whole struct is sent + (as is) over the network. + + This is why the payload field can be of arbitrary length and is + defined as a char. Allocating a message with a payload larger than + one byte can be done with sizeof() arithmetic, and by setting size + accordingly. +*/ +typedef struct message { + state_machine_id to_machine_id; + state_machine_id from_machine_id; + state_machine_id initiator_machine_id; + char initiator[MAX_ADDRESS_LENGTH]; + message_name type; + /** Payload is a byte array of arbitrary length. **/ + char payload[MAX_PAYLOAD]; +} Message; + +/** + This struct contains the state for the messages (networking) layer. + Currently, everything here can be derived at startup, so this won't + need to be in transactional storage, with some luck. */ +typedef struct networkSetup { + unsigned short localport; + char * localhost; + int socket; + /** + Same format as argv for main(). If a message is addressed to + "broadcast", then the message will be sent to each + "address:port" pair in this string. If you want to use proper + IP broadcast, then this list can simply contain one entry that + contains a subnet broadcast address like "1.2.3.0:1234". + + It would be best to set this value to NULL and + broadcast_list_count to zero if you don't plan to use broadcast. + */ + char *** broadcast_lists; + int broadcast_lists_count; + int *broadcast_list_host_count; +} NetworkSetup; + +int init_network(NetworkSetup *ns, unsigned short portnum); + +int init_network_broadcast(NetworkSetup * ns, unsigned short portnum, char * localhost, char *** broadcast_lists, + int broadcast_lists_count, int * broadcast_list_host_count); + /*int init_network_broadcast(NetworkSetup * ns, unsigned short portnum, char *** broadcast_lists, + int broadcast_lists_count, int * broadcast_list_host_count); */ + +int send_message(const NetworkSetup *ns, Message *m, const char *to); +int receive_message(NetworkSetup *ns, Message *m, char *from); + +/** + Remember to call free() on the pointer that this returns! +*/ +char * parse_addr(const char *message); +short parse_port(const char *message); +int get_index(char ** table, int table_length, const char *message); + + +#endif diff --git a/libdfa/rw.h b/libdfa/rw.h new file mode 100644 index 0000000..2f685b1 --- /dev/null +++ b/libdfa/rw.h @@ -0,0 +1,91 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/* + * File : rw.c + * + * Title : Demo Readers/Writer. + * + * Short : A solution to the multi-reader's, one writer problem. + * + * Long : + * + * Author : Andrae Muys + * + * Date : 18 September 1997 + * + * Revised : 4-7-04 Shamelessly stolen and adapted by Rusty Sears. + * Found the code at this url: + * http://www.cs.nmsu.edu/~jcook/Tools/pthreads/rw.c + */ + +#include + +#include +#include +#include + +typedef struct { + pthread_mutex_t *mut; + int writers; + int readers; + int waiting; + pthread_cond_t *writeOK, *readOK; +} rwl; + +rwl *initlock (void); +void readlock (rwl *lock, int d); +void writelock (rwl *lock, int d); +void readunlock (rwl *lock); +void writeunlock (rwl *lock); +void deletelock (rwl *lock); +/* +typedef struct { + rwl *lock; + int id; + long delay; +} rwargs; + +rwargs *newRWargs (rwl *l, int i, long d); +void *reader (void *args); +void *writer (void *args); +*/ diff --git a/libdfa/smash.h b/libdfa/smash.h new file mode 100644 index 0000000..d73ef44 --- /dev/null +++ b/libdfa/smash.h @@ -0,0 +1,84 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include +#include +/** State machine hash library. */ + +typedef struct { + int size; + int contents; + state_machine_id next_sm_id; + recordid store; + /* Need to save the recordid of the hash if we want to recover... (???)*/ + recordid hash_store; + jbHashTable_t * hash; + pthread_mutex_t * lock; + int xid; + pblHashTable_t * memHash; +} smash_t; + +/** + Usage: + + rb = malloc (sizeof(MonoTree)); + rb->buffer = malloc(sizeof(StateMachine) * rb_size); + + init_MonoTree(rb, rb_size); + +*/ +smash_t * init_Smash(int size); +/** + Returns a pointer to a new machine, or null if the + buffer is full. + +*/ +StateMachine* allocSmash (smash_t * smash); +StateMachine* insertSmash(smash_t * smash, state_machine_id id); +int freeSmash (smash_t * smash, state_machine_id id); + +void * getSmash (smash_t * smash, state_machine_id id); +int setSmash (smash_t * smash, state_machine_id id); + +int forceSmash (smash_t * smash); +/*StateMachine * enumerateSmash(smash_t * rb, int * count);*/ diff --git a/libdfa/statemachine.h b/libdfa/statemachine.h new file mode 100644 index 0000000..6462801 --- /dev/null +++ b/libdfa/statemachine.h @@ -0,0 +1,163 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + + +#ifndef _STATEMACHINE_H +#define _STATEMACHINE_H + +#include +#include +#include + +#include +#include + +#define MAX_STATE_NAME UCHAR_MAX-1 +/* + + If a transition's post state is OVERRIDDEN_STATE, then the new + state is read from the return value of the callback_fcn. If + callback_fcn returns OVERRIDDEN_STATE, then no transition is + performed. + + Otherwise, then callback_fcn returns a standard boolean value. + (0-> no transition, !=0 -> take transition.) + +*/ + +#define MAX_STATE_COUNT UCHAR_MAX+1 + +#define MAX_APP_STATE_SIZE (sizeof(int) * 32) + +#define NULL_MACHINE (ULONG_MAX-1) +#define NULL_STATE MAX_STATE_NAME +#define NULL_STATE_TOMBSTONE (MAX_STATE_NAME-1) +#define OVERRIDDEN_STATE (MAX_STATE_NAME-2) +#define START_STATE 0 + +typedef unsigned char dfa_bool; + +typedef unsigned char state_name; + +/** + This struct contains all of the information associated with an + instance of a state machine. When combined with a set of states and + transitions, this provides enough information to actually execute a machine. + + The page record contains application specific state, which must be + stored in transactional, or otherwise reliable storage. + */ + +typedef struct stateMachine { + /** The unique identifier of this state machine. */ + state_machine_id machine_id; + /** The wall-clock time of the last transition made by this + machine. (Used to abort hung machines.)*/ + time_t last_transition; + /** A pointer to this state machine's page in memory. */ + Page * page; + /** The recordid of page (for recovery) */ + recordid page_id; + /** The current state of this machine, or NULL_STATE for machines + that should be garbage collected. */ + state_name current_state; + pthread_t worker_thread; + int pending; + pthread_mutex_t * mutex; + pthread_cond_t * sleepCond; + Message message; + char message_recipient[MAX_ADDRESS_LENGTH]; + int app_state[MAX_APP_STATE_SIZE]; +} StateMachine; + + +typedef state_name(callback_fcn)(void * dfaSet, StateMachine * stateMachine, Message * m, char * from); + + +/* All function pointers follow this prototype: + + TODO + + and may be null if no function needs to be executed. + +*/ + +typedef struct state { + /** The name of this state. Usually just the index of this state in the states array. + */ + state_name name; + /** A function pointer that will be periodically executed when the machine is in this state. Most network + transmits belong here, while 'guards' belong in fcn_ptr in the Transistion struct. + */ + callback_fcn* retry_fcn; + /** NULL unless the machine can be aborted while in this state. If + not-null, then it should point to a function that performs a + No-op or does any house-keeping that should be performed before + the machine gets nuked. + + Should normally be a callback_fcn, as defined in libdfa.h */ + + callback_fcn* abort_fcn; +} State; + + +typedef struct transition { + /** A unique (per machine type) identifier for this transition. */ + state_name remote_state; + /** The start state for this transition */ + state_name pre_state; + /** The stop state. */ + state_name post_state; + /** Executed when the machine traverses this arc. Returns false if + the arc should not be traversed. For sane semantics, exactly + one transition from a given start state should return true given + the same network message. */ + callback_fcn * fcn_ptr; + /** If true, this transitions causes a force to disk after fcn_ptr + returns, but before the retry_fcn for the state is automatically + executed the first time. */ + dfa_bool force; + +} Transition; + + +#endif diff --git a/lladd.prj b/lladd.prj new file mode 100644 index 0000000..6179610 --- /dev/null +++ b/lladd.prj @@ -0,0 +1,306 @@ +# Anjuta Version 1.2.2 +Compatibility Level: 1 + + +LLADD - Lightweight Library for Atomicity and Data Durability + + + + + + + + + + + + + + + + + +props.file.type=project + +anjuta.version=1.2.2 +anjuta.compatibility.level=1 + +project.name=lladd +project.type=GENERIC +project.target.type=EXECUTABLE +project.version=0.99 +project.author=Russell Sears +project.source.target=unknown +project.has.gettext=0 +project.gui.command= +project.programming.language=C +project.excluded.modules=intl + +project.config.extra.modules.before= +project.config.extra.modules.after= +project.config.blocked=1 +project.config.disable.overwriting=1 1 1 1 1 1 1 1 1 + +project.menu.entry=lladd Version 0.99 +project.menu.group=Application +project.menu.comment=lladd Version 0.99 +project.menu.icon= +project.menu.need.terminal=0 + +project.configure.options= +anjuta.program.arguments= +preferences.build.option.jobs=0 +preferences.build.option.silent=0 +preferences.build.option.autosave=0 +preferences.make=make +preferences.build.option.keep.going=1 +preferences.build.option.warn.undef=0 +preferences.autoformat.custom.style= -i8 -sc -bli0 -bl0 -cbi0 -ss +preferences.indent.opening=0 +preferences.autoformat.disable=1 +preferences.indent.automatic=1 +preferences.use.tabs=1 +preferences.indent.size=4 +preferences.tabsize=4 +preferences.indent.closing=0 + +module.include.name=. +module.include.type= +module.include.files=\ + 2pc/src/2pc/2pc.h\ + 2pc/src/cht/cht.h\ + 2pc/src/libdfa/rw.h\ + 2pc/src/libdfa/messages.h\ + 2pc/src/libdfa/smash.h\ + 2pc/src/libdfa/monotree.h\ + 2pc/src/libdfa/callbacks.h\ + 2pc/src/libdfa/libdfa.h\ + 2pc/src/libdfa/statemachine.h\ + 2pc/config.h\ + pbl/pbl.h\ + pbl/jbhash.h\ + test/test.h\ + test/rand_str.h\ + constants.h\ + bufferManager.h\ + operations/set.h\ + operations/lladdhash.h\ + operations/increment.h\ + operations/decrement.h\ + operations/prepare.h\ + recovery.h\ + logger/logstreamer.h\ + logger/logparser.h\ + page.h\ + logger.h\ + transactional.h\ + linkedlist.h\ + operations.h + +module.source.name=. +module.source.type= +module.source.files=\ + 2pc/src/2pc/2pc.c\ + 2pc/src/cht/cht.c\ + 2pc/src/tests/2pc/always_commit.c\ + 2pc/src/tests/cht/simple.c\ + 2pc/src/tests/cht/cht_server.c\ + 2pc/src/tests/dfa/ping_pong_dfa.c\ + 2pc/src/tests/dfa/star.c\ + 2pc/src/tests/dfa/fork_bomb.c\ + 2pc/src/tests/messages/ping_pong.c\ + 2pc/src/tests/monotree/binary_search.c\ + 2pc/src/tests/monotree/bit_arithmetic.c\ + 2pc/src/tests/monotree/soundness.c\ + 2pc/src/libdfa/rw.c\ + 2pc/src/libdfa/messages.c\ + 2pc/src/libdfa/smash.c\ + 2pc/src/libdfa/monotree.c\ + 2pc/src/libdfa/callbacks.c\ + 2pc/src/libdfa/libdfa.c\ + pbl/pbl.c\ + pbl/pblkfblockprint.c\ + pbl/pbliftst.c\ + pbl/pblhttst.c\ + pbl/pblhash.c\ + pbl/jbhash.c\ + pbl/pblisam.c\ + pbl/pblkf.c\ + pbl/pbltest.c\ + pbl/pblkftst.c\ + test/db41/dbInsertSequential.c\ + test/db41/jbhashmany.c\ + test/db41/dbInsert.c\ + test/db41/dbAbort.c\ + test/db41/jbhashsimple.c\ + test/db41/dbUpdate.c\ + test/db41/dbGet.c\ + test/strings.c\ + test/jbhashdisk.c\ + test/TGet.c\ + test/TUpdate.c\ + test/jbhashmany.c\ + test/twentyfour2.c\ + test/abort-speed.c\ + test/nontrans.c\ + test/lhpackingfactor.c\ + test/jbhtsimple.c\ + test/inc_dec.c\ + test/test0.c\ + test/test1.c\ + test/test2.c\ + test/test3.c\ + test/recover.c\ + test/commit-speed.c\ + test/logvals.c\ + test/jbht-speed.c\ + test/interleaved.c\ + test/TAbort.c\ + test/loop.c\ + test/abort.c\ + test/test.c\ + test/TInsertSequential.c\ + test/lhmany.c\ + test/twentyfour.c\ + test/prepare_1.c\ + test/prepare_2.c\ + test/prepare_3.c\ + test/rand_str.c\ + test/TInsert.c\ + cyrus/cyrusdb_lladd.c\ + bufferManager.c\ + operations/set.c\ + operations/lladdhash.c\ + operations/increment.c\ + operations/decrement.c\ + operations/prepare.c\ + recovery.c\ + logger/logstreamer.c\ + logger/logparser.c\ + page.c\ + timing/getTimeOfDay.c\ + logger.c\ + transactional.c\ + linkedlist.c + +module.pixmap.name=. +module.pixmap.type= +module.pixmap.files=\ + pbl/doc/icon1.gif\ + pbl/doc/icon2.gif + +module.data.name=. +module.data.type= +module.data.files= + +module.help.name=. +module.help.type= +module.help.files= + +module.doc.name=. +module.doc.type= +module.doc.files=\ + 2pc/COPYING\ + pbl/doc/pblKfInit.html\ + pbl/doc/pblHtNext.html\ + pbl/doc/pblKfPrev.html\ + pbl/doc/pbl_LongToBuf.html\ + pbl/doc/pbl_LongToVarBuf.html\ + pbl/doc/pbl_VarBufToLong.html\ + pbl/doc/pblKfFlush.html\ + pbl/doc/pblKfOpen.html\ + pbl/doc/pblIsamGet.html\ + pbl/doc/pblKfDelete.html\ + pbl/doc/pblIsamFile_t.html\ + pbl/doc/pbl_LongSize.html\ + pbl/doc/pbl_errno.html\ + pbl/doc/pblIsamReadKey.html\ + pbl/doc/pblIsamCommit.html\ + pbl/doc/AIntroduction.html\ + pbl/doc/pblKEYFILE_TestFrame.html\ + pbl/doc/pbl_mem2dup.html\ + pbl/doc/pbl_ShortToBuf.html\ + pbl/doc/pblIsamFlush.html\ + pbl/doc/pblHtInsert.html\ + pbl/doc/DDefinitionsforKeyFileParameters.html\ + pbl/doc/pbl_memlcpy.html\ + pbl/doc/pblKfCreate.html\ + pbl/doc/pblIsamFind.html\ + pbl/doc/pblHtLookup.html\ + pbl/doc/pblKfUpdate.html\ + pbl/doc/index.html\ + pbl/doc/pblHtDelete.html\ + pbl/doc/pblHtRemove.html\ + pbl/doc/pbl_malloc0.html\ + pbl/doc/pblIsamInsert.html\ + pbl/doc/pblKfGetRel.html\ + pbl/doc/pblKfLast.html\ + pbl/doc/pblKfStartTransaction.html\ + pbl/doc/pblIsamStartTransaction.html\ + pbl/doc/pblKfRead.html\ + pbl/doc/pblIsamDelete.html\ + pbl/doc/BFiles.html\ + pbl/doc/pblHashTable_t.html\ + pbl/doc/pblKeyFile_t.html\ + pbl/doc/pbl_memdup.html\ + pbl/doc/pblIsamOpen.html\ + pbl/doc/pblIsamUpdateData.html\ + pbl/doc/pbl_memcmplen.html\ + pbl/doc/pblHtFirst.html\ + pbl/doc/pblHtCreate.html\ + pbl/doc/pblKfClose.html\ + pbl/doc/pblKfSetCompareFunction.html\ + pbl/doc/CErrorcodes.html\ + pbl/doc/pblKfNext.html\ + pbl/doc/PBLKEYLENGTH.html\ + pbl/doc/pbl_malloc.html\ + pbl/doc/pblIsamReadDatalen.html\ + pbl/doc/pblISAMFILE_TestFrame.html\ + pbl/doc/pblHtCurrent.html\ + pbl/doc/General.html\ + pbl/doc/pblKfRestorePosition.html\ + pbl/doc/pblKfFirst.html\ + pbl/doc/pblIsamUpdateKey.html\ + pbl/doc/pbl_BufToShort.html\ + pbl/doc/PBL_LIST_PUSH.html\ + pbl/doc/pbl_memcmp.html\ + pbl/doc/pblKfThis.html\ + pbl/doc/pblKfCommit.html\ + pbl/doc/pblKfGetAbs.html\ + pbl/doc/pblIsamClose.html\ + pbl/doc/pbl_errstr.html\ + pbl/doc/PBLDATALENGTH.html\ + pbl/doc/PBL_LIST_APPEND.html\ + pbl/doc/PBL_LIST_.html\ + pbl/doc/pblKfFind.html\ + pbl/doc/PBL_FREE.html\ + pbl/doc/EDefinitionsforISAMParameters.html\ + pbl/doc/pbl_VarBufSize.html\ + pbl/doc/pblKfSavePosition.html\ + pbl/doc/PBL_LIST_UNLINK.html\ + pbl/doc/pblIsamReadData.html\ + pbl/doc/pbl_BufToLong.html\ + pbl/doc/pblKfInsert.html\ + pbl/doc/pblIsamSetCompareFunction.html\ + timing/README + +module.po.files= + +compiler.options.supports= +compiler.options.include.paths=\ + .\ + .. +compiler.options.library.paths= +compiler.options.libraries= +compiler.options.libraries.selected= +compiler.options.defines=\ + HAVE_CONFIG_H +compiler.options.defines.selected= +compiler.options.warning.buttons=0 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0 +compiler.options.optimize.buttons=0 0 1 0 +compiler.options.other.buttons=1 0 +compiler.options.other.c.flags= +compiler.options.other.l.flags= +compiler.options.other.l.libs= + +project.src.paths= diff --git a/lladd.pws b/lladd.pws new file mode 100644 index 0000000..e7b0865 --- /dev/null +++ b/lladd.pws @@ -0,0 +1,78 @@ + +[executer] +RunInTerminal=true + +[Project State] +clean before build=false + +[File View] +filter.file.unmatch=*.so *.o *.a *.la +filter.file.ignore.hidden=0 +filter.dir.ignore.hidden=0 + +[filelist] +0=/home/morph/lladd/recovery.c +1=/home/morph/lladd/logger/logparser.c +2=/home/morph/lladd/logger/logstreamer.c +3=/home/morph/lladd/constants.h +4=/home/morph/lladd/bufferManager.c +5=/home/morph/lladd/page.c +6=/home/morph/lladd/logger/logparser.h +7=/home/morph/lladd/operations.c +8=/home/morph/lladd/logger.c +9=/home/morph/lladd/operations/increment.c +10=/home/morph/lladd/transactional.c +11=/home/morph/lladd/operations.h +12=/home/morph/lladd/test/lhpackingfactor.c +13=/home/morph/lladd/test/lladdHashTest.c +14=/home/morph/lladd/operations/lladdhash.c +15=/home/morph/lladd/pbl/pbl.h +16=/home/morph/lladd/operations/lladdhash.h +17=/home/morph/lladd/transactional.h + +[filenumbers] +0=61 +1=21 +2=1 +3=43 +4=329 +5=510 +6=71 +7=1 +8=63 +9=1 +10=67 +11=1 +12=17 +13=1 +14=104 +15=387 +16=58 +17=8 + +[filemarkers] +0= +1= +2= +3= +4= +5= +6= +7= +8= +9= +10= +11= +12= +13= +14= +15= +16= +17= + +[Project Tree] +0=0 + +[File Tree] +0=0 +1=0:7 diff --git a/lladd/Makefile b/lladd/Makefile new file mode 100644 index 0000000..41fe6e3 --- /dev/null +++ b/lladd/Makefile @@ -0,0 +1,197 @@ +# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = .. + +prefix = /usr/local +exec_prefix = ${prefix} + +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 +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/hello +pkglibdir = $(libdir)/hello +pkgincludedir = $(includedir)/hello + +top_builddir = .. + +ACLOCAL = aclocal-1.4 +AUTOCONF = autoconf +AUTOMAKE = automake-1.4 +AUTOHEADER = autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL} +transform = s,x,x, + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = +host_triplet = i686-pc-linux-gnu +AR = ar +AS = @AS@ +CC = gcc +CHECK_CFLAGS = +CHECK_LIBS = -lcheck +CPP = gcc -E +CXX = g++ +CXXCPP = g++ -E +DLLTOOL = @DLLTOOL@ +ECHO = echo +EGREP = grep -E +EXEEXT = +F77 = g77 +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +HAVE_LIB = @HAVE_LIB@ +LIB = @LIB@ +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LN_S = ln -s +LTLIB = @LTLIB@ +MAKEINFO = makeinfo +OBJDUMP = @OBJDUMP@ +OBJEXT = o +PACKAGE = hello +RANLIB = ranlib +RC = @RC@ +STRIP = strip +VERSION = 0.1 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../[config.h] +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu lladd/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lladd + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu lladd/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lladd/Makefile.am b/lladd/Makefile.am new file mode 100644 index 0000000..e69de29 diff --git a/lladd/bufferManager.h b/lladd/bufferManager.h new file mode 100644 index 0000000..72feb60 --- /dev/null +++ b/lladd/bufferManager.h @@ -0,0 +1,288 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * @file + * Manages the page buffer + * + * @todo Allow error checking! + * + * @todo CORRECTNESS PROBLEM: Recovery assumes that each page is + * written atomically to disk, and that the LSN field of the page will + * be in sync with the contents of each record on the page. Since we + * use mmap() to read and write the pages, and a page fault could + * interrupt LLADD between a writeRecord and writeLSN call, it is + * possible for the operating system to steal dirty pages from the + * buffer manager. (We support steal in the normal case, but still + * need to be sure that the stolen pages are internally consistent!) + * + * It looks as though we will need to re-write the buffer manager so + * that it only uses read or write calls. Alternatively, we could + * lock pages as we update them, but that requires root privliges. + * + * @todo Refactoring for lock manager / correctness + * + * Possible interfaces: + * + + + blobManager - Provides blob handling @todo Set range?? + Plan for modularity: Exactly one blob manager per storeFile. + Blob manager interacts with page manger via page manager's + public api. + + - void * readBlob(rid); // if blob is resident, return a pointer to it. + // if blob isn't dirty, read it from its primary location. + // if it is dirty, but not resident (stolen), read from secondary location. + + - writeBlob(rid); // if blob isn't dirty, marks blob dirty. + + - kickBlob(rid); // if blob isn't dirty, free it. + // Otherwise, steal to blob store, but + // remember that its dirty. + + - commitBlob(rid); // if blob is resident, flush it to disk, + // set pointer to new store bit, then + // write new store bit to bufferManager + + - abortBlob(rid); // kickBlob(), mark it clean. + + + + pageManager - Provides cached page handling, delegates to blob + manager when necessary. Doesn't implement an eviction policy. + That is left to a cacheManager. (Multiple cacheManagers can be + used with a single page manager.) + + typedef struct { + Page * page; + /* If this page is pinned, what's the maximum lsn that's dirtied it? * / + lsn_t * max_dirty_lsn = 0; + /* How many times has this page been pinned using readWriteMap()? * / + int pin_count; + } page_metadata_t; + + + Calls for user managed memory: + + Read only access to record: + + Cost with cache hit: memcpy(); + + - int readRecord(rid, void *); + + Write record directly: + Cost with cache hit: memcpy(rid.size), eventual disk flush; + + - int writeRecord(rid, lsn, void *); + + @todo need alloc + free... + + Calls for LLADD managed memory (returns pointers to LLADD's cache.) + + Read only access to record (requires an un-pinning) + + Cost with cache hit: pointer arithmetic. + + - map_t readMapRecord(rid, &((const void *)); + + Map a page read / write. Pins the page, sets its lsn, and provides a pointer to the record: + Cost with cache hit: pointer arithmetic, eventual disk flush. + + - map_t readWriteMapRecord(rid, &(void *)); + + Unmap a mapped page so that it can be kicked. + + @param lsn can be 0 if this is a read-only mapping. Otherwise, + it should be the LSN of the operation that calls unmapRecord. + @todo What connection between the lock manager and this function + is there? Presumably, unmap should be called when the locks are + released... + + - void unmapRecord(map_t, lsn); + + cachePolicy + + page_id kickPage(); // Choose a page to kick. May call logFlush() if necessary. + readPage(page); // Inform the cache that a page was read. + writePage(page); // Inform the cache that a page was written. + cacheHint(void *); // Optional method needed to implement dbmin. + + lockManager + + - These functions provide a locking implementation based on logical operations: + + lock_t lock(Operation o); + unlock(Operation o); + + - These functions provide a locking implementation based on physical operations: + + (Insert bufferManager API here, but make each call take a xid and a lock_t* parameter) + + Locking functions can return errors such as DEADLOCK, etc. + + * + * @ingroup LLADD_CORE + * $Id$ + */ + +#ifndef __BUFFERMANAGER_H__ +#define __BUFFERMANAGER_H__ + +#include +#include + +/** + * initialize buffer manager + * @return 0 on success + * @return error code on failure + */ +int bufInit(); + +/** + * @param pageid ID of the page you want to load + * @return fully formed Page type + * @return page with -1 ID if page not found + */ +Page loadPage(int pageid); + +/** + * allocate a record + * @param xid The active transaction. + * @param size The size of the new record + * @return allocated record + */ +recordid ralloc(int xid, size_t size); + +/** + * This function updates the LSN of a page. This is needed by the + * recovery process to make sure that each action is undone or redone + * exactly once. + * + * @param LSN The new LSN of the page. + * @param pageid ID of the page you want to write + * + * @todo This needs to be handled by ralloc and writeRecord for + * correctness. Right now, there is no way to atomically update a + * page(!) To fix this, we need to change bufferManager's + * implementation to use read/write (to prevent the OS from stealing + * pages in the middle of updates), and alter kickPage to see what the + * last LSN synced to disk was. If the log is too far behind, it will + * need to either choose a different page, or call flushLog(). We may + * need to implement a special version of fwrite() to do this + * atomically. (write does not have to write all of the data that was + * passed to it...) + */ +void writeLSN(long LSN, int pageid); + +/** + * @param pageid ID of page you want to read + * @return LSN found on disk + */ +long readLSN(int pageid); + +/** + * @param xid transaction id + * @param rid recordid where you want to write + * @param dat data you wish to write + */ +void writeRecord(int xid, recordid rid, const void *dat); + +/** + * @param xid transaction ID + * @param rid + * @param dat buffer for data + */ +void readRecord(int xid, recordid rid, void *dat); + +/** + * @param page write page to disk, including correct LSN + * @return 0 on success + * @return error code on failure + */ +int flushPage(Page page); + +/* + * this function does NOT write to disk, just drops the page from the active + * pages + * @param page to take out of buffer manager + * @return 0 on success + * @return error code on failure +int dropPage(Page page); + */ + +/** + * all actions necessary when committing a transaction. Can assume that the log + * has been written as well as any other actions that do not depend on the + * buffer manager + * + * Basicly, this call is here because we used to do copy on write, and + * it might be useful when locking is implemented. + * + * @param xid transaction ID + * @return 0 on success + * @return error code on failure + */ +int bufTransCommit(int xid); + +/** + * + * Currently identical to bufTransCommit. + * + * @param xid transaction ID + * @return 0 on success + * @return error code on failure + */ +int bufTransAbort(int xid); + +/** + * will write out any dirty pages, assumes that there are no running + * transactions + */ +void bufDeinit(); + +/** @todo Global file descriptors are nasty. */ + +extern int blobfd0; +extern int blobfd1; + + +#endif diff --git a/lladd/common.h b/lladd/common.h new file mode 100644 index 0000000..0a6aa28 --- /dev/null +++ b/lladd/common.h @@ -0,0 +1,105 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * @file + * + * A standard header file, adopted from Autobook. + * + * @todo: Need to make sure everyone actually includes this thing, and also includes constants.h + * + * @ingroup LLADD_CORE + * + * $Id$ + */ + +#ifndef __lladd_common_h +#define __lladd_common_h 1 + + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +/* Should be included by the .c files only. :( */ +/*#if HAVE_CONFIG_H + # include "config.h" + #endif */ + +#include +#include + +#if STDC_HEADERS +# include +# include +#elif HAVE_STRINGS_H +# include +#endif /*STDC_HEADERS*/ + +#if HAVE_UNISTD_H +# include +#endif + +#if HAVE_ERRNO_H +# include +#endif /*HAVE_ERRNO_H*/ +#ifndef errno +/* Some systems #define this! */ +extern int errno; +#endif + +#define byte unsigned char +#define lsn_t off_t + + + +#define DEBUGGING +#define DEBUG(...) \ + printf(__VA_ARGS__); fflush(NULL) + + +/*#define DEBUG(...) */ + +#endif /* __lladd_common_h */ diff --git a/lladd/config.h.in b/lladd/config.h.in new file mode 100644 index 0000000..65b64a3 --- /dev/null +++ b/lladd/config.h.in @@ -0,0 +1,178 @@ +/* lladd/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the `bzero' function. */ +#undef HAVE_BZERO + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the `inet_ntoa' function. */ +#undef HAVE_INET_NTOA + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the `mkdir' function. */ +#undef HAVE_MKDIR + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/lladd/constants.h b/lladd/constants.h new file mode 100644 index 0000000..d203c70 --- /dev/null +++ b/lladd/constants.h @@ -0,0 +1,126 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * @file + * + * defines various constants + * + * @todo Sometime, LLADD's #includes need to be cleaned up. In + * particular, we should make sure everything directly or indirectly + * includes this file, common.h, and constants.h + * + * @ingroup LLADD_CORE + * + * $Id$ + */ + +#ifndef __CONSTANTS_H__ +#define __CONSTANTS_H__ + +/*#define DEBUG 1*/ + +#define LOG_FILE "logfile.txt" +#define STORE_FILE "storefile.txt" +#define BLOB0_FILE "blob0_file.txt" +#define BLOB1_FILE "blob1_file.txt" + +/* @define error codes + */ +#define OUT_OF_MEM 1 +#define FILE_OPEN_ERROR 2 +#define FILE_READ_ERROR 3 +#define FILE_WRITE_ERROR 4 +#define FILE_WRITE_OPEN_ERROR 5 +#define MEM_WRITE_ERROR 6 + +#define PAGE_SIZE 4096 + +/*#define MAX_BUFFER_SIZE 100003 */ +/*#define MAX_BUFFER_SIZE 10007 */ +#define MAX_BUFFER_SIZE 71 + +/* 71 */ +#define BUFFER_ASOOCIATIVE 2 + +#define MAX_TRANSACTIONS 32 + +/** Operation types */ + +#define NO_INVERSE -1 +#define OPERATION_SET 0 +#define OPERATION_INCREMENT 1 +#define OPERATION_DECREMENT 2 +#define OPERATION_ALLOC 3 +#define OPERATION_PREPARE 4 +#define OPERATION_LHINSERT 5 +#define OPERATION_LHREMOVE 6 +#define OPERATION_DEALLOC 7 +/* number above should be less than number below */ +#define MAX_OPERATIONS 20 + +/** @todo undocumented */ + +#define INVALID_SLOT PAGE_SIZE +#define BLOB_SLOT (PAGE_SIZE + 1) +#define BLOB_REC_SIZE 12 +#define BLOB_THRESHOLD_SIZE (PAGE_SIZE-30) + +#define BITS_PER_BYTE 8 + +/** Log entry types. (Not to be confused with operation types, which are more interesting.) */ + + +/* + Definitions for different types of logs +*/ +#define UPDATELOG 1 +#define XBEGIN 2 +#define XCOMMIT 3 +#define XABORT 4 +/* Folded into update log entries */ +/*#define XALLOC 5*/ +/** XEND is used for after a transaction is aborted or commited, and some + * additional steps are taken and then the XEND is written */ +#define XEND 6 +#define CLRLOG 7 + +#endif diff --git a/lladd/logger.h b/lladd/logger.h new file mode 100644 index 0000000..f7e8ec9 --- /dev/null +++ b/lladd/logger.h @@ -0,0 +1,126 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + * @file + * + * External interaface to Logging API. (Only exposes operations used + * to add entries to the log.) + * + * Logger is the front end for logging actions -- whatever must be done (ie + * write to the log tail; flushing for commits) is handled in these functions + * + * @deprecated + * @see logger2.h + * + * @ingroup LLADD_CORE + * $Id$ + * + * *************/ + + +#ifndef __LOGGER_H__ +#define __LOGGER_H__ + +#include "transactional.h" +#include "operations.h" + +/** + Does NOT write a transaction begin; rather, just returns that the + LSN of a potential entry is -1 so the next command will have a + prevLSN of -1. (Althoug this is currently a no-op, it's possible + that some other logging scheme would actually write begin records.) +*/ +long LogTransBegin(Transaction t); + +/** + * logs the fact that a rid has been allocated for a transaction + */ +long LogTransAlloc(long prevLSN, int xid, recordid rid); + +/** + Write a transaction COMMIT to the log tail, then flush the log tail immediately to disk + + @return the LSN of this entry +*/ +long LogTransCommit(long prevLSN, int xid); + +/** + Write a transaction ABORTto the log tail + + @return returns the LSN of this entry +*/ +long LogTransAbort(long prevLSN, int xid); + +/** + LogUpdate writes an UPDATE log record to the log tail + + returns the LSN of this entry +*/ +long LogUpdate (long prevLSN, int xid, recordid rid, Operation op, const void *args); + +/** + Write a compensation log record. These records are used to allow + for efficient recovery, and possibly for log truncation. They + record the completion of undo operations. +*/ +long LogCLR (long prevLSN, int xid, long ulLSN, recordid ulRID, long ulPrevLSN); + +/** + Write a end transaction record @ todo What does this do exactly? Indicate completion of aborts? +*/ +long LogEnd (long prevLSN, int xid); + +/* + Starts a new log stream, possibly other stuff can go here too? +*/ +void logInit(); + +/* + Called when ALL transactions are guaranteed to be completed (either + committed or aborted) and no new ones can be had. So therefore we + can close the log streamer and delete the log file. @todo Doesn't + delete logs right now. (For debugging) +*/ +void logDeinit(); + +#endif diff --git a/lladd/logger/logEntry.h b/lladd/logger/logEntry.h new file mode 100644 index 0000000..ef93fcb --- /dev/null +++ b/lladd/logger/logEntry.h @@ -0,0 +1,129 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#ifndef __LLADD_LOGGING_LOGENTRY_H +#define __LLADD_LOGGING_LOGENTRY_H + +#include +#include + +BEGIN_C_DECLS + +/** + @file + + Next generation logger api. + + @todo Was getting some memory over-runs from the fact that I didn't + know the exact length of a raw log entry. This seems to be fixed + now. (Need to run through electric fence / determine the 'right + way' to do this...) +*/ + +typedef struct { + lsn_t thisUpdateLSN; + recordid rid; + lsn_t undoNextLSN; +} CLRLogEntry; + +typedef struct { + unsigned int funcID : 8; + recordid rid; + unsigned int argSize : 16; /*2^16 = 64M*/ + /* int invertible; */ /* no longer needed */ + /* Implicit members: + args; @ ((byte*)ule) + sizeof(UpdateLogEntry) + preImage; @ ((byte*)ule) + sizeof(UpdateLogEntry) + ule.argSize */ +} UpdateLogEntry; + +struct __raw_log_entry { + lsn_t LSN; + lsn_t prevLSN; + int xid; + unsigned int type; +}; + +/*#define sizeofRawLogEntry (sizeof(lsn_t)*2+sizeof(int)+4)*/ + +typedef struct { + lsn_t LSN; + lsn_t prevLSN; + int xid; + unsigned int type; + union { + UpdateLogEntry update; + CLRLogEntry clr; + } contents; +} LogEntry; + +/** + All of these return a pointer to a single malloced region that should be freed. +*/ + +/** + Allocate a log entry that does not contain any extra payload information. (Eg: Tbegin, Tcommit, etc.) + */ +LogEntry * allocCommonLogEntry(lsn_t prevLSN, int xid, unsigned int type); +/** + Allocate a log entry with extra payload info.(eg: Tupdate, Talloc, etc) +*/ +LogEntry * allocUpdateLogEntry(lsn_t prevLSN, int xid, + unsigned int operation, recordid rid, + const byte * args, unsigned int argSize, const byte * preImage); +/** + Allocate a CLR entry. These are written during recovery to + indicate that the stable copy of the store file reflects the state + of the database after an operation has successfuly been + redone/undone. + */ +LogEntry * allocCLRLogEntry (lsn_t prevLSN, int xid, + lsn_t thisUpdateLSN, recordid rid, lsn_t undoNextLSN); + + + +size_t sizeofLogEntry(const LogEntry * log); +const byte * getUpdateArgs(const LogEntry * log); +const byte * getUpdatePreImage(const LogEntry * log); + +END_C_DECLS + +#endif /* __LOGENTRY_H */ diff --git a/lladd/logger/logHandle.h b/lladd/logger/logHandle.h new file mode 100644 index 0000000..8f7d453 --- /dev/null +++ b/lladd/logger/logHandle.h @@ -0,0 +1,115 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include "logEntry.h" +#include "logWriter.h" + +#ifndef __LOGHANDLE_H +#define __LOGHANDLE_H + +BEGIN_C_DECLS + +/** + @file + A simple data structure that allows forward iterations over + the log, and also allows reverse iterations. Forward iterations + are used for redo, and return every log entry, in its original + order. Reverse iterations are used for undo, and are transaction + specific. They follow the prevLSN. (or the next entry to be + undone stored in any CLR's that are encountered.) + + logHandle is useful for read only access to the log. + + @see logWriter.h For write access to the log. +*/ + +typedef int (guard_fcn_t)(LogEntry *, void *); + +typedef struct { + /** The LSN of the last log entry returned.*/ + /* lsn_t file_offset; */ /* Unneeded? */ + /** The LSN of the log entry that we would return if next is called. */ + lsn_t next_offset; + /** The LSN of the log entry that we would return if previous is called. */ + lsn_t prev_offset; + guard_fcn_t * guard; + void * guard_state; +} LogHandle; + +/** Returns a logHandle pointing at the first log entry in the log. */ +LogHandle getLogHandle(); +/** Returns a logHandle pointing at lsn. */ +LogHandle getLSNHandle(lsn_t lsn); +/** Returns a 'guarded log handle'. This handle executes a callback + function on each entry it encounters. If the guard returns 0, + then it's iterator terminates. Otherwise, it behaves normally. */ +LogHandle getGuardedHandle(lsn_t lsn, guard_fcn_t * f, void * guard_state); + +/** + @return a pointer to the next log entry in the log, or NULL if at + EOF. + + */ +LogEntry * nextInLog(LogHandle * h); +/** + Returns a pointer to the previous log entry in this + transaction. This is used to undo transactions. If the logHandle + is a guarded handle, the handle returns null. + + The guard is useful for Tprepare, partial rollback, and probably + any reasonable lock manager implementations. + + If we encounter a CLR, that means that everything after the clr's + undoNextLSN has already been undone. In that case, we can skip + all intervening log entries (including CLR's), since they contain + 'stale' data. + + @return NULL if there is no previous LogEntry for this + transaction, or if the guard indicates that we're done by returning 0. + */ +LogEntry * previousInTransaction(LogHandle * h); +/* +void closeHandle(LogHandle h); +*/ +END_C_DECLS + +#endif diff --git a/lladd/logger/logWriter.h b/lladd/logger/logWriter.h new file mode 100644 index 0000000..cb13c04 --- /dev/null +++ b/lladd/logger/logWriter.h @@ -0,0 +1,158 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + * @file + * + * New version of logstreamer; designed to work with logEntry, and has + * a simplified API. + * + * logstreamer is the implementation of writing the log tail + * It must be bufferred -- in that when something is written to the log tail it + * is not immediately written to disk, but rather just to memory. But + * logstreamer must be able to force flush to disk, which will be done when a + * commit log entry is written to the log tail + * + * Note: using the stdio FILEs for this, and by default it is "fully" buffered. + * The log tail may be flushed to disk without an explicit call to fflush (when + * the program terminates, the file closes), but this is acceptable because it + * never hurts to have more flushes to disk, as long as it doesn't hurt + * performance. + * + * @todo Everything in this file cores on failure (no error handling yet) + * @todo All of the logWriter calls should be reentrant. + * + * $Id$ + * + */ + +#ifndef __LOGWRITER_H__ +#define __LOGWRITER_H__ + +#include "logEntry.h" +#include +#include + +BEGIN_C_DECLS +/** + start a new log stream by opening the log file for reading + + returns 0 on success, or an error code define above + +*/ +int openLogWriter(); + +/** + + @param e Pointer to a log entry. After the call, e->LSN will be set appropriately. + + returns 0 on success, or an error code defined above +*/ +int writeLogEntry(LogEntry * e); + +/* + flush the entire log (tail) that is currently in memory to disk +*/ +void syncLog(); + +/* + Close the log stream +*/ +void closeLogWriter(); + +/* + Get the current position of the stream (in terms of bytes) +*/ +/*long getFilePos();*/ + +/* + Actually deletes the log file that may have been written to disk! Danger!! + Only use after calling closeLogStream AND you are sure there are no active (or + future active) transactions! +*/ +void deleteLogWriter(); + +/* + * Returns the current position of the stream no matter where it is + */ +/*long streamPos();*/ + +/* + * Returns the position of the stream if it were to read. + */ +/*long writeStreamPos();*/ + +/* + * readLog reads a line from the log puts it in a string + * + * This was made static because it exports state that the interface + * should be hiding. (To use this function, the user must make + * assumptions regarding the value of the FILE's current offset.) + * + * returns the number of bytes read and put into buffer + * */ +/*int readLog(byte **buffer);*/ +/* LogEntry * readLogEntry(); */ + +/* + * seek to a position in the log file and read it into the buffer + * + * returns the number of bytes read and put into buffer + * */ + +/*int seekAndReadLog(long pos, byte **buffer);*/ + +LogEntry * readLSNEntry(lsn_t LSN); + +/* lsn_t nextLSN(); */ + +/* + * tell the current position in the log file + * */ +/*long readPos (); + +void seekInLog(long pos);*/ + +END_C_DECLS + +#endif /* __LLADD_LOGGER_LOGWRITER_H */ + diff --git a/lladd/logger/logger2.h b/lladd/logger/logger2.h new file mode 100644 index 0000000..7a37e09 --- /dev/null +++ b/lladd/logger/logger2.h @@ -0,0 +1,123 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + * @file + * + * New version of logger. Based on logger.h + * + * $Id$ + * + */ + + +#ifndef __LOGGER2_H__ +#define __LOGGER2_H__ + +#include "logEntry.h" +#include "logHandle.h" +#include +/** + Contains the state needed by the logging layer to perform + operations on a transaction. + */ +typedef struct { + int xid; + lsn_t prevLSN; + LogHandle lh; +} TransactionLog; + +/** + Inform the logging layer that a new transaction has begun. + Currently a no-op. +*/ +TransactionLog LogTransBegin(int xid); + +/** + Write a transaction COMMIT to the log tail, then flush the log tail immediately to disk + + @return 0 if the transaction succeeds, an error code otherwise. +*/ +void LogTransCommit(TransactionLog * l); + +/** + Write a transaction ABORT to the log tail + + @return 0 if the transaction was successfully aborted. +*/ +void LogTransAbort(TransactionLog * l); + +/** + LogUpdate writes an UPDATE log record to the log tail +*/ +LogEntry * LogUpdate(TransactionLog * l, recordid rid, int operation, const byte * args); +/* * + (Was folded into LogUpdate.) + + Logs the fact that a rid has been allocated for a transaction. + @ todo Should this be folded into LogUpdate? (Make "alloc" an operation...) + @ todo Surely, we need a dealloc! + */ +/*lsn_t LogTransAlloc(TransactionLog * l, recordid rid);*/ + + +/** + Write a compensation log record. These records are used to allow + for efficient recovery, and possibly for log truncation. They + record the completion of undo operations. + + @return the lsn of the CLR entry that was written to the log. + (Needed so that the lsn slot of the page in question can be + updated.) + + @todo Remove this from this interface? Should it be internal to + the recovery routines? +*/ +lsn_t LogCLR (LogEntry * undone); /*TransactionLog * l, long ulLSN, recordid ulRID, long ulPrevLSN); */ + +/** + Write a end transaction record @todo What does this do exactly? Indicate completion of aborts? + @todo Move into recovery-only code? +*/ +void LogEnd (TransactionLog * l); + +#endif diff --git a/lladd/operations.h b/lladd/operations.h new file mode 100644 index 0000000..8bc46f4 --- /dev/null +++ b/lladd/operations.h @@ -0,0 +1,179 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + * @file + * + * Interface for defining new logical operations. + * + * @ingroup LLADD_CORE OPERATIONS + * $Id$ + */ + +#ifndef __OPERATIONS_H__ +#define __OPERATIONS_H__ + +/*#include */ +/*#include "common.h"*/ + + + + +#include +#include +#include + +BEGIN_C_DECLS + + +/* @type Function + * function pointer that the operation will run + */ +typedef int (*Function)(int xid, recordid r, const void *d); + +/* @type Operation + + * @param sizeofData size of the data that function accepts (as void*) + * @param undo index into operations table of undo function (takes same args) + * @param run what function to actually run + */ + +/* @type Special cases + */ +#define SIZEOF_RECORD -1 +#define NO_INVERSE -1 +typedef struct { + /** + * ID of operation, also index into operations table + */ + int id; + /** + This value is the size of the arguments that this operation + takes. If set to SIZEOF_RECORD, then the size of the record + that the operation affects will be used instead. + */ + size_t sizeofData; + /** + Does this operation supply an undo operation? + + --Unneeded; just set undo to the special value NO_INVERSE. + */ + /* int invertible; */ + /** + Implementing operations that may span records is subtle. + Recovery assumes that page writes (and therefore logical + operations) are atomic. This isn't the case for operations that + span records. Instead, there are two (and probably other) choices: + + - Periodically checkpoint, syncing the data store to disk, and + writing a checkpoint operation. No writes can be serviced + during the sync, and this implies 'no steal'. See: + + @inproceedings{ woo97accommodating, + author = "Seung-Kyoon Woo and Myoung-Ho Kim and Yoon-Joon Lee", + title = "Accommodating Logical Logging under Fuzzy Checkpointing in Main Memory Databases", + booktitle = "International Database Engineering and Application Symposium", + pages = "53-62", + year = "1997", + url = "citeseer.ist.psu.edu/135200.html" } + + for a more complex scheme involving a hybrid logical/physical + logging system that does not implement steal. + + The other option: + + - Get rid of operations that span records entirely by + splitting complex logical operations into simpler one. + + We chose the second option for now. + + */ + int undo; + Function run; +} Operation; + +/* These need to be installed, since they are required by applications that use LLADD. */ +/*#include "constants.h" + #include */ + +#include "operations/increment.h" +#include "operations/decrement.h" +#include "operations/set.h" +#include "operations/prepare.h" +#include "operations/lladdhash.h" +#include "operations/alloc.h" + + +extern Operation operationsTable[]; /* [MAX_OPERATIONS]; memset somewhere */ + +/** Performs an operation during normal execution. + + Does not write to the log, and assumes that the operation's + results are not already in the buffer manager. +*/ +void doUpdate(const LogEntry * e); +/** Undo the update under normal operation, and during recovery. + + Assumes that the operation's results are reflected in the contents of the buffer manager. + + Does not write to the log. + + @todo Currently, undos do not result in CLR entries, but they should. (Should this be done here?) + +*/ +void undoUpdate(const LogEntry * e); +/** + Redoes an operation during recovery. This is different than + doUpdate because it checks to see if the operation needs to be redone + before redoing it. (if(e->lsn > e->rid.lsn) { doUpdate(e); } return) + + Also, this is the only function in operations.h that can take + either CLR or UPDATE log entries. The other functions can only + handle update entries. + + Does not write to the log. +*/ +void redoUpdate(const LogEntry * e); + +END_C_DECLS + +#endif diff --git a/lladd/operations/alloc.h b/lladd/operations/alloc.h new file mode 100644 index 0000000..f678079 --- /dev/null +++ b/lladd/operations/alloc.h @@ -0,0 +1,11 @@ +#include + +#ifndef __ALLOC_H +#define __ALLOC_H + +Operation getAlloc(); +Operation getDealloc(); +recordid Talloc(int xid, size_t size); +void Tdealloc(int xid, recordid rid); + +#endif diff --git a/lladd/operations/decrement.h b/lladd/operations/decrement.h new file mode 100644 index 0000000..3a9ebeb --- /dev/null +++ b/lladd/operations/decrement.h @@ -0,0 +1,65 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * @file + * + * function definitions for decrement + * + * @ingroup OPERATIONS + * + * @see increment.h + * + * $Id$ + */ + +#ifndef __DECREMENT_H__ +#define __DECREMENT_H__ + +/*#include "../constants.h"*/ +#include +/*#include "../bufferManager.h"*/ + +#define Tdecrement(xid,rid) Tupdate(xid,rid,0, OPERATION_DECREMENT) + +Operation getDecrement(); + +#endif diff --git a/lladd/operations/increment.h b/lladd/operations/increment.h new file mode 100644 index 0000000..a766278 --- /dev/null +++ b/lladd/operations/increment.h @@ -0,0 +1,68 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + * @file + * function definitions for increment + * + * Increment provides an example of a logical operation that does not + * require any extra logging information, and (could someday) support + * reordering. + * + * @see decrement.h + * + * $Id$ + */ + + +#ifndef __INCREMENT_H__ +#define __INCREMENT_H__ + +/*#include "../constants.h"*/ +#include +/*#include "../bufferManager.h"*/ + +#define Tincrement(xid,rid) Tupdate(xid,rid,0, OPERATION_INCREMENT) + +Operation getIncrement(); + +#endif diff --git a/lladd/operations/lladdhash.h b/lladd/operations/lladdhash.h new file mode 100644 index 0000000..287986a --- /dev/null +++ b/lladd/operations/lladdhash.h @@ -0,0 +1,78 @@ +/** + * A durable, recoverable hashtable + * Based on Peter Graf's pblhash, + * (actually based on jbhash.c, which was based on pblhash) + * + * + * $Id$ + */ + +/** + @file + + A persistant hash, based on logical operations. + + lladdhash: /yad-hash/ n. LLADD's hash table, based on logical operations. + + @todo CORRECTNESS PROBLEM. It allows logical operations to span + more than one record, which is incompatible with our logical + operations. Also, Blob handling + LLADD hash's implementation + result in poor performance when the bucket size is large, and + transactions are short. + + $Id$ + +*/ + +#ifndef __LLADDHASH_H__ +#define __LLADDHASH_H__ + +/*#include "../transactional.h"*/ + +#include + +#define MAX_LLADDHASHES 1000 + +typedef struct { + recordid store; + size_t keylen; + size_t datlen; + recordid next; +} lladdHashItem_t; + +typedef struct { + int size; + recordid hashmap_record; + /* recordid store; */ + int store; + lladdHashItem_t *iterItem; + unsigned int iterIndex; + void *iterData; + recordid* hashmap; +} lladdHash_t; + +/** Allocate a new hash */ + +lladdHash_t * lHtCreate(int xid, int size); +int lHtValid(int xid, lladdHash_t *ht); +int lHtLookup( int xid, lladdHash_t *ht, const void *key, size_t keylen, void *buf ); +int lHtFirst( int xid, lladdHash_t *ht, void *buf ); +int lHtNext( int xid, lladdHash_t *ht, void *buf ); +int lHtCurrent( int xid, lladdHash_t *ht, void *buf); +int lHtCurrentKey(int xid, lladdHash_t *ht, void *buf); +int lHtDelete(int xid, lladdHash_t *ht); +int lHtPosition( int xid, lladdHash_t *ht, const void *key, size_t key_length ); +/* These two are the only ones that result in a log entry... */ +/* + int _lHtInsert(int xid, lladdHash_t *ht, const void *key, size_t keylen, void * dat, size_t datlen); + int _lHtRemove( int xid, lladdHash_t *ht, const void *key, size_t keylen, void *buf ); +*/ + +int lHtInsert(int xid, lladdHash_t *ht, const void *key, size_t keylen, void * dat, size_t datlen); +int lHtRemove( int xid, lladdHash_t *ht, const void *key, size_t keylen, void *buf, size_t buflen); + +Operation getLHInsert(); +Operation getLHRemove(); + + +#endif diff --git a/lladd/operations/prepare.h b/lladd/operations/prepare.h new file mode 100644 index 0000000..6b233fb --- /dev/null +++ b/lladd/operations/prepare.h @@ -0,0 +1,71 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * @file + * Prepare pseudo-operation + * + * Tprepare() uses the operation interface to abstract away log handling. + * It would be nice if the logger API could be simplified by having + * more of its functionality handled this way. + * + * + * @ingroup OPERATIONS + * + * $Id$ + * + * + */ + +#ifndef __PREPARE_H__ +#define __PREPARE_H__ + +#include + +extern recordid prepare_bogus_rec; + +#define Tprepare(xid, rec, dat) Tupdate(xid, rec, 0, OPERATION_PREPARE) + +Operation getPrepare(); + +int prepareGuard(LogEntry * e, void * state); +void * getPrepareGuardState(); +#endif diff --git a/lladd/operations/set.h b/lladd/operations/set.h new file mode 100644 index 0000000..e3bc33c --- /dev/null +++ b/lladd/operations/set.h @@ -0,0 +1,62 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * @file + * + * function definitions for set + * + * @ingroup OPERATIONS + * + * $Id$ + * + **********************************************/ + +#ifndef __SET_H__ +#define __SET_H__ + +#include + +#define Tset(xid,rid,dat) Tupdate(xid,rid,dat, OPERATION_SET) + +Operation getSet(); + +#endif diff --git a/lladd/page.h b/lladd/page.h new file mode 100644 index 0000000..9653e38 --- /dev/null +++ b/lladd/page.h @@ -0,0 +1,150 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + * @file + * + * interface for dealing with pages + * + * @ingroup LLADD_CORE + * $Id$ + * + * @todo update docs in this file. + **/ + +#ifndef __PAGE_H__ +#define __PAGE_H__ + +#include "common.h" + +BEGIN_C_DECLS + +#include +/*#include */ + +/** + * represents how to look up a record on a page + */ +typedef struct { + int page; + int slot; + size_t size; +} recordid; + + +typedef struct Page_s { + int id; + long LSN; + byte *memAddr; + int dirty; + struct Page_s *next; + /** for replacement policy */ + struct Page_s *prev; + /** this too */ + int queue; +} Page; + +/** + * tracks changes to blobs + */ +typedef struct { + int xid; + recordid *records; + size_t len; +} touchedBlob_t; + +#define DEFAULT_TOUCHED 2 + +/** + * initializes all the important variables needed in all the + * functions dealing with pages. + */ +void pageInit(); + +/** + * assumes that the page is already loaded in memory. It takes + * as a parameter a Page. The Page struct contains the new LSN and the page + * number to which the new LSN must be written to. + */ +void pageWriteLSN(Page page); + +/** + * assumes that the page is already loaded in memory. It takes + * as a parameter a Page and returns the LSN that is currently written on that + * page in memory. + */ +long pageReadLSN(Page page); + +/** + * assumes that the page is already loaded in memory. It takes as a + * parameter a Page, and returns an estimate of the amount of free space on this + * page. This is either exact, or an underestimate. + */ +size_t freespace(Page page); + +/** + * assumes that the page is already loaded in memory. It takes as + * parameters a Page and the size in bytes of the new record. pageRalloc() + * returns a recordid representing the newly allocated record. + */ +recordid pageRalloc(Page page, size_t size); + +void pageWriteRecord(int xid, Page page, recordid rid, const byte *data); + +void pageReadRecord(int xid, Page page, recordid rid, byte *buff); + +void pageCommit(int xid); + +void pageAbort(int xid); + +void pageRealloc(Page *p, int id); + +Page* pageAlloc(int id); + +recordid pageSlotRalloc(Page page, recordid rid); + +int pageTest(); +recordid pageBalloc(Page page, int size, int offset); + +END_C_DECLS + +#endif diff --git a/lladd/recovery2.h b/lladd/recovery2.h new file mode 100644 index 0000000..fb38228 --- /dev/null +++ b/lladd/recovery2.h @@ -0,0 +1,9 @@ + +#ifndef __LLADD_RECOVERY2_H +#define __LLADD_RECOVERY2_H + +void InitiateRecovery(); +/** This really doesn't belong in recovery.c, but there's so much code overlap, it doesn't make sense not to put it there. */ +void undoTrans(); + +#endif diff --git a/lladd/stamp-h.in b/lladd/stamp-h.in new file mode 100644 index 0000000..e69de29 diff --git a/lladd/stamp-h1 b/lladd/stamp-h1 new file mode 100644 index 0000000..dd5938d --- /dev/null +++ b/lladd/stamp-h1 @@ -0,0 +1 @@ +timestamp for lladd/config.h diff --git a/lladd/transactional.h b/lladd/transactional.h new file mode 100644 index 0000000..1c94961 --- /dev/null +++ b/lladd/transactional.h @@ -0,0 +1,186 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + * @defgroup LLADD_CORE Core API + * + * The minimal subset of LLADD necessary to implement transactional consistency. + * + * This module includes the standard API (excluding operations), the logger, the buffer mananger, and recovery code. + * + */ +/** + * @defgroup OPERATIONS Logical Operations + * + * Implementations of logical operations, and the interfaces that allow new operations to be added. + * + * @todo Write a brief howto to explain the implementation of new operations. + * + */ + +/** + * @file + * + * Defines LLADD's primary interface. + * + * + * + * @todo error handling + * + * @ingroup LLADD_CORE + * $Id$ + */ + + + + +#ifndef __TRANSACTIONAL_H__ +#define __TRANSACTIONAL_H__ + +#include "common.h" + +BEGIN_C_DECLS + +#include "page.h" +#include "operations.h" + +/** + * Currently, LLADD has a fixed number of transactions that may be + * active at one time. + */ +#define EXCEED_MAX_TRANSACTIONS 1 + +/** + * @param xid transaction ID + * @param LSN last log that this transaction used + */ +/* @param status @ todo Undocumented. (Unused?) + */ +typedef struct { + int xid; + long LSN; + /* int status; */ +} Transaction; + +/** + * initialize the transactional system, including running recover (if + * necessary), building the operations_table, and opening the logs + * @return 0 on success + * @throws error code on error + */ +int Tinit(); + +/** + * @return positive transaction ID on success, negative return value on error + */ +int Tbegin(); + +/** + * Used when extending LLADD. + * Operation implementors should wrap around this function to provide more mnuemonic names. + * + * @param xid The current transaction. + * @param rid The record the operation pertains to. For some logical operations, this will be a dummy record. + * @param dat Application specific data to be recorded in the log (for undo/redo), and to be passed to the implementation of op. + * @param op The operation's offset in operationsTable + * + * @see operations.h set.h + */ +void Tupdate(int xid, recordid rid, const void *dat, int op); + +/** + * @param xid transaction ID + * @param rid reference to page/slot + * @param dat buffer into which data goes + */ +void Tread(int xid, recordid rid, void *dat); + +/** + * @param xid transaction ID + * @return 0 on success + * @throws error vallue on error + */ +int Tcommit(int xid); + +/** + * @param xid The current transaction + * @param size The size, in bytes of the new record you wish to allocate + * @returns A new recordid. On success, this recordid's size will be + * the requested size. On failure, its size will be zero. + */ +recordid Talloc(int xid, size_t size); + +/* @function Tabort + * @param xid transaction ID + * @return 0 on success, -1 on error. + */ +int Tabort(int xid); + +/** + * flushes all pages, cleans up log + * @return 0 on success + * @throws error value on error + */ +int Tdeinit(); + +/** + * Used by the recovery process. + * Revives Tprepare'ed transactions. + * + * @param xid The xid that is to be revived. + * @param lsn The lsn of that xid's most recent PREPARE entry in the log. + */ +void Trevive(int xid, long lsn); + +/** + * Used by the recovery process. + * + * Sets the number of active transactions. + * Should not be used elsewhere. + * + * @param xid The new active transaction count. + */ +void TsetXIDCount(int xid); + +END_C_DECLS + +#endif diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..6b3b5fc --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id$ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/pbl/Makefile b/pbl/Makefile new file mode 100644 index 0000000..b1e37e5 --- /dev/null +++ b/pbl/Makefile @@ -0,0 +1,197 @@ +# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = .. + +prefix = /usr/local +exec_prefix = ${prefix} + +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 +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/hello +pkglibdir = $(libdir)/hello +pkgincludedir = $(includedir)/hello + +top_builddir = .. + +ACLOCAL = aclocal-1.4 +AUTOCONF = autoconf +AUTOMAKE = automake-1.4 +AUTOHEADER = autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL} +transform = s,x,x, + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = +host_triplet = i686-pc-linux-gnu +AR = ar +AS = @AS@ +CC = gcc +CHECK_CFLAGS = +CHECK_LIBS = -lcheck +CPP = gcc -E +CXX = g++ +CXXCPP = g++ -E +DLLTOOL = @DLLTOOL@ +ECHO = echo +EGREP = grep -E +EXEEXT = +F77 = g77 +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +HAVE_LIB = @HAVE_LIB@ +LIB = @LIB@ +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LN_S = ln -s +LTLIB = @LTLIB@ +MAKEINFO = makeinfo +OBJDUMP = @OBJDUMP@ +OBJEXT = o +PACKAGE = hello +RANLIB = ranlib +RC = @RC@ +STRIP = strip +VERSION = 0.1 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../[config.h] +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu pbl/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = pbl + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu pbl/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/pbl/Makefile.am b/pbl/Makefile.am new file mode 100644 index 0000000..e69de29 diff --git a/pbl/jbhash.h b/pbl/jbhash.h new file mode 100644 index 0000000..3223ce7 --- /dev/null +++ b/pbl/jbhash.h @@ -0,0 +1,176 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * header file for jb hash table structs + * Based on Peter Graf's pblhash, + * Jim Blomo + * $Id$ + */ + +#ifndef __JBHASH_H__ +#define __JBHASH_H__ + +#include +#include + +/* #define JB_HASHTABLE_SIZE 79 */ + +typedef struct { + recordid store; + size_t keylen; + size_t datlen; + recordid next; +} jbHashItem_t; + +typedef struct { + int size; + recordid hashmap_record; /*[JB_HASHTABLE_SIZE]*/ + recordid store; + jbHashItem_t *iterItem; + unsigned int iterIndex; + byte *iterData; + recordid* hashmap; +} jbHashTable_t; + +/** + * jbHtCreate makes a new persistant hashtable + * @param xid transaction id + * + * @param size The number of hashbuckets. Currently, jbHash does not + * resize its bucket table, so it is important to set this number + * appropriately. + * + * @return pointer to hashtable, or NULL on error + */ +jbHashTable_t* jbHtCreate(int xid, int size); + +/** + * jbHtValid determins if a hashtable pointer is valid + * @param xid transaction id + * @param ht hashtable you want to validate + * @return true if valid, false otherwise + */ +int jbHtValid(int xid, jbHashTable_t *ht); + +/** + * Insert a key/value pair + * makes a SHALLOW COPY of the data to keep in durable storage + * will REPLACE an existing entry with the same key + * @param xid transaction id + * @param ht hashtable in which to insert + * @param key pointer to data serving as key + * @param keylen how much data to use from pointer + * @param dat data to insert + * @param datlen length data + * @return -1 on error, 0 on success + */ +int jbHtInsert(int xid, jbHashTable_t *ht, const byte *key, size_t keylen, const byte *dat, size_t datlen); + + +/** + * Lookup a value with a key + * @param xid transaction id + * @param ht hashtable in which to look + * @param key pointer to key data + * @param keylen length of key + * @param buf preallocated buffer in which to put data + * @return -1 if error occurs, including nothing found + */ +int jbHtLookup( int xid, jbHashTable_t *ht, const byte *key, size_t keylen, byte *buf ); + +/** + * Delete entry associated with key + * @param xid transaction id + * @param ht hashtable in which to delete + * @param key pointer to key data + * @param keylen length of key + * @param buf if non-NULL, preallocated space to copy data from deleted key + * @return -1 on errors or not found, 0 if existing entry was deleted + */ +int jbHtRemove( int xid, jbHashTable_t *ht, const byte *key, size_t keylen, byte *buf ); + +/** + * Start an iterator on the hash table + * @param xid transaction id + * @param ht hashtable + * @param buf preallocated space to put data + * @return -1 for no data or error, 0 on success + */ +int jbHtFirst( int xid, jbHashTable_t *ht, byte *buf ); + +/** + * iterates to the next item + * @param xid transaction id + * @param ht hashtable + * @param buf preallocated space to put data + * @return -1 for no data or error, 0 on success + */ +int jbHtNext( int xid, jbHashTable_t *ht, byte *buf ); + +/** + * get data for the place the iterator is currently in + * @param xid transaction id + * @param ht hashtable + * @param buf preallocated space to put data + * @return -1 for no data or error, 0 on success + */ +int jbHtCurrent(int xid, jbHashTable_t *ht, byte *buf); + +/** + * get key for the place the iterator is currently in + * @param xid transaction id + * @param ht hashtable + * @param buf preallocated space to put key + * @return -1 for no data or error, 0 on success + */ +int jbHtCurrentKey(int xid, jbHashTable_t *ht, byte *buf); + +/** + * Delete a hashtable + * table must be empty + * @param xid transaction id + * @param ht hashtable to delete + * @return 0 on success, -1 on error + */ +int jbHtDelete(int xid, jbHashTable_t *ht); + +#endif diff --git a/pbl/pbl.h b/pbl/pbl.h new file mode 100644 index 0000000..1b538f1 --- /dev/null +++ b/pbl/pbl.h @@ -0,0 +1,549 @@ +#ifndef _PBL_H_ +#define _PBL_H_ +/* + pbl.h - external include file of library + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + $Log$ + Revision 1.1 2004/06/24 21:11:33 sears + Initial revision + + Revision 1.4 2004/06/09 21:27:40 sears + Final CVS checkin before major refactoring. + + Revision 1.3 2003/12/11 10:48:16 jim + compiles, not link. added quasi-pincount, shadow pages + + Revision 1.2 2003/12/11 09:21:20 jim + update includes + + Revision 1.1 2003/12/11 09:10:48 jim + pbl + + Revision 1.2 2002/09/12 20:47:18 peter + added the isam file handling to the library + + Revision 1.1 2002/09/05 13:44:12 peter + Initial revision + + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char* _PBL_H_id = "$Id$"; +static int _PBL_H_fct() { return( _PBL_H_id ? 0 : _PBL_H_fct() ); } + +#include + +/*****************************************************************************/ +/* #defines */ +/*****************************************************************************/ + +#ifdef _WIN32 + +/* + * some functions have strange names on windows + */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define snprintf _snprintf + +#else + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#endif + +#define PBL_ERRSTR_LEN 2048 + +/** @name B: Files + * list of files of component + *

+ * FILES + *

    + *
  • pbl.h - the include file of the library + *
  • pbl.c - source for the base functions + *
  • pblhash.c - source file for the + * hash functions + *
  • pblhttst.c - source file for the + * hash function test frame + *
  • pblkf.c - source file for the key + * file functions + *
  • pblkftst.c - source file for the + * key file handling test frame + *
  • pblisam.c - source file for the isam + * file functions + *
  • pbliftst.c - source file for the + * isam file handling test frame + *
  • makefile - a Unix makefile for the + * component + *
  • pblhttstdeb.dsp - a Microsoft Visual + * Studio 6.0 project file for + * hash table debug + *
  • pblkftstdeb.dsp - a Microsoft + * Visual Studio 6.0 project file + * for key file debug + *
  • pbliftstdeb.dsp - a Microsoft Visual + * Studio 6.0 project file for + * isam file debug + *
  • ISAM0001.LOG - a test case for the + * isam file handling test frame + *
  • pbl.dxx - the source for this document + *
+ */ + +#define PBL_FILE_LIST + +/** @name C: Error codes + * error codes of the pbl library + * + * @field PBL_ERROR_OUT_OF_MEMORY out of memory + * @field PBL_ERROR_EXISTS record already exists + * @field PBL_ERROR_NOT_FOUND record not found + * @field PBL_ERROR_BAD_FILE file structure damaged + * @field PBL_ERROR_PARAM_MODE parameter mode is not valid + * @field PBL_ERROR_PARAM_KEY parameter key is not valid + * @field PBL_ERROR_PARAM_KEYLEN parameter keylen is not valid + * @field PBL_ERROR_PARAM_DATA parameter data is not valid + * @field PBL_ERROR_PARAM_DATALEN parameter datalen is not valid + * @field PBL_ERROR_PARAM_INDEX parameter index is not valid + * @field PBL_ERROR_CREATE file system create error, see errno + * @field PBL_ERROR_OPEN file system open error, see errno + * @field PBL_ERROR_SEEK file system seek error, see errno + * @field PBL_ERROR_READ file system read error, see errno + * @field PBL_ERROR_WRITE file system write error, see errno + * @field PBL_ERROR_PROGRAM an internal error in the code, debug it!! + * @field PBL_ERROR_NOFIT internal error forcing a block split + * @field PBL_ERROR_NOT_ALLOWED file not open for update, operation not allowed + * @field PBL_ERROR_POSITION current record is not positioned + */ +#define PBL_ERROR_BASE 1000 + +#define PBL_ERROR_OUT_OF_MEMORY ( PBL_ERROR_BASE + 1 ) +#define PBL_ERROR_EXISTS ( PBL_ERROR_BASE + 2 ) +#define PBL_ERROR_NOT_FOUND ( PBL_ERROR_BASE + 3 ) +#define PBL_ERROR_BAD_FILE ( PBL_ERROR_BASE + 4 ) +#define PBL_ERROR_PARAM_MODE ( PBL_ERROR_BASE + 5 ) +#define PBL_ERROR_PARAM_KEY ( PBL_ERROR_BASE + 6 ) +#define PBL_ERROR_PARAM_KEYLEN ( PBL_ERROR_BASE + 7 ) +#define PBL_ERROR_PARAM_DATA ( PBL_ERROR_BASE + 8 ) +#define PBL_ERROR_PARAM_DATALEN ( PBL_ERROR_BASE + 9 ) +#define PBL_ERROR_PARAM_INDEX ( PBL_ERROR_BASE + 10 ) + +#define PBL_ERROR_CREATE ( PBL_ERROR_BASE + 20 ) +#define PBL_ERROR_OPEN ( PBL_ERROR_BASE + 21 ) +#define PBL_ERROR_SEEK ( PBL_ERROR_BASE + 22 ) +#define PBL_ERROR_READ ( PBL_ERROR_BASE + 23 ) +#define PBL_ERROR_WRITE ( PBL_ERROR_BASE + 24 ) + +#define PBL_ERROR_PROGRAM ( PBL_ERROR_BASE + 30 ) +#define PBL_ERROR_NOFIT ( PBL_ERROR_BASE + 31 ) + +#define PBL_ERROR_NOT_ALLOWED ( PBL_ERROR_BASE + 40 ) +#define PBL_ERROR_POSITION ( PBL_ERROR_BASE + 41 ) + +/** @name D: Definitions for Key File Parameters + * DEFINES FOR PARAMETER mode OF \Ref{pblKfFind}() + * @field PBLEQ any record that is equal + * @field PBLFI first record that is equal + * @field PBLLA last record that is equal + * @field PBLGE last equal or first that is greater + * @field PBLGT first that is greater + * @field PBLLE first equal or last that is smaller + * @field PBLLT last that is smaller + */ +#define PBLEQ 1 +#define PBLFI 2 +#define PBLLA 3 +#define PBLGE 4 +#define PBLGT 5 +#define PBLLE 6 +#define PBLLT 7 + +/** @name E: Definitions for ISAM Parameters + * DEFINES FOR PARAMETER which OF \Ref{pblIsamGet}() + * @field PBLTHIS get key and keylen of current record + * @field PBLNEXT get key and keylen of next record + * @field PBLPREV get key and keylen of previous record + * @field PBLFIRST get key and keylen of first record + * @field PBLLAST get key and keylen of last record + */ +#define PBLTHIS 1 +#define PBLNEXT 2 +#define PBLPREV 3 +#define PBLFIRST 4 +#define PBLLAST 5 + +/** + * the maximum length of a key of the key file component, + * @doc maximum length of a key, 255 for now + */ +#define PBLKEYLENGTH 255 + +/** + * maximum data length of data being stored on index blocks of key files, + * @doc maximum length of data stored with an item on the level 0 block, 1024 + * @doc data that is longer is stored on data blocks. + */ +#define PBLDATALENGTH 1024 + +/*****************************************************************************/ +/* macros */ +/*****************************************************************************/ + +/* + * The PBL_MEMTRACE define can be used for debugging the library, + * if defined the library will log a line for all memory chunks + * that are allocated for more than 3 minutes into the file ./pblmemtrace.log + * + * This can be used to detect heap memory lost by the code. + * See also function pbl_memtrace_out in pbl.c + */ + +/* #define PBL_MEMTRACE */ +#ifdef PBL_MEMTRACE + +extern void pbl_memtrace_delete( void * data ); +extern void pbl_memtrace_out( int checktime ); + +#define PBL_FREE( ptr ) if( ptr ){ pbl_memtrace_delete( ptr );\ + free( ptr ); ptr = 0; } + +#else + +/** + * make free save against NULL pointers, + * @doc also the parameter ptr is set to NULL + */ +#define PBL_FREE( ptr ) if( ptr ){ free( ptr ); ptr = 0; } + +#endif + +/** + * macros for linear list handling, + */ +#define PBL_LIST_( Parameters ) + +/** + * push an element to the beginning of a linear list + */ +#define PBL_LIST_PUSH( HEAD, TAIL, ITEM, NEXT, PREV )\ +{\ + (ITEM)->PREV = 0;\ + if(( (ITEM)->NEXT = (HEAD) ))\ + { (ITEM)->NEXT->PREV = (ITEM); }\ + else\ + { (TAIL) = (ITEM); }\ + (HEAD) = (ITEM);\ +} + +/** + * append an element to the end of a linear list + */ +#define PBL_LIST_APPEND( HEAD, TAIL, ITEM, NEXT, PREV )\ + PBL_LIST_PUSH( TAIL, HEAD, ITEM, PREV, NEXT ) + +/** + * remove an element from a linear list + */ +#define PBL_LIST_UNLINK( HEAD, TAIL, ITEM, NEXT, PREV )\ +{\ + if( (ITEM)->NEXT )\ + { (ITEM)->NEXT->PREV = (ITEM)->PREV; }\ + else\ + { (TAIL) = (ITEM)->PREV; }\ + if( (ITEM)->PREV )\ + { (ITEM)->PREV->NEXT = (ITEM)->NEXT; }\ + else\ + { (HEAD) = (ITEM)->NEXT; }\ +} + +/* + * SOME MACROS FOR KEY FILE READ FUNCTIONS + */ +/** + * set the current record to the first record of the file + */ +#define pblKfFirst( KF, K, L ) pblKfGetAbs( KF, 0, K, L ) + +/** + * set the current record to the last record of the file + */ +#define pblKfLast( KF, K, L ) pblKfGetAbs( KF, -1, K, L ) + +/** + * set the current record to the next record of the file + */ +#define pblKfNext( KF, K, L ) pblKfGetRel( KF, 1, K, L ) + +/** + * set the current record to the previous record of the file + */ +#define pblKfPrev( KF, K, L ) pblKfGetRel( KF, -1, K, L ) + +/** + * return the datalen of the current record + */ +#define pblKfThis( KF, K, L ) pblKfGetRel( KF, 0, K, L ) + +/*****************************************************************************/ +/* typedefs */ +/*****************************************************************************/ + +struct pblHashTable_s +{ + char * magic; +}; + +/** + * the hash table type the pblHt* functions are dealing with, + * @doc the details of the structure are hidden from the user + */ +typedef struct pblHashTable_s pblHashTable_t; + +struct pblKeyFile_s +{ + char * magic; +}; + +/** + * the key file type the pblKf* functions are dealing with, + * @doc the details of the structure are hidden from the user + */ +typedef struct pblKeyFile_s pblKeyFile_t; + +struct pblIsamFile_s +{ + char * magic; +}; + +/** + * the ISAM file type the pblIsam* functions are dealing with, + * @doc the details of the structure are hidden from the user + */ +typedef struct pblIsamFile_s pblIsamFile_t; + +/*****************************************************************************/ +/* variable declarations */ +/*****************************************************************************/ +/** + * integer value used for returning error codes + */ +extern int pbl_errno; + +/** + * character buffer used for returning error strings + */ +extern char * pbl_errstr; + +/*****************************************************************************/ +/* function declarations */ +/*****************************************************************************/ +extern void * pbl_malloc( char * tag, size_t size ); +extern void * pbl_malloc0( char * tag, size_t size ); +extern void * pbl_memdup( char * tag, void * data, size_t size ); +extern void * pbl_mem2dup( char * tag, void * mem1, size_t len1, + void * mem2, size_t len2 ); +extern int pbl_memcmplen( void * left, size_t llen, + void * right, size_t rlen ); +extern int pbl_memcmp( void * left, size_t llen, void * right, size_t rlen ); +extern size_t pbl_memlcpy( void * to, size_t tolen, void * from, size_t n ); + +extern void pbl_ShortToBuf( unsigned char * buf, int s ); +extern int pbl_BufToShort( unsigned char * buf ); +extern void pbl_LongToBuf( unsigned char * buf, long l ); +extern long pbl_BufToLong( unsigned char * buf ); +extern int pbl_LongToVarBuf( unsigned char * buffer, unsigned long value ); +extern int pbl_VarBufToLong( unsigned char * buffer, long * value ); +extern int pbl_LongSize( unsigned long value ); +extern int pbl_VarBufSize( unsigned char * buffer ); + +extern pblHashTable_t * pblHtCreate( ); +extern int pblHtInsert ( pblHashTable_t * h, void * key, size_t keylen, + void * dataptr); +extern void * pblHtLookup ( pblHashTable_t * h, void * key, size_t keylen ); +extern void * pblHtFirst ( pblHashTable_t * h ); +extern void * pblHtNext ( pblHashTable_t * h ); +extern void * pblHtCurrent ( pblHashTable_t * h ); +extern void * pblHtCurrentKey ( pblHashTable_t * h ); +extern int pblHtRemove ( pblHashTable_t * h, void * key, size_t keylen ); +extern int pblHtDelete ( pblHashTable_t * h ); + +/* + * FUNCTIONS ON KEY FILES + */ + int pblKfInit ( int nblocks ); +extern pblKeyFile_t * pblKfCreate( char * path, void * filesettag ); +extern pblKeyFile_t * pblKfOpen ( char * path, int update, void * filesettag ); +extern int pblKfClose ( pblKeyFile_t * k ); +extern int pblKfFlush ( pblKeyFile_t * k ); +extern int pblKfStartTransaction( pblKeyFile_t * k ); +extern int pblKfCommit( pblKeyFile_t * k, int rollback ); +extern int pblKfSavePosition( pblKeyFile_t * k ); +extern int pblKfRestorePosition( pblKeyFile_t * k ); + +extern void pblKfSetCompareFunction( +pblKeyFile_t * k, /** key file to set compare function for */ +int ( *keycompare ) /** compare function to set */ + ( + void* left, /** "left" buffer for compare */ size_t llen, /** length of that buffer */ void* right, /** "right" buffer for compare */ size_t rlen /** length of that buffer */ + ) +); + +/* + * WRITE FUNCTIONS ON RECORDS, DELETE AND UPDATE WORK ON CURRENT RECORD + */ +extern int pblKfInsert( +pblKeyFile_t * k, +unsigned char * key, +int keylen, +unsigned char * data, +long datalen +); + +extern int pblKfDelete( pblKeyFile_t * k ); + +extern int pblKfUpdate( +pblKeyFile_t * k, +unsigned char * data, +long datalen +); + +/* + * KEY FILE READ FUNCTIONS ON RECORDS + */ +extern long pblKfFind( +pblKeyFile_t * k, +int mode, +unsigned char * skey, +int skeylen, +unsigned char * okey, +int * okeylen +); + +extern long pblKfRead( +pblKeyFile_t * k, +unsigned char * data, +long datalen +); + +/* + * FUNCTIONS ACTUALLY ONLY TO BE USED THROUGH THE MAKROS DEFINED BELOW + * + * however, the functions work, but they are not very fast + * + * pblKfGetRel - positions relative to the current record to any other + * record of the file, interface is like pblKfNext + * + * pblKfGetAbs - positions absolute to the absindex 'th record of the file, + * -1L means last, interface is like pblKfFirst + */ +extern long pblKfGetRel( pblKeyFile_t * k, long relindex, + char *okey, int *okeylen); +extern long pblKfGetAbs( pblKeyFile_t * k, long absindex, + char *okey, int *okeylen); + +/* + * FUNCTIONS ON ISAM FILES + */ +extern int pblIsamClose( pblIsamFile_t * isamfile ); +extern int pblIsamFlush( pblIsamFile_t * isamfile ); +extern int pblIsamDelete( pblIsamFile_t * isamfile ); + +extern pblIsamFile_t * pblIsamOpen( +char * path, +int update, +void * filesettag, +int nkeys, +char ** keyfilenames, +int * keydup +); + +extern int pblIsamInsert( +pblIsamFile_t * isamfile, +unsigned char * allkeys, +int allkeyslen, +unsigned char * data, +long datalen +); + +extern int pblIsamFind( +pblIsamFile_t * isamfile, +int mode, +int index, +unsigned char * skey, +int skeylen, +unsigned char * okey +); + +extern int pblIsamGet( +pblIsamFile_t * isamfile, +int which, +int index, +unsigned char * okey +); + +extern int pblIsamReadKey( +pblIsamFile_t * isamfile, +int index, +unsigned char * okey +); + +extern long pblIsamReadDatalen( pblIsamFile_t * isamfile ); + +extern long pblIsamReadData( +pblIsamFile_t * isamfile, +unsigned char * buffer, +long bufferlen +); + +extern long pblIsamUpdateData( +pblIsamFile_t * isamfile, +unsigned char * data, +long datalen +); + +extern int pblIsamUpdateKey( +pblIsamFile_t * isamfile, +int index, +unsigned char * ukey, +int ukeylen +); + +extern int pblIsamStartTransaction( int nfiles, pblIsamFile_t ** isamfiles ); +extern int pblIsamCommit( int nfiles, pblIsamFile_t ** isamfiles, int rollback); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/reconf b/reconf new file mode 100755 index 0000000..ac4acf0 --- /dev/null +++ b/reconf @@ -0,0 +1,11 @@ +#!/bin/sh +rm -f config.cache +rm -f acconfig.h +#touch acconfig.h +#aclocal -I m4 +aclocal +autoconf +autoheader +#acconfig +automake -a +exit diff --git a/src/2pc/2pc.c b/src/2pc/2pc.c new file mode 100644 index 0000000..4133f77 --- /dev/null +++ b/src/2pc/2pc.c @@ -0,0 +1,285 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "2pc.h" +#include +#include +#include "../libdfa/callbacks.h" + +#define TRUE 1 +#define FALSE 0 +/* #define _TWO_PC 1 */ + +const int transition_count_2pc = 14; +const int client_transition_count_2pc = 4; +const int state_count_2pc = 9; + + + +callback_fcn check_veto_2pc; +callback_fcn tally_2pc; +callback_fcn send_ack_2pc; +callback_fcn coordinator_init_xact_2pc; +callback_fcn veto_or_prepare_2pc; +callback_fcn abort_2pc; +callback_fcn commit_2pc; + + +/* Remember to update transition_count_2pc if you add/remove transitions */ +Transition transitions_2pc[] = { + + /* Coordinator transitions */ + + /* Library user must provide callback that init_xact_2pc calls. */ + { AWAIT_ARRIVAL, NULL_STATE, COORDINATOR_START_2PC, coordinator_init_xact_2pc, FALSE }, + { AWAIT_COMMIT_POINT, NULL_STATE, COORDINATOR_START_2PC, coordinator_init_xact_2pc, FALSE }, + { AWAIT_RESULT, NULL_STATE, COORDINATOR_START_2PC, coordinator_init_xact_2pc, FALSE }, + { NULL_STATE, NULL_STATE, COORDINATOR_START_2PC, coordinator_init_xact_2pc, FALSE }, + + /* TODO: tally_2pc and check_veto_2pc should respond to initiator where applicable. */ + { SUBORDINATE_VETO_2PC, COORDINATOR_START_2PC, COORDINATOR_ABORTING_2PC, &check_veto_2pc, TRUE }, + { SUBORDINATE_PREPARED_2PC, COORDINATOR_START_2PC, COORDINATOR_COMMITTING_2PC, &tally_2pc, TRUE }, + { SUBORDINATE_ACKING_2PC, COORDINATOR_ABORTING_2PC, NULL_STATE, &tally_2pc, FALSE}, + { SUBORDINATE_ACKING_2PC, COORDINATOR_COMMITTING_2PC, NULL_STATE, &tally_2pc, FALSE}, + + /* Subordinate transitions */ + /* veto_or_prepare overrides target state. */ + + /* Library user must provide the subordinate function pointers for these transitions */ + { COORDINATOR_START_2PC, NULL_STATE, OVERRIDDEN_STATE, &veto_or_prepare_2pc, TRUE }, + { COORDINATOR_ABORTING_2PC, SUBORDINATE_PREPARED_2PC, NULL_STATE, &abort_2pc, FALSE}, + { COORDINATOR_COMMITTING_2PC, SUBORDINATE_PREPARED_2PC, NULL_STATE, &commit_2pc, FALSE}, + { COORDINATOR_ABORTING_2PC, SUBORDINATE_VETO_2PC, NULL_STATE, NULL, FALSE}, + + /* transition fcn always fails, but sends ack to coordinator */ + { COORDINATOR_COMMITTING_2PC, NULL_STATE, OVERRIDDEN_STATE, &send_ack_2pc, TRUE}, + { COORDINATOR_ABORTING_2PC, NULL_STATE, OVERRIDDEN_STATE, &send_ack_2pc, TRUE}, + + + + +}; + +Transition client_transitions_2pc[] = { + + /* Caller transitions */ + + { COORDINATOR_START_2PC, AWAIT_ARRIVAL, NULL_STATE, NULL, FALSE}, + + { COORDINATOR_COMMITTING_2PC, AWAIT_COMMIT_POINT, NULL_STATE, NULL, FALSE}, + { COORDINATOR_ABORTING_2PC, AWAIT_COMMIT_POINT, NULL_STATE, NULL, FALSE}, + + { SUBORDINATE_ACKING_2PC, AWAIT_RESULT, NULL_STATE, NULL, FALSE}, + + + +}; + + +State states_2pc[MAX_STATE_COUNT] = { + +/* Coordinator states */ + + { COORDINATOR_START_2PC, NULL, NULL }, /* Need abort fcn */ + { COORDINATOR_COMMITTING_2PC, NULL, NULL }, + { COORDINATOR_ABORTING_2PC, NULL, NULL }, + +/* Subordinate states */ + + { SUBORDINATE_VETO_2PC, NULL, NULL }, /* Need to think about callback fcns */ + { SUBORDINATE_PREPARED_2PC, NULL, NULL }, + { SUBORDINATE_ACKING_2PC, NULL, NULL }, + + /* Client states */ + + { AWAIT_ARRIVAL, NULL, NULL}, + { AWAIT_RESULT, NULL, NULL}, + { AWAIT_COMMIT_POINT, NULL, NULL}, + +}; + + + + +/* + + - add broadcast to messages.h (Done) + - change libdfa so that it scans the states array (Done) + - add support for OVERRIDDEN_STATE to libdfa (Done, test it) + - add support for transactions to libdfa (Need to replace monotree) + - write the callback fcns. (~Done, test it!) + +*/ + + +/* Probably should ack the client that called commit(), instead of + hoping that UDP got it here for them... ;) So, they should have a + state machine that initiated the transaction, and waits for an ACK + or NAK from us. */ +state_name coordinator_init_xact_2pc(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + TwoPCMachineState * state = (TwoPCMachineState*) &(stateMachine->app_state); + TwoPCAppState * app_state = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); + short bc_group = app_state->get_broadcast_group(dfaSet, m); + int ret; + + if(!app_state->is_coordinator) { + return 0; + } + + printf("bc_group %d\n", bc_group); + + /* Need to check for this somewhere... */ + assert(sizeof(TwoPCAppState) <= MAX_APP_STATE_SIZE); + + memset(state->subordinate_votes, 0, MAX_SUBORDINATES); + /* state->xid = m->from_machine_id; */ + state->xid = stateMachine->machine_id; + printf("From: %s", from); + /*strncpy(state->initiator, from, MAX_ADDRESS_LENGTH);*/ + + sprintf(from, "bc:%d\n", bc_group); + + /* TODO: (n)ack the client. (Implies yes / no / already pending return values for callback on last line) + Currently, this is handled by the library user. It could be moved back into here. + + */ + if(app_state->init_xact_2pc != NULL) { + ret = app_state->init_xact_2pc(dfaSet, stateMachine, m, from); + } else { + ret = 1; + } + /* Where was this before?? */ + m->from_machine_id = stateMachine->machine_id; + + return ret; + + +} +state_name send_ack_2pc(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + respond_once(&((DfaSet*)dfaSet)->networkSetup, SUBORDINATE_ACKING_2PC, m, from); + return OVERRIDDEN_STATE; +} + +/** + TODO: Can this be done in a way that avoids blocking? +*/ +state_name veto_or_prepare_2pc(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + TwoPCAppState * app_state = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); + + return app_state->veto_or_prepare_2pc(dfaSet, stateMachine, m, from); +} + +/** + TODO: The next two functions should fork and immediately return true. +*/ + +state_name abort_2pc(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + TwoPCAppState * app_state = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); + + send_ack_2pc(dfaSet, stateMachine, m, from); + + return app_state->abort_2pc(dfaSet, stateMachine, m, from); +} + +state_name commit_2pc(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + TwoPCAppState * app_state = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); + + send_ack_2pc(dfaSet, stateMachine, m, from); + return app_state->commit_2pc(dfaSet, stateMachine, m, from); +} + +state_name check_veto_2pc(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + /* Clear subordinate_votes array, so that it can be used to + tally acks after the votes are tallied. */ + + TwoPCAppState * app_state = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); + TwoPCMachineState * machine_state = (TwoPCMachineState*)&(stateMachine->app_state); + + /* if (!check_from()) { return 0; } */ + short bc_group = app_state->get_broadcast_group(dfaSet, m); + + printf("bc_group:veto %d\n", bc_group); + + memset(machine_state->subordinate_votes, 0, MAX_SUBORDINATES); + sprintf(from, "bc:%d", bc_group); + + return 1; +} + +state_name tally_2pc(void * dfaSetPtr, StateMachine * stateMachine, Message * m, char * from) { + + TwoPCMachineState * machine_state = (TwoPCMachineState*)&(stateMachine->app_state); + DfaSet * dfaSet = (DfaSet*) dfaSetPtr; + + TwoPCAppState * app_state = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); + + /* if (!check_from()) { return 0; } */ + short bc_group = app_state->get_broadcast_group(dfaSet, m); + + if(bc_group < dfaSet->networkSetup.broadcast_lists_count) { + state_name ret = tally(dfaSet->networkSetup.broadcast_lists[bc_group], + dfaSet->networkSetup.broadcast_list_host_count[bc_group], + (char*)(machine_state->subordinate_votes), from); + if(ret) { + /* Clear subordinate_votes array, so that it can be used to + tally acks after the votes are tallied. */ + memset(machine_state->subordinate_votes, 0, MAX_SUBORDINATES); + } + + + /* Needed to use the from variable to do the tally, so this + sprintf needs to be down here. */ + + sprintf(from, "bc:%d", bc_group); + + if(ret && app_state->tally_2pc != NULL) { + return app_state->tally_2pc(dfaSet, stateMachine, m, from); + } else { + return ret; + } + } else { + sprintf(from, "bc:%d", bc_group); + + return FALSE; + } + +} + diff --git a/src/2pc/2pc.h b/src/2pc/2pc.h new file mode 100644 index 0000000..8d13c8a --- /dev/null +++ b/src/2pc/2pc.h @@ -0,0 +1,153 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#define MAX_SUBORDINATES 10 + +/** To use this library, you need to implement: + +
    +
  • get_broadcast_group, which maps from message to broadcast group. +
  • prepare_or_veto_2pc, which, given a message, returns SUBORDINATE_VETO_2PC or SUBORDINATE_PREPARED_2PC, and calls abort, if appropriate +
  • abort, which handles the application specific actions for abort +
  • commit, which handles the application specific commit. +
+ +A note on transaction ID's: clients specify transaction ID's by +addressing messages to the state machine with machine_id = +transaction_id. + +The coordinator sends an ack to the client once the transaction +commits or aborts, and keeps the machine around until the client ack's +the ack. This is done in order to provide exactly once semantics. + +No locking, or ordering of requests is performed by the library. + +The 64-bit transaction id's could, in principle, be reused. + +Distinct requests with identical transaction id's are serialized by +the current implementation, but no scheduling is done. The first +request that retries after a transaction completes is the one that +gets to reuse the transaction id. + + +*/ +/* + These will generally be defined by the user of the library. + + (If you need more than one instance of 2pc per binary, memcpy the tranistions_2pc and states_2pc arrays...) + +*/ + +/* STATES */ +#define COORDINATOR_START_2PC 101 +#define COORDINATOR_COMMITTING_2PC 102 +#define COORDINATOR_ABORTING_2PC 103 + +#define SUBORDINATE_VETO_2PC 201 +#define SUBORDINATE_PREPARED_2PC 202 +#define SUBORDINATE_ACKING_2PC 203 + +#define AWAIT_ARRIVAL 211 +#define AWAIT_COMMIT_POINT 212 +#define AWAIT_RESULT 213 + +/** + The callbacks are called whenever the transition 'should' succeed. + Other than tally_2pc, they are always called when a + corresponding message comes in. tally_2pc is only called after + the last subordinate votes to prepare. + + All callbacks (other than veto_or_prepare) should return TRUE or + FALSE, depending on whether or not the transition should + succeed. veto_or_prepare returns SUBORDINATE_PREPARED_2PC, + SUBORDINATE_VETO_2PC, or OVERRIDDEN_STATE. + + Under normal operations, they should never return OVERRIDDEN_STATE + or FALSE, since that would violate the normal 2pc protocol. + +*/ +typedef struct { + /** The global transaction ID. Provided by caller of api's commit() function. */ + int xid; + /* char initiator[MAX_ADDRESS_LENGTH]; */ + + /** Right now, get number of subordinates from network setup. (Need + to do something more fancy for recursive transactions.) + */ + char subordinate_votes[MAX_SUBORDINATES]; + +} TwoPCMachineState; + + + +typedef struct { + /** TRUE if this instance of the program is the coordinator. A + single process could be both a subordinate and the coordinator, + in priniciple. In that case, is_coordinator should be set to + true, (and the coordinator process's address sould be present in + two broadcast groups.) */ + char is_coordinator; + callback_fcn *init_xact_2pc; + callback_fcn *veto_or_prepare_2pc; + callback_fcn *abort_2pc; + callback_fcn *commit_2pc; + callback_fcn *tally_2pc; + /** + The get_broadcast_group function should return the number of the + broadcast group that the message should be forwarded to. (The + coordinator is in broadcast group 0, so this function should + return a number greater than zero. + */ + short (*get_broadcast_group)(DfaSet *, Message * m); + recordid app_state_record_id; + void * app_state; +} TwoPCAppState; + +/* #ifndef _TWO_PC */ +extern const int transition_count_2pc; +extern const int client_transition_count_2pc; +extern const int state_count_2pc; +extern Transition client_transitions_2pc[]; +extern Transition transitions_2pc[]; +extern State states_2pc[]; +/* #endif */ diff --git a/src/2pc/Makefile.am b/src/2pc/Makefile.am new file mode 100644 index 0000000..3c27b81 --- /dev/null +++ b/src/2pc/Makefile.am @@ -0,0 +1,4 @@ +#LDADD=$(top_builddir)/build/libdfa.a +lib_LIBRARIES=lib2pc.a +lib2pc_a_SOURCES=2pc.c +AM_CFLAGS= -g -Wall -pedantic -std=gnu99 diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..5757a2e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = pbl lladd libdfa 2pc timing apps diff --git a/src/apps/Makefile.am b/src/apps/Makefile.am new file mode 100644 index 0000000..206dbf2 --- /dev/null +++ b/src/apps/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = cht #cyrus diff --git a/src/apps/cht/Makefile.am b/src/apps/cht/Makefile.am new file mode 100644 index 0000000..95cb6b5 --- /dev/null +++ b/src/apps/cht/Makefile.am @@ -0,0 +1,5 @@ +LDADD=$(top_builddir)/src/libdfa/libdfa.a $(top_builddir)/src/2pc/lib2pc.a +SOURCES=cht.c +lib_LIBRARIES=libcht.a +libcht_a_SOURCES=cht.c +AM_CFLAGS= -g -Wall -pedantic -std=gnu99 diff --git a/src/apps/cht/cht.c b/src/apps/cht/cht.c new file mode 100644 index 0000000..49faf5b --- /dev/null +++ b/src/apps/cht/cht.c @@ -0,0 +1,652 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "cht.h" +#include +#include +#include +#include +#include "../../2pc/2pc.h" +#include "../../libdfa/callbacks.h" +#include +#define CREATE 1 +#define INSERT 2 +#define LOOKUP 3 +#define REMOVE 4 +#define DELETE 5 +/** Unimplemented: Evaluate a function call from a table provided by the library user. */ +#define TSTSET 6 +#define GETXID 7 +/* #define COMMIT 8 + #define ABORT 9 */ + +typedef struct { + unsigned short key_length; + unsigned short value_length; + unsigned char request_type; + unsigned char response_type; + clusterHashTable_t hashTable; +} payload_header; + +typedef struct { + int ht_xid; + jbHashTable_t * xid_ht; + jbHashTable_t * ht_ht; + int next_hashTableId; +} CHTAppState; + + + +#define __header_ptr(m) ((payload_header*)(&((m)->payload))) + +static unsigned short* _key_length(Message * m) { + return &(__header_ptr(m)->key_length); +} + +static unsigned short* _value_length(Message *m) { + return &(__header_ptr(m)->value_length); +} + +#define getKeyLength(m) (ntohs(*_key_length(m))) +#define setKeyLength(m, x) (*_key_length(m)=htons(x)) + + +#define getValLength(m) (ntohs(*_value_length(m))) +#define setValLength(m, x) (*_value_length(m)=htons(x)) + +static unsigned char * requestType(Message *m) { + return &(__header_ptr(m)->request_type); +} + +static unsigned char * responseType(Message *m) { + return &(__header_ptr(m)->response_type); +} + +/** TODO: Endianness. (ICK) */ +#define setup_vars \ +state_name request_type =*(requestType(m)); \ +state_name response_type =*(responseType(m)); \ +TwoPCMachineState * machine_state_2pc = (TwoPCMachineState*) &(stateMachine->app_state); \ +TwoPCAppState * app_state_2pc = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); \ +CHTAppState * app_state_cht = app_state_2pc->app_state; \ +jbHashTable_t * xid_ht = app_state_cht->xid_ht; \ +jbHashTable_t * ht_ht = app_state_cht->ht_ht; \ +int ht_xid = app_state_cht->ht_xid; \ +int xid; \ +int xid_exists = (-1 != jbHtLookup(ht_xid, xid_ht, &(stateMachine->machine_id), sizeof(state_machine_id), &xid)); \ +jbHashTable_t ht; \ +int ht_exists = (-1 != jbHtLookup(ht_xid, ht_ht, &(__header_ptr(m)->hashTable), sizeof(clusterHashTable_t), &ht)) + + + + +/** + * Hash function generator, taken directly from pblhash + */ +static int hash( const unsigned char * key, size_t keylen , int table_length) { + int ret = 104729; + + for( ; keylen-- > 0; key++ ) + { + if( *key ) + { + ret *= *key + keylen; + ret %= table_length; + } + } + + return( ret % table_length ); +} + +void * getKeyAddr(Message *m) { + char * stuff = m->payload; + + return (stuff + sizeof(payload_header)); /* Just add the header length. */ + +} + +void * getValAddr(Message * m) { + return ((char*)getKeyAddr(m)) + getKeyLength(m); /* key address + key length. */ +} + +/** + + @return 1 if the payload is valid (key_length and value length do not over-run the message's memory, 0 otherwise.) + +*/ +int checkPayload(Message * m) { + char * a = (char*)m; + char * b = getValAddr(m); + return (a+ sizeof(Message) ) >= (b + getValLength(m)); +} + +/** TODO: multiplex_interleaved needs to return a special group for + begin/commit/abort requests. There will then be two types of + transactions. Explicit ones will create xids on all replicas, and + span multiple operations. Implcit ones will only span one replica + group, but may only contain a single operation. +*/ +short multiplex_interleaved(DfaSet * dfaSet, Message * m) { + short table_length = dfaSet->networkSetup.broadcast_lists_count-2; + short bc_group; + if((*requestType(m) == CREATE) || (*requestType(m) == DELETE)) { + /* Special case: Send to all replicas...bc_group one should contain all replicas... */ + bc_group = 1; + } else { + /* Need to add one so that no requests are assigned to the coordinator (bc:0) */ + bc_group = hash(getKeyAddr(m), getKeyLength(m), table_length) + 2; + } + + printf("request %d bc group: %d\n", *requestType(m), bc_group); + + return bc_group; + +} + +state_name do_work(void * dfaSet, StateMachine * stateMachine, Message * m, char * from); + +/** + The client side function that 'does everything' + + @param request_type The type of request to be run. + + @param response_type The expected response type. Returns 1 if this + remote state is returned, 0 otherwise. (TODO: + Double check this documentation.) + + @param xid The (stateMachine) transaction id. Set to a random + number when calling BEGIN. To prevent deadlock, it's + best to choose a number unlikely to correspond to an + active transaction. (A random number within 2^32 of the + highest 64-bit integer will work.) + + @param reply_type When should the local call return? The choices + are AWAIT_ARRIVAL, which returns after hearing + back from the coordinator, AWAIT_COMMIT_POINT to + wait until after the transaction commits/aborts, + AWAIT_RESULT, which waits for the actual result + from one of the replicas. + + @param key, key_size, value, value_size depend on the value of request_type. + + @return 1 on success, 0 on failure. +*/ + +int _chtEval(DfaSet * dfaSet, + unsigned char request_type, + unsigned char response_type, + state_machine_id * xid, + clusterHashTable_t * ht, + void * key, size_t * key_size, + void * value, size_t * value_size) { + + /* Fill out a message payload. */ + + Message m; + + if(ht != NULL) { + printf("_chtEval(request=%d, response=%d, xid=%ld, ht=%d ", request_type, response_type, *xid, ht->id); + } else { + printf("_chtEval(request=%d, response=%d, xid=%ld, ht=NULL ", request_type, response_type, *xid); + } + if(key == NULL) { + printf(")\n"); + } else { + printf("key=%d)\n", *(int*)key); + } + * requestType(&m) = request_type; + * responseType(&m) = response_type; + + setKeyLength(&m, *key_size); + setValLength(&m, *value_size); + + assert(checkPayload(&m)); + if(key_size != 0) { + memcpy(getKeyAddr(&m), key, *key_size); + } + if(value_size != 0) { + memcpy(getValAddr(&m), value, *value_size); + } + if(ht != NULL) { + memcpy(&(__header_ptr(&m)->hashTable), ht, sizeof(clusterHashTable_t)); + } + + /* printf("%s <- %s\n", __header_ptr(&m)->initiator, dfaSet->networkSetup.localhost); */ + + /* Synchronously run the request */ + request(dfaSet, response_type, "bc:0", *xid, &m); + + if(!checkPayload(&m)) { + printf("_chtEval failed: Invalid response.\n"); + assert(0); + } + + /* Copy message contents back into caller's buffers, even if the + request failed. (There may be app-specific information in the + response...) */ + + if(ht != NULL) { + memcpy(ht, &(__header_ptr(&m)->hashTable), sizeof(clusterHashTable_t)); + } + if (*key_size != 0) { + /* printf("\n+%x<-%x+, length %d value=%s and %s\n", (unsigned int) value, (unsigned int)getValAddr(&m), getValLength(&m), value, getValAddr(&m)); */ + memcpy(value, getValAddr(&m), getValLength(&m)); + } + if (*value_size != 0) { + memcpy(key, getKeyAddr(&m), getKeyLength(&m)); + } + + *xid = m.to_machine_id; + + printf("+chtEval returning %d\n", m.type); + + return m.type; +} + + +state_name init_xact_cht(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + + + TwoPCMachineState * state = (TwoPCMachineState*) &(stateMachine->app_state); + TwoPCAppState * app_state_2pc = ((TwoPCAppState*)(((DfaSet*)dfaSet)->app_setup)); + CHTAppState * app_state_cht = app_state_2pc->app_state; + + if(m->type != *responseType(m)) { + printf("Bug in client! m->type != response_type(m).\n"); + } + + if(*requestType(m) == CREATE) { + clusterHashTable_t new_cht; + new_cht.id = app_state_cht->next_hashTableId; + app_state_cht->next_hashTableId++; + + memcpy(&(__header_ptr(m)->hashTable), &new_cht, sizeof(clusterHashTable_t)); + + printf("Allocated hashtable %d\n", new_cht.id); + } + + printf("requestType: %d, responseType: %d key: %d from %s:%ld\n", *requestType(m), *responseType(m), *(int*)getKeyAddr(m), m->initiator, m->initiator_machine_id); + + if(*responseType(m) == AWAIT_ARRIVAL) { + state_machine_id tmp = m->from_machine_id; + + /* TODO: Could the chages to from_machine_id be moved into libdfa (it does this anyway, but it does it too late.) */ + m->from_machine_id = m->initiator_machine_id; /*stateMachine->machine_id;*/ + + printf("Responding\n"); + + respond_once(&((DfaSet*)dfaSet)->networkSetup, COORDINATOR_START_2PC, m, m->initiator); + + m->from_machine_id = tmp; + } + + return 1; +} + +callback_fcn abort_cht; + +/* Begins new transaction, does the work the transaction requests, stores the message, and returns the corresponding error code. */ +state_name veto_or_prepare_cht(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + + state_name ret; + setup_vars; + + if(xid_exists) { printf("Warning: Stale xid found!\n"); } + assert(!xid_exists); + printf("requestType: %d, responseType: %d key: %d from %s:%ld\n", *requestType(m), *responseType(m), *(int*)getKeyAddr(m), m->initiator, m->initiator_machine_id); + + /* This is the start of a new transaction */ + xid = Tbegin(); // !!!! + if(xid < 0) { + + printf("Tbegin failed; %d\n", xid); + + } else if(jbHtInsert(ht_xid, xid_ht, &(stateMachine->machine_id), sizeof(state_machine_id), &xid, sizeof(int)) == -1) { + + printf("jbHtInsert failed.\n"); + + } else { + + xid_exists = 1; + } + Tcommit(app_state_cht->ht_xid); + app_state_cht->ht_xid = Tbegin(); + + if(xid_exists) { + + ret = do_work(dfaSet, stateMachine, m, from); + + ret = ret ? SUBORDINATE_PREPARED_2PC : SUBORDINATE_VETO_2PC; + + } else { + + ret = SUBORDINATE_VETO_2PC; + + } + + if(ret == SUBORDINATE_VETO_2PC) { + abort_cht(dfaSet, stateMachine, m, from); + } + return ret; +} + +state_name abort_cht(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + setup_vars; + + printf("Aborting!!\n"); + + if(response_type == AWAIT_COMMIT_POINT || response_type == AWAIT_RESULT) { + state_machine_id tmp = m->from_machine_id; + + /* TODO: Could the chages to from_machine_id be moved into libdfa (it does this anyway, but it does it too late.) */ + m->from_machine_id = m->initiator_machine_id; /*stateMachine->machine_id;*/ + + printf("Response being sent to: %s:%ld\n", m->initiator, m->to_machine_id); + respond_once(&((DfaSet*)dfaSet)->networkSetup, SUBORDINATE_VETO_2PC, m, m->initiator); + m->from_machine_id = tmp; + } + + assert(xid_exists); + + Tabort(xid); // !!!! + jbHtRemove(ht_xid, xid_ht, &(stateMachine->machine_id), sizeof(state_machine_id), &xid); + Tcommit(app_state_cht->ht_xid); + app_state_cht->ht_xid = Tbegin(); + return 1; +} + +/** TODO For now, we ignore the possiblity that jbHashTable's functions + return error codes. Instead, we assume that they always + succeed. */ +state_name do_work(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + int ret; + setup_vars; + + /* printf("ht_ht = %x, ht = %x\n", ht_ht, ht); */ + + switch(request_type) + { + case CREATE: + { + jbHashTable_t * new = jbHtCreate(ht_xid, 79); + if(new != NULL) { + ret = (jbHtInsert(ht_xid, ht_ht, &(__header_ptr(m)->hashTable), sizeof(clusterHashTable_t), new, sizeof(jbHashTable_t)) >= 0); + } else { + ret = 0; + } + if(ret) { + printf("Created local slice of global hash table %d\n", (__header_ptr(m)->hashTable).id); + Tcommit(app_state_cht->ht_xid); + app_state_cht->ht_xid = Tbegin(); + } else { + printf("Failed to insert new hash table slice!"); + } + + } break; + + case INSERT: + { + if(!ht_exists) { printf ("Hash table %d doesn't exist!\n", (__header_ptr(m)->hashTable).id); fflush(NULL); ret = 0; } else { + ret = (jbHtInsert(xid, &ht, getKeyAddr(m), getKeyLength(m), getValAddr(m), getValLength(m)) >= 0); + printf("Insert: %d ht=%d (key length %d) %d -> %s\n", ret, (__header_ptr(m)->hashTable).id, getKeyLength(m), *(int*)getKeyAddr(m), getValAddr(m)); + (jbHtInsert(ht_xid, ht_ht, &(__header_ptr(m)->hashTable), sizeof(clusterHashTable_t), &ht, sizeof(jbHashTable_t))); + + } + } break; + + case LOOKUP: + { + if(!ht_exists) { printf ("Hash table doesn't exist!\n"); fflush(NULL); ret = 0; } else { + ret = (jbHtLookup(xid, &ht, getKeyAddr(m), getKeyLength(m), getValAddr(m)) >= 0); + printf("Lookup: %d ht=%d (key length %d) %d -> %s\n", ret, (__header_ptr(m)->hashTable).id, getKeyLength(m), *(int*)getKeyAddr(m), getValAddr(m)); + } + } break; + + case REMOVE: + { + if(!ht_exists) { printf ("Hash table doesn't exist!\n"); fflush(NULL); ret = 0; } else { + ret = (jbHtRemove(xid, &ht, getKeyAddr(m), getKeyLength(m), getValAddr(m)) >= 0); + (jbHtInsert(ht_xid, ht_ht, &(__header_ptr(m)->hashTable), sizeof(clusterHashTable_t), &ht, sizeof(jbHashTable_t))); + } + } break; + + case DELETE: + { + if(!ht_exists) { printf ("Hash table doesn't exist!\n"); fflush(NULL); ret = 0; } else { + jbHtRemove(xid, ht_ht, getKeyAddr(m), getKeyLength(m), NULL); + (jbHtInsert(ht_xid, ht_ht, &(__header_ptr(m)->hashTable), sizeof(clusterHashTable_t), &ht, sizeof(jbHashTable_t))); + /* ret = (jbHtDelete(xid, &ht) >= 0); */ /* Don't need this--jbHtDelete just frees the (stack!) pointer. */ + Tcommit(app_state_cht->ht_xid); + app_state_cht->ht_xid = Tbegin(); + + } + } break; + + case TSTSET: + { + printf("Unimplemented request!\n"); + } break; + + case GETXID: + { + /* int new_xid = Tbegin(); + if(new_xid >= 0) { + setKeyLength(m, 0); + setValLength(m, sizeof(int)); + *((int*)getValAddr(m)) = new_xid; + ret = 1; + if(jbHtInsert(ht_xid, xid_ht, &(stateMachine->machine_id), sizeof(state_machine_id), &xid, sizeof(int)) == -1) { + printf("Begin failed on jbHtInsert!\n"); + } else { + printf("Created local xid for global xid: %ld\n", stateMachine->machine_id); + } + } else { + printf("Begin failed on Tbegin()!\n"); + + ret = 0; + } NOOP */ + } break; + + /* case COMMIT: + { + ret = (Tcommit(xid) >= 0); + } break; + + case ABORT: + { + ret = (Tabort(xid) >= 0); + } break; + */ + default: + { + printf("Unknown request type: %d\n", request_type); + } + } + + return ret; +} + +state_name commit_cht(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + + setup_vars; + + assert(xid_exists); + Tcommit(xid); + jbHtRemove(ht_xid, xid_ht, &(stateMachine->machine_id), sizeof(state_machine_id), &xid); + Tcommit(app_state_cht->ht_xid); + app_state_cht->ht_xid = Tbegin(); + /* }*/ + + if(response_type == AWAIT_RESULT) { + printf("commit_cht responding on an AWAIT_RESULT request.\n"); + assert(0); + /* respond_once(&((DfaSet*)dfaSet)->networkSetup, SUBORDINATE_ACKING_2PC, m, __header_ptr(m)->initiator); */ + } + /* TODO: Check error codes, and return accordingly... */ + return 1; +} + +state_name tally_cht(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + + setup_vars; + + /* TODO: Make sure this is after tally forces the log. Also, need to + make sure that it increments the (currently unimplemented) + sequence number before flushing... */ + + if(response_type == AWAIT_COMMIT_POINT && stateMachine->current_state==COORDINATOR_START_2PC) { + state_machine_id tmp = m->from_machine_id; + + /* TODO: Could the chages to from_machine_id be moved into libdfa (it does this anyway, but it does it too late.) */ + m->from_machine_id = m->initiator_machine_id; /*stateMachine->machine_id;*/ + + printf("Coordinator responding: ? ht=? (key length %d) %d -> to %s:%ld\n", getKeyLength(m), *(int*)getKeyAddr(m), /*getValAddr(m),*/ m->initiator, m->initiator_machine_id ); + respond_once(&((DfaSet*)dfaSet)->networkSetup, COORDINATOR_COMMITTING_2PC, m, m->initiator); + + m->from_machine_id = tmp; + } + + return 1; +} + +DfaSet * cHtInit(int cht_type, char * localhost, + short (* get_broadcast_group)(DfaSet *, Message *), + short port, + char *** broadcast_lists, + int broadcast_lists_count, + int* broadcast_list_host_count) { + + DfaSet * dfaSet; + int xid = Tbegin(); + TwoPCAppState * twoPC_state; + CHTAppState * chtApp_state; + + int error; + + dfaSet = dfa_malloc(DFA_MACHINE_COUNT, port, broadcast_lists, broadcast_lists_count, broadcast_list_host_count); + + /* srand(time(NULL)); */ + + twoPC_state = calloc(1, sizeof(TwoPCAppState)); + chtApp_state = calloc(1, sizeof(CHTAppState)); + + if(cht_type == CHT_CLIENT) { + error = dfa_reinitialize(dfaSet, localhost, client_transitions_2pc, client_transition_count_2pc, states_2pc, state_count_2pc); + } else { + error = dfa_reinitialize(dfaSet, localhost, transitions_2pc, transition_count_2pc, states_2pc, state_count_2pc); + } + + if(error < 0) { + perror("dfa_reinitialize failed"); + return NULL; + } + + if(cht_type != CHT_CLIENT) { + chtApp_state->xid_ht = jbHtCreate(xid, 79); + chtApp_state->ht_ht = jbHtCreate(xid, 79); + chtApp_state->ht_xid = Tbegin(); // !!!! + chtApp_state->next_hashTableId = 0; /* This gets incremented each time a new hashtable is allocated. */ + + twoPC_state->is_coordinator = (cht_type == CHT_COORDINATOR); + twoPC_state->init_xact_2pc = init_xact_cht; + twoPC_state->veto_or_prepare_2pc = veto_or_prepare_cht; + twoPC_state->abort_2pc = abort_cht; + twoPC_state->commit_2pc = commit_cht; + twoPC_state->tally_2pc = tally_cht; + if(get_broadcast_group == NULL) get_broadcast_group = multiplex_interleaved; + twoPC_state->get_broadcast_group = get_broadcast_group; + twoPC_state->app_state_record_id = Talloc(xid, sizeof(CHTAppState)); + twoPC_state->app_state = chtApp_state; + + Tset(xid, twoPC_state->app_state_record_id, chtApp_state); + + dfaSet->app_setup = twoPC_state; + } + + Tcommit(xid); + + return dfaSet; +} + +int cHtCreate(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t * new_ht) { + size_t zero = 0; + return _chtEval(dfaSet, CREATE, AWAIT_COMMIT_POINT, &xid, new_ht, NULL, &zero, NULL, &zero) != SUBORDINATE_VETO_2PC; +} + + +int cHtInsert(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t * ht, void * key, size_t keylen, void * dat, size_t datlen) { + return _chtEval(dfaSet, INSERT, AWAIT_COMMIT_POINT, &xid, ht, key, &keylen, dat, &datlen) != SUBORDINATE_VETO_2PC; +} + +int cHtLookup(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t * ht, void * key, size_t keylen, void * dat, size_t * datlen) { + return _chtEval(dfaSet, LOOKUP, AWAIT_COMMIT_POINT, &xid, ht, key, &keylen, dat, datlen) != SUBORDINATE_VETO_2PC; +} + +int cHtRemove(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t * ht, void * key, size_t keylen, void * dat, size_t * datlen) { + return _chtEval(dfaSet, REMOVE, AWAIT_COMMIT_POINT, &xid, ht, key, &keylen, dat, datlen) != SUBORDINATE_VETO_2PC; +} + +int cHtDelete(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t *ht) { + size_t zero = 0; + return _chtEval(dfaSet, DELETE, AWAIT_COMMIT_POINT, &xid, ht, NULL, &zero, NULL, &zero) != SUBORDINATE_VETO_2PC; +} + +int cHtGetXid(state_machine_id* xid, DfaSet * dfaSet) { + size_t zero = 0; + *xid = NULL_MACHINE; /* Will be overwritten by + _chtEval... Need a large random + value so that the request will + be serviced exactly once, but + will not conflict with real + transactions or other begins.*/ + return _chtEval(dfaSet, GETXID, AWAIT_ARRIVAL, xid, NULL, NULL, &zero, NULL, &zero) != SUBORDINATE_VETO_2PC; +} + +/*int cHtCommit(state_machine_id xid, DfaSet * dfaSet) { + size_t zero = 0; + return _chtEval(dfaSet, COMMIT, AWAIT_COMMIT_POINT, &xid, NULL, NULL, &zero, NULL, &zero); +} + + +int cHtAbort(state_machine_id xid, DfaSet * dfaSet) { + size_t zero = 0; + return _chtEval(dfaSet, ABORT, AWAIT_COMMIT_POINT, &xid, NULL, NULL, &zero, NULL, &zero); + }*/ diff --git a/src/apps/cht/cht.h b/src/apps/cht/cht.h new file mode 100644 index 0000000..03368a6 --- /dev/null +++ b/src/apps/cht/cht.h @@ -0,0 +1,140 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#define CHT_COORDINATOR 1 +#define CHT_SERVER 2 +#define CHT_CLIENT 3 + + +typedef struct { + int id; +} clusterHashTable_t; + +/** + * jbHtCreate makes a new persistant hashtable + * @param xid transaction id + * @param dfaSet The state machine set that will be used to manage the cluster hash table. (TODO: Who initializes this?) + * @param new_ht a preallocated buffer to hold the new hash table. + * @return 1 on success, 0 on error.pointer to hashtable, or NULL on error + */ +int cHtCreate(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t * new_ht); + + +/** + * Insert a key/value pair + * makes a SHALLOW COPY of the data to keep in durable storage + * will REPLACE an existing entry with the same key + * @param xid transaction id + * @param ht hashtable in which to insert + * @param key pointer to data serving as key + * @param keylen how much data to use from pointer + * @param dat data to insert + * @param datlen length data + * @return -1 on error, 0 on success + */ +int cHtInsert(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t * ht, void * key, size_t keylen, void * dat, size_t datlen); + +/** + * Lookup a value with a key + * + * *TODO* This api is only safe becuase value lengths are bounded! + * Need to fix API, and implementation to support arbitrary length + * keys and values. + * + * + * @param xid transaction id + * @param ht hashtable in which to look + * @param key pointer to key data + * @param keylen length of key + * @param dat preallocated buffer in which to put data + * @param datlen overwritten with the size of the data that was read. + * @return -1 if error occurs, including nothing found + */ +int cHtLookup(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t *ht, void *key, size_t keylen, void *dat, size_t* datlen); + + +/** + * Delete entry associated with key + * @param xid transaction id + * @param ht hashtable in which to delete + * @param key pointer to key data + * @param keylen length of key + * @param buf if non-NULL, preallocated space to copy data from deleted key + * @return -1 on errors or not found, 0 if existing entry was deleted + */ +int cHtRemove( state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t *ht, void *key, size_t keylen, void *dat, size_t * datlen ); + +/** + * Delete a hashtable + * table must be empty + * @param xid transaction id + * @param ht hashtable to delete + * @return 0 on success, -1 on error + */ +int cHtDelete(state_machine_id xid, DfaSet * dfaSet, clusterHashTable_t *ht); + +/** + * Returns a new DfaSet that is ready to have main_loop() or + * request() called on it. Of course, the DfaSet implements a + * cluster hash table. ;) + * + * @param cht_type CHT_CLIENT, CHT_COORDINATOR, CHT_SUBORDINATE, + * depending on which portion of the CHT the dfa set should implement. + * + * @param get_broadcast_group A function that maps key values (from + * the messages key field) to broadcast groups. + * + * @see dfa_malloc for a description of the other parameters. + * + * + */ +DfaSet * cHtInit(int cht_type, char * localhost, + short (* get_broadcast_group)(DfaSet *, Message *), + short port, + char *** broadcast_lists, + int broadcast_lists_count, + int* broadcast_list_host_count); + +int cHtGetXid(state_machine_id* xid, DfaSet * dfaSet); +/*int cHtCommit(state_machine_id xid, DfaSet * dfaSet); + int cHtAbort(state_machine_id xid, DfaSet * dfaSet);*/ diff --git a/src/apps/cyrus/.deps/cyrusdb_lladd.Po b/src/apps/cyrus/.deps/cyrusdb_lladd.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/src/apps/cyrus/.deps/cyrusdb_lladd.Po @@ -0,0 +1 @@ +# dummy diff --git a/src/apps/cyrus/.deps/libcyrusdb_lladd.Po b/src/apps/cyrus/.deps/libcyrusdb_lladd.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/src/apps/cyrus/.deps/libcyrusdb_lladd.Po @@ -0,0 +1 @@ +# dummy diff --git a/src/apps/cyrus/Makefile b/src/apps/cyrus/Makefile new file mode 100644 index 0000000..2739e1f --- /dev/null +++ b/src/apps/cyrus/Makefile @@ -0,0 +1,371 @@ +# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = ../../.. + +prefix = /usr/local +exec_prefix = ${prefix} + +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 +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/hello +pkglibdir = $(libdir)/hello +pkgincludedir = $(includedir)/hello + +top_builddir = ../../.. + +ACLOCAL = aclocal-1.4 +AUTOCONF = autoconf +AUTOMAKE = automake-1.4 +AUTOHEADER = autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL} +transform = s,x,x, + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = +host_triplet = i686-pc-linux-gnu +AR = ar +AS = @AS@ +CC = gcc +CHECK_CFLAGS = +CHECK_LIBS = -lcheck +CPP = gcc -E +CXX = g++ +CXXCPP = g++ -E +DLLTOOL = @DLLTOOL@ +ECHO = echo +EGREP = grep -E +EXEEXT = +F77 = g77 +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +HAVE_LIB = @HAVE_LIB@ +LIB = @LIB@ +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LN_S = ln -s +LTLIB = @LTLIB@ +MAKEINFO = makeinfo +OBJDUMP = @OBJDUMP@ +OBJEXT = o +PACKAGE = hello +RANLIB = ranlib +RC = @RC@ +STRIP = strip +VERSION = 0.1 + +LDADD = $(top_builddir)/build/libdfa.a $(top_builddir)/build/lib2pc.a +SOURCES = cyrusdb_lladd.c +lib_LIBRARIES = libcyrusdb_lladd.a +libcyrusdb_lladd_a_SOURCES = cyrusdb_lladd.c +AM_CFLAGS = -g -Wall -pedantic +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../../[config.h] +CONFIG_CLEAN_FILES = +LIBRARIES = $(lib_LIBRARIES) + + +DEFS = -DHAVE_CONFIG_H -I. -I$(srcdir) -I../../.. +CPPFLAGS = +LDFLAGS = +LIBS = -lpthread +libcyrusdb_lladd_a_LIBADD = +libcyrusdb_lladd_a_OBJECTS = cyrusdb_lladd.$(OBJEXT) +CFLAGS = -g -O2 +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +DEP_FILES = .deps/cyrusdb_lladd.P +SOURCES = $(libcyrusdb_lladd_a_SOURCES) +OBJECTS = $(libcyrusdb_lladd_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .obj .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu src/apps/cyrus/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-libLIBRARIES: + +clean-libLIBRARIES: + -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) + +distclean-libLIBRARIES: + +maintainer-clean-libLIBRARIES: + +install-libLIBRARIES: $(lib_LIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libdir) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + @$(POST_INSTALL) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(RANLIB) $(DESTDIR)$(libdir)/$$p"; \ + $(RANLIB) $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + +uninstall-libLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(lib_LIBRARIES)'; for p in $$list; do \ + rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +# FIXME: We should only use cygpath when building on Windows, +# and only if it is available. +.c.obj: + $(COMPILE) -c `cygpath -w $<` + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libcyrusdb_lladd.a: $(libcyrusdb_lladd_a_OBJECTS) $(libcyrusdb_lladd_a_DEPENDENCIES) + -rm -f libcyrusdb_lladd.a + $(AR) cru libcyrusdb_lladd.a $(libcyrusdb_lladd_a_OBJECTS) $(libcyrusdb_lladd_a_LIBADD) + $(RANLIB) libcyrusdb_lladd.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags -o $$here/TAGS $(ETAGS_ARGS) $$tags $$unique $(LISP)) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = src/apps/cyrus + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/apps/cyrus/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-libLIBRARIES +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-libLIBRARIES +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(libdir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-libLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags mostlyclean-depend \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-libLIBRARIES clean-compile clean-libtool clean-tags \ + clean-depend clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-libLIBRARIES distclean-compile \ + distclean-libtool distclean-tags distclean-depend \ + distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-libLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-depend \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-libLIBRARIES distclean-libLIBRARIES \ +clean-libLIBRARIES maintainer-clean-libLIBRARIES uninstall-libLIBRARIES \ +install-libLIBRARIES mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile mostlyclean-libtool \ +distclean-libtool clean-libtool maintainer-clean-libtool tags \ +mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \ +distdir mostlyclean-depend distclean-depend clean-depend \ +maintainer-clean-depend info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/apps/cyrus/Makefile.am b/src/apps/cyrus/Makefile.am new file mode 100644 index 0000000..ff8172e --- /dev/null +++ b/src/apps/cyrus/Makefile.am @@ -0,0 +1,5 @@ +LDADD=$(top_builddir)/build/libdfa.a $(top_builddir)/build/lib2pc.a +SOURCES=cyrusdb_lladd.c +lib_LIBRARIES=libcyrusdb_lladd.a +libcyrusdb_lladd_a_SOURCES=cyrusdb_lladd.c +AM_CFLAGS= -g -Wall -pedantic diff --git a/src/apps/cyrus/cyrusdb_lladd.c b/src/apps/cyrus/cyrusdb_lladd.c new file mode 100644 index 0000000..3279c66 --- /dev/null +++ b/src/apps/cyrus/cyrusdb_lladd.c @@ -0,0 +1,492 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include +#include +#include "cyrusdb.h" +#include "exitcodes.h" +#include "string.h" +#include "xmalloc.h" + +#include +#include "../../pbl/jbhash.h" + + +struct db { + jbHashTable_t *nameSpace; +}; + +struct txn { + int tid; +}; + +static int dirExists(char *dir) +{ + char *curDir = getcwd(NULL, 0); + int status = chdir(dir); + chdir(curDir); + free(curDir); + return (status == 0); +} + +static char *dbdirName = 0; +static int dbinit = 0; +static void openNameSpace(const char *filename, jbHashTable_t ** nameHT); +static void writeNameSpace(const char *filename, jbHashTable_t * nameHT); + +/* + * init() should be called once per process; no calls are legal until init() returns + */ +static int init(const char *dbdir, int myflags) +{ + dbdirName = malloc(strlen(dbdir)); + strcpy(dbdirName, dbdir); + if (!dirExists(dbdirName)) + mkdir(dbdirName); + dbinit = 1; + return 0; +} + +/* + * done() should be called once per process; no calls are legal once done() starts. it is legal to call + * init() after done() returns to reset state + */ +static int done(void) +{ + free(dbdirName); + dbdirName = 0; + dbinit = 0; + return 0; +} + +/* checkpoints this database environment */ +static int mysync(void) +{ + return 0; /* no need to checkpoint */ +} + +/* + * archives this database environment, and specified databases into the specified directory + */ +static int archive(const char **fnames, const char *dirname) +{ + /* looks like this copies the db file and the log to a new directory */ + jbHashTable_t *oldHT, *newHT; + const char **list = fnames; + recordid loc; + static char archiveName[200]; + static char data[600]; /* max is 600 now! should be a better system for this... */ + static char curKey[80]; + int xid, status, datalen, keylen; + struct txn **trans; + if (list != NULL) { + while (*list != NULL) { + openNameSpace(*list, &oldHT); + if (oldHT != 0) { + syslog(LOG_ERR, "DBERROR: error archiving database file: %s", *list); + return CYRUSDB_IOERROR; + } + /* theoretically, can use foreach here */ + xid = Tbegin(); + newHT = jbHtCreate(xid); + strcpy(archiveName, "archive/"); + strcat(archiveName, *list); + writeNameSpace(archiveName,newHT); + for (datalen = jbHtFirst(xid, oldHT, data); datalen > 0; datalen = jbHtNext(xid, oldHT, data)) { + loc = Talloc(xid, datalen); + Tset(xid, loc, data); + keylen = jbHtCurrentKey(xid, oldHT, curKey); + jbHtInsert(xid, newHT, curKey, keylen, data, datalen); + } + Tcommit(xid); + free(newHT); + list++; + } + } + return 0; +} + +/* + * Pass in a filename and an unallocated hashtable, will return either a valid malloc'ed hashtable or null + * into nameHT + */ +static void openNameSpace(const char *filename, jbHashTable_t ** nameHT) +{ + int count; + FILE *fp = fopen(filename, "r"); + recordid rid; + if (fp != 0) { + *nameHT = xmalloc(sizeof(jbHashTable_t)); + for (count = 0; count < sizeof(recordid); count++) + *(char *)(&rid + count) = fgetc(fp); + fclose(fp); + Tread(69, rid, *nameHT); + if (!jbHtValid(69, *nameHT)) { + free(*nameHT); + *nameHT = NULL; /* not a valid hashtable, so return null */ + } + } else { /* file does not exist */ + fclose(fp); + *nameHT = NULL; + } +} + +static void writeNameSpace(const char *filename, jbHashTable_t * nameHT) +{ + int count; + FILE *fp = fopen(filename, "w"); + if (fp != 0) { + for (count = 0; count < sizeof(recordid); count++) + fputc(*(char *)(&nameHT->store+count), fp); + } +} + +/* open the specified database in the global environment */ +static int myopen(const char *fname, int flags, struct db ** ret) +{ + jbHashTable_t *nameHT; + static char filename[40]; + struct db *newdb = xmalloc(sizeof(struct db)); + int xid, i; + FILE *fp; + recordid rid; + assert(dbinit && fname && ret); + /* prepare the filename by concatenating the dbdir with the filename */ + strcpy(filename, dbdirName); + strcat(filename, "/"); + strncat(filename, fname, strlen(fname)); + + /* this is where you load the namespace for this db into memory */ + openNameSpace(filename, &nameHT); + if (nameHT != NULL) { + /* that means we found a valid hashtable in the filename */ + newdb->nameSpace = nameHT; + *ret = newdb; + return 0; + } + /* by this point */ + + + /* if we've reached here, that means the HT didn't exist */ + free(nameHT); /* get rid of the attempt to find the HT */ + /* make a xid just for the creation of the namespace hashtable */ + xid = Tbegin(); + newdb->nameSpace = jbHtCreate(xid); /* make a new nameSpace just for this database */ + rid = newdb->nameSpace->store; /* get the rid of this namespace to save to a file */ + fp = fopen(filename, "w"); + if (fp == 0) { + syslog(LOG_ERR, "DBERROR: opening %s for writing", filename); + return CYRUSDB_IOERROR; + } + for (i = 0; i < sizeof(recordid); i++) + fputc(*(char *)(&rid + i), fp); + fclose(fp); /* this flushes the location to disk */ + Tcommit(xid); /* commit the transaction only when the intermediate step of recording the + * location of it has been flushed to disk */ + /* + * note: this means it's possible to record an rid on disk without it actually being written there, + * so therefore check validity of HT next time + */ + *ret = newdb; + return 0; +} + +/* close the specified database */ +static int myclose(struct db * db) +{ + /* + * since there are transactions, no need to do anything to them now should be all committed by this + * point just deallocate the hashtable + */ + assert(dbinit && db); + free(db->nameSpace); + free(db); + return 0; +} + +/* what are the overall specifications? */ +/* + * 'mydb': the database to act on 'key': the key to fetch. cyrusdb currently requires this to not have any + * of [\t\n\0] in keys 'keylen': length of the key 'data': where to put the data (generally won't have + * [\n\0]) 'datalen': how big is the data? 'mytid': may be NULL, in which case the fetch is not txn + * protected. if mytid != NULL && *mytid == NULL, begins a new txn if mytid != NULL && *mytid != NULL, + * continues an old txn + * + * transactions may lock the entire database on some backends. beware + * + * fetchlock() is identical to fetch() except gives a hint to the underlying database that the key/data being + * fetched will be modified soon. it is useless to use fetchlock() without a non-NULL mytid + */ +static int fetch(struct db * mydb, + const char *key, int keylen, + const char **data, int *datalen, + struct txn ** mytid) +{ + recordid rid; + int xid, status; + assert(dbinit && mydb); + if (mytid != NULL && *mytid == NULL) { /* make a new transaction */ + /* begin a new transaction */ + *mytid = (struct txn *) xmalloc(sizeof(struct txn)); + (*mytid)->tid = Tbegin(); + xid = (*mytid)->tid; + } else if (mytid != NULL) { /* therefore *mytid!=NULL, continue an old txn */ + xid = (*mytid)->tid; + } else if (mytid == NULL) { + /* not transaction protected */ + xid = 69; + /* + * note, Tread shouldn't have xid needed, but it's there so put in junk xid + */ + } + /* get the record given the key */ + status = jbHtLookup(xid, mydb->nameSpace, key, keylen, &rid); + if (status == -1) { + /* invalid key! return error */ + Tabort(xid); + if (mytid && *mytid) + free(*mytid); + return -1; /* what is the return for an error? */ + } + Tread(xid, rid, *data); +} + +static int fetchlock(struct db * mydb, + const char *key, int keylen, + const char **data, int *datalen, + struct txn ** mytid) +{ + /* for now, the same as fetch */ + return fetch(mydb, key, keylen, data, datalen, mytid); +} + +/* + * foreach: iterate through entries that start with 'prefix' if 'p' returns true, call 'cb' + * + * if 'cb' changes the database, these changes will only be visible if they are after the current database + * cursor. If other processes change the database (i.e. outside of a transaction) these changes may or may + * not be visible to the foreach() + * + * 'p' should be fast and should avoid blocking it should be safe to call other db routines inside of 'cb'. + * however, the "flat" backend is currently are not reentrant in this way unless you're using transactions + * and pass the same transaction to all db calls during the life of foreach() + */ +static int foreach(struct db * mydb, + char *prefix, int prefixlen, + foreach_p * p, + foreach_cb * cb, void *rock, + struct txn ** tid) +{ + char data[600]; + char curKey[80]; + int datalen, keylen, xid, r; + if (tid && *tid) + xid = (*tid)->tid; + else + xid = 69; + assert(dbinit && mydb && cb); + for (datalen = jbHtFirst(xid, mydb->nameSpace, data); datalen > 0; datalen = jbHtNext(xid, mydb->nameSpace, data)) { + /* does this match our prefix? */ + keylen = jbHtCurrentKey(xid, mydb->nameSpace, curKey); + if (prefixlen && memcmp(curKey, prefix, prefixlen)) + continue; + /* else we have a match! */ + if (p(rock, curKey, keylen, data, datalen)) { + /* we have a winner! */ + r = cb(rock, curKey, keylen, data, datalen); + if (r != 0) { + if (r < 0) { + syslog(LOG_ERR, "DBERROR: foreach cb() failed"); + } + /* don't mistake this for a db error -- WHY?? */ + r = 0; + + break; + } + } + } +} + +/* + * mystore combines create and store and delete, flags: 0 = storing and nooverwrite 1 = storing and overwrite + * 2 = deleting + * + */ +static int mystore(struct db * db, + const char *key, int keylen, + const char *data, int datalen, + struct txn ** tid, int flags) +{ + int xid, status; + struct txn *newtxn; + recordid rid; + assert(dbinit && db && key && keylen); + /* check tid first!! if *mytid null, start a new transaction */ + if (!tid) { + /* create a new transaction with no intention of committing it (ever) */ + xid = Tbegin(); + } else if (!*tid) { + /* make a new transaction */ + newtxn = xmalloc(sizeof(struct txn)); + newtxn->tid = Tbegin(); + xid = newtxn->tid; + *tid = newtxn; + } else + xid = (*tid)->tid; /* transaction already exists */ + /* first see if a variable of this key exists */ + status = jbHtLookup(xid, db->nameSpace, key, keylen, &rid); + if (status == -1) { /* this variable doesn't exist yet */ + if (flags != 2) { /* only add variable if you aren't deleting it, duh */ + /* key doesn't exist, so make it and allocate space */ + rid = Talloc(xid, datalen); + jbHtInsert(xid, db->nameSpace, key, keylen, &rid, sizeof(recordid)); + } /* else if you are deleting this, nothing to do since variable never existed! + * yay! */ + } else { + /* key exists */ + switch (flags) { + case 0: + /* -- if no overwrite, return error */ + Tabort(xid); + if (tid && *tid) + free(*tid); + return -1; + break; + case 2: + /* delete: so remove it from namespace */ + jbHtRemove(xid, db->nameSpace, key, keylen, NULL); + break; + case 1: + break; + } + } + if (flags != 2) + Tset(xid, rid, data); + /* else Tdealloc(xid, rid); ** IS THERE A DEALLOC YET? ** */ + if (!tid) /* was a one time transaction, commit it */ + Tcommit(xid); +} + +/* + * Place entries in database create will not overwrite existing entries + */ +static int create(struct db * db, + const char *key, int keylen, + const char *data, int datalen, + struct txn ** tid) +{ + return mystore(db, key, keylen, data, datalen, tid, 0); /* no overwrite, not deleting */ + +} + +static int store(struct db * db, + const char *key, int keylen, + const char *data, int datalen, + struct txn ** tid) +{ + return mystore(db, key, keylen, data, datalen, tid, 1); /* overwrite, not deleting */ +} + +/* Remove entrys from the database */ +static int delete(struct db * db, + const char *key, int keylen, + struct txn ** tid, + int force) +{ /* 1 = ignore not found errors */ + return mystore(db, key, keylen, NULL, 0, tid, 2); /* overwrite (meaningless), deleting */ +} + +/* + * Commit the transaction. When commit() returns, the tid will no longer be valid, regardless of if the + * commit succeeded or failed + */ +static int mycommit(struct txn * tid) +{ + Tcommit(tid->tid); + assert(dbinit && tid); + free(tid); +} + +static int mycommit_db(struct db * db, struct txn * tid) +{ + return mycommit(tid); +} + +/* Abort the transaction and invalidate the tid */ +static int myabort(struct txn * tid) +{ + assert(dbinit && tid); + Tabort(tid->tid); + free(tid); +} + +static int myabort_db(struct db * db, struct txn * tid) +{ + return myabort(tid); +} + +struct cyrusdb_backend cyrusdb_lladd = +{ + "lladd", /* name */ + + &init, + &done, + &mysync, + &archive, + + &myopen, + &myclose, + + &fetch, + &fetchlock, + &foreach, + &create, + &store, + &delete, + + &mycommit_db, + &myabort_db, + + NULL, + NULL +}; diff --git a/src/libdfa/Makefile.am b/src/libdfa/Makefile.am new file mode 100644 index 0000000..25d704d --- /dev/null +++ b/src/libdfa/Makefile.am @@ -0,0 +1,4 @@ +#LDADD=$(top_builddir)/build/transactional.a $(top_builddir)/build/libpbl.a +lib_LIBRARIES=libdfa.a +libdfa_a_SOURCES=libdfa.c monotree.c smash.c rw.c callbacks.c messages.c +AM_CFLAGS= -g -Wall -pedantic -std=gnu99 diff --git a/src/libdfa/callbacks.c b/src/libdfa/callbacks.c new file mode 100644 index 0000000..ea319e8 --- /dev/null +++ b/src/libdfa/callbacks.c @@ -0,0 +1,88 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "callbacks.h" +#include "stdio.h" + +#define TRUE 1 +#define FALSE 0 + +state_name respond_once(NetworkSetup * ns, state_name type, Message * incoming_message, char * from) { + + state_machine_id id; + state_name original_type = incoming_message->type; + incoming_message->type = type; + id = incoming_message->to_machine_id; + incoming_message->to_machine_id = incoming_message->from_machine_id; + incoming_message->from_machine_id = id; + + send_message(ns, incoming_message, from); + + incoming_message->type = original_type; + id = incoming_message->to_machine_id; + incoming_message->to_machine_id = incoming_message->from_machine_id; + incoming_message->from_machine_id = id; + + return TRUE; + +} + +state_name tally(char ** broadcast_list, int host_count, char * bitSet, char * from) { + + int i; + int index; + + index= get_index(broadcast_list, host_count, from); + + if(index < 0) { + printf("Received message from unknown recipient: %s\n", from); + return FALSE; + } + bitSet[index] = TRUE; + + for(i = 0; i < host_count; i++) { + if(!bitSet[i]) { + return FALSE; + } + } + return TRUE; +} + diff --git a/src/libdfa/callbacks.h b/src/libdfa/callbacks.h new file mode 100644 index 0000000..308c859 --- /dev/null +++ b/src/libdfa/callbacks.h @@ -0,0 +1,75 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +/** + A covienence function that responds to an incoming message one + time. (Useful for sending ACK's, and then freeing a machine.) + @param ns The network setup that will be used to send the message. + @param type The 'local state' that the message should respond with + @param incoming_message The message that we're responding to. This can be a broadcast addess such as bc:1. + @param from The network address of that we're responding to. + @see NetworkSetup +*/ + +state_name respond_once(NetworkSetup * ns, state_name type, Message * incoming_message, char * from); +/** + A convienence function that keeps track of responses from multiple + machines. For example, this is used by two phase commit to count + PREPARED messages. + + @param broadcast_list An array of strings containing the addresses + of the remote machines. + + @param host_count The number of strings in broadcast_list + + @param bitSet An array of host_count characters, each initialized + to zero. (as in (unsigned char)0, not '0') The application should + manage this memory, and only initializes it when its time to start + a fresh tally. + + @param from The address of the remote machine we just recieved a + message from. + + @return 1 if all hosts have responded, 0 otherwise. +*/ +state_name tally(char ** broadcast_list, int host_count, char * bitSet, char * from); + diff --git a/src/libdfa/libdfa.c b/src/libdfa/libdfa.c new file mode 100644 index 0000000..e09210e --- /dev/null +++ b/src/libdfa/libdfa.c @@ -0,0 +1,765 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void * run_request(DfaSet * dfaSet, state_machine_id machine_id); + +typedef struct { + DfaSet * dfaSet; + const Transition * transitions; + int transition_count; + const State * states; + state_name state_count; + rwl* lock; +} main_wrap_args; + +void dfa_initialize_new(DfaSet * dfaSet, unsigned short port, int count) { + /*init_MonoTree(&(dfaSet->monoTree), count);*/ + Tinit(); + dfaSet->smash = init_Smash(count); + dfaSet->networkSetup.localport = port; +} + +void recover(DfaSet * dfaSet); + +/*void nothing(int signo) { + / + This space left intentionally blank. + / + }*/ + +int dfa_reinitialize(DfaSet *dfaSet, char * localhost, + Transition transitions[], int transition_count, + State states[], state_name state_count) { + +/* struct sigaction actions; + int rc;*/ + + + dfaSet->lock = initlock(); + dfaSet->states = states; + dfaSet->state_count = state_count; + dfaSet->transitions = transitions; + dfaSet->transition_count = transition_count; + + +/* memset(&actions, 0, sizeof(actions)); + sigemptyset(&actions.sa_mask); + actions.sa_flags = 0; + actions.sa_handler = nothing; + + rc = sigaction(SIGALRM,&actions,NULL); + if(rc < 0) { + perror("sigaction"); + return -1; + } +*/ + + if(init_network_broadcast(&(dfaSet->networkSetup), dfaSet->networkSetup.localport, localhost, + dfaSet->networkSetup.broadcast_lists, + dfaSet->networkSetup.broadcast_lists_count, + dfaSet->networkSetup.broadcast_list_host_count) < 0) { + return -1; + } + writelock(dfaSet->lock, 100); + recover(dfaSet); + writeunlock(dfaSet->lock); + + return 0; + +} + +/* Processes incoming events, and updates state machine states. */ + +typedef struct { + DfaSet *dfaSet; + state_machine_id machine_id; +} WorkerLoopArgs; + +void * worker_loop(void * worker_loop_args); +pthread_t spawn_worker_thread(DfaSet * dfaSet, state_machine_id machine_id); +pthread_t spawn_main_thread(DfaSet * dfaSet); + +void recover(DfaSet * dfaSet) { + /* int machine_count; + StateMachine* machines = enumerateMachines(&(dfaSet->monoTree), &machine_count); + int i; + for(i = 0; i < machine_count; i++) { + machines[i].worker_thread = spawn_worker_thread(dfaSet, machines[i].machine_id); + } */ + StateMachine sm_stack; + StateMachine * sm = &sm_stack; + StateMachine * this; + int ret = (jbHtFirst(dfaSet->smash->xid, dfaSet->smash->hash, sm) != -1); + + + while(ret) { + this = getSmash(dfaSet->smash, sm->machine_id); + printf("StateMachine %ld\n", sm->machine_id); + this->worker_thread = spawn_worker_thread(dfaSet, sm->machine_id); + ret = (jbHtNext(dfaSet->smash->xid, dfaSet->smash->hash, sm) != -1); + } + +} + +void* main_loop(DfaSet *dfaSet) { + + Message * message = malloc(sizeof(Message)); + char * from = malloc(sizeof(char) * MAX_ADDRESS_LENGTH); + NetworkSetup * networkSetup = malloc(sizeof(NetworkSetup)); + int recieved_message = 0; + + /* StateMachine stateMachine_stack; */ + StateMachine * stateMachine; /* = &stateMachine_stack; */ + + + writelock(dfaSet->lock, 300); + memcpy(networkSetup, &(dfaSet->networkSetup), sizeof(NetworkSetup)); + writeunlock(dfaSet->lock); + + while(1) { + int i; + state_name new_state, current_state; + /* int ret;*/ + int new_machine = 0; + + /*Listen on socket... */ + if(recieved_message) { + /* if(stateMachine != NULL) { + setSmash(dfaSet->smash, stateMachine->machine_id); + } */ + writeunlock(dfaSet->lock); + recieved_message = 0; + } + + if(receive_message(networkSetup, message, from) <= 0) { + continue; + } + + recieved_message = 1; + + /* The commented out, more complex locking scheme does not work, + because freeMachine (called by worker threads) invalidates + stateMachine pointers, so this loop really needs a global + write lock. */ + /* readlock(dfaSet->lock, 200); */ + + writelock(dfaSet->lock, 200); + + stateMachine = getSmash(dfaSet->smash, message->to_machine_id); + /* printf("Lookup %ld, ret = %d\n", message->to_machine_id, ret); */ + /* stateMachine = getMachine(&(dfaSet->monoTree), message->to_machine_id); */ + /* if(stateMachine != NULL) { + / * Grab the lock now. * / + pthread_mutex_lock(&(stateMachine->mutex)); + } */ + + /* This is the only thread that can write to the monoTree, so we + don't need to worry that someone else will create the + stateMachine, so we can safely release all locks if the + stateMachine was null, and not worry about race conditions. */ + + /* readunlock(dfaSet->lock); */ + + /* TODO: Check states to make sure they actually exist? */ + + if(stateMachine == NULL) { + + /*writelock(dfaSet->lock, 600);*/ + + printf("Allocate machine %ld->", message->to_machine_id); fflush(NULL); + + if(message->to_machine_id == NULL_MACHINE) { + + stateMachine = allocSmash(dfaSet->smash); + + /*stateMachine = allocMachine(&(dfaSet->monoTree));*/ + + } else { + + /* TODO: Check id. */ + /*stateMachine = insertMachine(&(dfaSet->monoTree), message->to_machine_id); */ + + stateMachine = insertSmash(dfaSet->smash, message->to_machine_id); + } + + if(stateMachine == NULL) { + + + /*writeunlock(dfaSet->lock);*/ + + printf("Too many state machines. Dropping request for new one.\n"); + continue; + + } else { + /* printf("machine->id:%ld\n", stateMachine->machine_id); */ + } + + new_machine = 1; + + + /* Done with monotree for now. */ + + /* Grab a write lock on our machine before releasing the global + write lock, so that its worker thread doesn't get a hold of + it. */ + + /*pthread_mutex_lock(&(stateMachine->mutex));*/ + + /*writeunlock(dfaSet->lock);*/ + + stateMachine->worker_thread = (pid_t)NULL; + + stateMachine->page = NULL; + stateMachine->page_id.page = 0; /* TODO: Is there such a thing as a null page?? */ + stateMachine->page_id.slot = 0; + stateMachine->page_id.size = 0; + + current_state = NULL_STATE; + } else { + current_state = stateMachine->current_state; + } + + /* At this point, we hold stateMachine->mutex and no other locks. */ + + new_state = current_state; + + /* Find the appropriate transition */ + + assert(message->to_machine_id == stateMachine->machine_id || message->to_machine_id == NULL_MACHINE); + + for(i = 0; i< dfaSet->transition_count; i++) { + if(dfaSet->transitions[i].remote_state == message->type && + dfaSet->transitions[i].pre_state == current_state) { + + break; + } + } + + if(i == dfaSet->transition_count) { + + printf("%ld received: %ld-%d:%d->? (bad message)\n", stateMachine->machine_id, message->from_machine_id, + message->type, current_state); + /*pthread_mutex_unlock(&(stateMachine->mutex));*/ + continue; + + } + + + if(dfaSet->transitions[i].fcn_ptr == NULL) { + + new_state = dfaSet->transitions[i].post_state; + + } else { + + /* Evaluate callback -- This produces a new state, and + overwrites m with a new message for the state machine. */ + + int ret = (dfaSet->transitions[i].fcn_ptr)(dfaSet, stateMachine, message, from); + + if (dfaSet->transitions[i].post_state == OVERRIDDEN_STATE) { + if( ret != OVERRIDDEN_STATE) { + + new_state = ret; + + } /* else leave new_state alone; the transition failed. */ + } else if (ret) { + + new_state = dfaSet->transitions[i].post_state; + + } + + } + + + /* Update machine state. */ + + if(new_state == NULL_STATE) { + + /* Time to de-allocate machine */ + + if(stateMachine->worker_thread == (pid_t)NULL) { + + /* No worker thread, so just deallocate, and move on */ + /* Note, that at this point, we hold the mutex on the state machine, and the global write lock. */ + /*writelock(dfaSet->lock,500); + pthread_mutex_unlock(&(stateMachine->mutex));*/ + + /*freeMachine(&(dfaSet->monoTree), + stateMachine->machine_id); */ + freeSmash(dfaSet->smash, stateMachine->machine_id); + + /*writeunlock(dfaSet->lock);*/ + continue; + } else { + + /* NULL_STATE_TOMBSTONE tells the worker thread that it's + time to shut down. (NULL_STATE is reserved by monoTree + for machines that have already been deleted..) */ + + new_state = NULL_STATE_TOMBSTONE; + } + assert(!new_machine); + } + + if(new_state != current_state) { + + printf("%ld transitioned on: %ld-%d:%d->%d from %s\n", stateMachine->machine_id, message->from_machine_id, + dfaSet->transitions[i].remote_state, dfaSet->transitions[i].pre_state, dfaSet->transitions[i].post_state, from); + printf(" -> %d %ld\n", new_state, message->from_machine_id); + + assert(new_state != NULL_STATE); + stateMachine->current_state = new_state; + stateMachine->last_transition = time(NULL); + + /* TODO: Is this general enough? The transition function is + able to overwrite both variables, so it should be + good enough. */ + + memcpy(&(stateMachine->message_recipient), from, MAX_ADDRESS_LENGTH); + memcpy(&(stateMachine->message), message, sizeof(Message)); + + /* We don't want to just swap the sender and recipient, + since we might have just allocated this machine. If not, + then the original message's recipient should be the + same as stateMachine->machine_id anyway. + + At any rate, the transition function should overwrite + message->from_machine_id to change the machine that the + state machine will deal with. + + */ + + stateMachine->message.from_machine_id = stateMachine->machine_id; + stateMachine->message.to_machine_id = message->from_machine_id; + + /* TODO: Force if necessary.*/ + + if(dfaSet->transitions[i].force) { + setSmash(dfaSet->smash, stateMachine->machine_id); + forceSmash(dfaSet->smash); + } + + /*stateMachine->pending++; */ + + /* setSmash(dfaSet->smash, stateMachine->machine_id); */ + + + /* Fork or signal the process if there already is one. */ + + if(stateMachine->worker_thread == (pthread_t)NULL) { + /* assert (getMachine(&(dfaSet->monoTree), stateMachine->machine_id) == stateMachine); */ + assert ((stateMachine->current_state != NULL_STATE) && + (stateMachine->current_state != NULL_STATE_TOMBSTONE)); + + stateMachine->worker_thread = spawn_worker_thread(dfaSet, stateMachine->machine_id); + + } else { + /* pthread_cond_t * cond; + pthread_cond_t cond_copy; + + pthread_kill (stateMachine->worker_thread, SIGALRM); + pthread_cond_signal (&(stateMachine->sleepCond)); */ + /* printf("Waking worker...\n"); */ + + /* memcpy(&cond_copy, &(stateMachine->sleepCond), sizeof(pthread_cond_t)); */ + + pthread_cond_broadcast (stateMachine->sleepCond); /* TODO: Signal should be adequate.. */ + } + } + /* setSmash(dfaSet->smash, stateMachine->machine_id); */ + + } +} + +void * inner_worker_loop(void * arg_void) { + + WorkerLoopArgs * arg = arg_void; + /* int ret; */ + DfaSet * dfaSet = arg->dfaSet; + const state_machine_id machine_id = arg->machine_id; + /* pthread_cond_t cond_copy; + pthread_mutex_t mutex_copy; */ + + int timeout = 0; /* Run through the loop immediately the first time around. */ + int state = 0; + /* int tries = 0; */ + /* StateMachine stateMachine_stack; */ + StateMachine* stateMachine; /* = &stateMachine_stack; */ + + + free(arg_void); + + readlock(dfaSet->lock, machine_id); + + + + stateMachine = getSmash(dfaSet->smash, machine_id); + + + /* stateMachine = getMachine(&(dfaSet->monoTree), machine_id); */ + /* assert(stateMachine != NULL); */ + /* assert(ret); */ + + /* memcpy(&mutex_copy, &(stateMachine->mutex), sizeof(pthread_mutex_t)); + memcpy(&cond_copy, &(stateMachine->sleepCond), sizeof(pthread_cond_t)); */ + + pthread_mutex_lock(stateMachine->mutex); + + while(1) { + int rc = 0; + + state_name i, state_idx; + + /** SIGALRM will make sleep return immediately (I hope!)*/ + + /* printf("pending: %ld, %d\n", stateMachine->machine_id, stateMachine->pending); */ + + if(1|| !stateMachine->pending) { /* If no pending messages, go to sleep */ + struct timeval now; + struct timespec timeout_spec; + + pthread_cond_t * cond; + pthread_mutex_t * mutex; + + long usec; + + cond = stateMachine->sleepCond; + mutex = stateMachine->mutex; + + /* setSmash(dfaSet->smash, stateMachine); */ /* No longer write to stateMacine in this loop..Well + , we do, but we can safely lose that change. */ + readunlock(dfaSet->lock); + + /* A note on locking: This loop maintains a read lock everywhere + except for this call to sleep, and upon termination when it + requires a write lock. */ + + gettimeofday(&now, NULL); + + + + usec = now.tv_usec + timeout; + + if(usec > 1000000) { + now.tv_sec++; + usec-=1000000; + } + timeout_spec.tv_sec = now.tv_sec;/* + timeout; */ + timeout_spec.tv_nsec = 1000 * usec; /*now.tv_usec * 1000; */ + + + rc = pthread_cond_timedwait (cond, mutex, &timeout_spec ); + + /* rc = sleep(timeout); */ + + + if(rc == EINVAL) { + perror("pthread"); + } /*else if (rc != ETIMEDOUT) { + printf("Worker signaled.\n"); + } else { + printf("Timed out.\n"); + }*/ + readlock(dfaSet->lock, machine_id); + + /* Some other thread may have invalidated our pointer while we + were sleeping witout a lock... no longer true, *but* since + our pointer is local to this thread, we still need to re-read + from the store.*/ + + /*stateMachine = getMachine(&(dfaSet->monoTree), machine_id);*/ + assert(stateMachine == getSmash(dfaSet->smash, machine_id)); + } + + /* stateMachine = getMachine(&(dfaSet->monoTree), machine_id); */ + /* This can't happen! */ + /* assert(ret); */ + /* assert(stateMachine != NULL); */ + + /* pthread_mutex_lock(&(stateMachine->mutex)); */ + + /* if(stateMachine->pending > 0) { + + if(stateMachine->pending > 0) { + stateMachine->pending--; + } + assert (stateMachine->pending >= 0); + + }*/ + /* pthread_mutex_unlock(&(stateMachine->mutex)); */ + + /* printf("Current State: %d, %d\n", stateMachine->current_state, NULL_STATE_TOMBSTONE); */ + if(stateMachine->current_state == NULL_STATE_TOMBSTONE) { + /* printf("Breaking\n"); */ + break; + } + state = stateMachine->current_state; + stateMachine->message.type = stateMachine->current_state; + timeout = 690000 +(int) (300000.0*rand()/(RAND_MAX+1.0)); + /* timeout = 1; */ + for(i = 0; i < dfaSet->state_count; i++) { + if(dfaSet->states[i].name == stateMachine->current_state) { + state_idx = i; + } + } + + /* if(dfaSet->states[stateMachine->current_state].abort_fcn && (time(NULL) - stateMachine->last_transition > 100)) { + if(dfaSet->states[state_idx].abort_fcn && (time(NULL) - stateMachine->last_transition > 100)) { + ((callback_fcn*)dfaSet->states[state_idx].abort_fcn)(dfaSet, stateMachine, &(stateMachine->message), NULL); + freeMachine(&(dfaSet->monoTree), machine_id); + break; + } + / * if((time(NULL) - stateMachine->last_transition > abort_timeout) && abort_fcn!=NULL) { + abort_fcn(dfaSet, stateMachine, &(stateMachine->message), NULL); * / + }*/ + + /* TODO: Copy this stuff into buffers w/ memcopy, unlock, then call send_message. */ + + /* printf("Worker loop for state machine: %ld still active\n", machine_id); */ + + send_message(&(dfaSet->networkSetup), &(stateMachine->message), stateMachine->message_recipient); + + } + + setSmash(dfaSet->smash, stateMachine->machine_id); + + pthread_mutex_unlock(stateMachine->mutex); + + readunlock(dfaSet->lock); + + + return 0; +} + +void * worker_loop(void * arg_void) { + + WorkerLoopArgs * arg = arg_void; + /* StateMachine stateMachine_stack; */ + StateMachine * stateMachine; /* = &stateMachine_stack; */ + DfaSet * dfaSet = arg->dfaSet; + state_machine_id machine_id = arg->machine_id; + + readlock(dfaSet->lock, machine_id); + + /* printf("Worker loop: %ld\n", machine_id); */ + + stateMachine = getSmash(dfaSet->smash, machine_id); + + /* stateMachine = getMachine(&(dfaSet->monoTree), machine_id); */ + /* assert(stateMachine != NULL); */ + assert(stateMachine->machine_id == machine_id); + + /* pthread_detach gets angry if the current process recieves a + signal. How to handle this properly? Can the main thread + wait until this thread detaches successfully? (Do we need a lock somewhere?) */ + if(pthread_detach(stateMachine->worker_thread) != 0) { + perror("pthread_detach"); + } + + readunlock(dfaSet->lock); + inner_worker_loop(arg_void); + + /* fflush(NULL); */ + + writelock(dfaSet->lock, machine_id); + printf("Freeing machine %ld\n", machine_id); + + /* pthread_mutex_lock(&(stateMachine->mutex)); */ + /*freeMachine(&(dfaSet->monoTree), machine_id); */ + freeSmash(dfaSet->smash, machine_id); + /* pthread_mutex_unlock(&(stateMachine->mutex)); */ + writeunlock(dfaSet->lock); + + + return 0; +} + +pthread_t spawn_main_thread(DfaSet * dfaSet) { + pthread_t worker_thread; + int ret; + + ret = pthread_create(&worker_thread, NULL, (void*(*)(void*))&main_loop, dfaSet); + + if(ret != 0) { + perror("libdfa: pthread_create:"); + fflush(NULL); + } + + + return worker_thread; +} + +pthread_t spawn_worker_thread(DfaSet * dfaSet, state_machine_id machine_id) { + + /* Do we need to malloc a new worker_loop_args for each thread? + TODO: Should this be freed? Is it already? + */ + pthread_t worker_thread; + int ret; + + WorkerLoopArgs ** worker_loop_args = malloc(sizeof(WorkerLoopArgs*)); + + + *worker_loop_args = malloc(sizeof(WorkerLoopArgs)); + + + printf("spawn_worker_thread(state_machine_id=%ld)\n", machine_id); + + (*worker_loop_args)->dfaSet = dfaSet; + (*worker_loop_args)->machine_id = machine_id; + + ret = pthread_create(&worker_thread, NULL, &worker_loop, *worker_loop_args); + + if(ret != 0) { + perror("libdfa: pthread_create:"); + worker_thread = (pthread_t)NULL; + fflush(NULL); + } + + return worker_thread; +} + +void * request(DfaSet * dfaSet, state_name start_state, char * recipient_addr, state_machine_id recipient_machine_id, Message * message) { + /* StateMachine initial_sm_stack; */ + StateMachine * initial_sm; /* = &initial_sm_stack; */ + state_machine_id machine_id; + int ret; + writelock(dfaSet->lock, 600); + + + /* initial_sm = allocMachine(&(dfaSet->monoTree)); */ + initial_sm = allocSmash(dfaSet->smash); + if(initial_sm == NULL) { + return NULL; + } + /* if(!ret) { + return NULL; + } */ + assert(start_state != NULL_STATE); + + if(message != NULL) { + + memcpy(&(initial_sm->message), message, sizeof(Message)); + } + + initial_sm->current_state = start_state; + initial_sm->message.from_machine_id = initial_sm->machine_id; + initial_sm->message.to_machine_id = recipient_machine_id; + initial_sm->message.type = start_state; + + strcpy(initial_sm->message.initiator, dfaSet->networkSetup.localhost); + initial_sm->message.initiator_machine_id = initial_sm->machine_id; + + strcpy(initial_sm->message_recipient, recipient_addr); + machine_id = initial_sm->machine_id; + /* setSmash(dfaSet->smash, initial_sm->machine_id); */ + writeunlock(dfaSet->lock); + + ret = (int)run_request(dfaSet, machine_id); + + + writelock(dfaSet->lock, machine_id); + assert(initial_sm == getSmash(dfaSet->smash, machine_id)); + if(message != NULL) { + + memcpy(message, &(initial_sm->message), sizeof(Message)); + } + + /* freeMachine(&(dfaSet->monoTree), initial_sm->machine_id); */ + freeSmash(dfaSet->smash, initial_sm->machine_id); + writeunlock(dfaSet->lock); + + return (void*)ret; +} + +void * run_request(DfaSet * dfaSet, state_machine_id machine_id) { + void * ret; + WorkerLoopArgs * worker_loop_args = malloc(sizeof(WorkerLoopArgs)); + /* StateMachine machine_stack; */ + StateMachine * machine; /* = &machine_stack; */ + + readlock(dfaSet->lock, 600); + + machine = getSmash(dfaSet->smash, machine_id); + /* machine= getMachine(&(dfaSet->monoTree), machine_id); */ + + worker_loop_args->dfaSet = dfaSet; + worker_loop_args->machine_id = machine_id; + + machine->worker_thread = pthread_self(); + /* setSmash(dfaSet->smash, machine->machine_id); */ + readunlock(dfaSet->lock); + + + ret = inner_worker_loop(worker_loop_args); + + return (void*)ret; + +} + +DfaSet * dfa_malloc(int count, short port, + char *** broadcast_lists, + int broadcast_lists_count, + int * broadcast_list_host_count) { + DfaSet * dfaSet = calloc(1, sizeof(DfaSet)); + /* dfaSet->monoTree.buffer = calloc(count, sizeof(StateMachine)); */ + dfa_initialize_new(dfaSet, port, count); + + dfaSet->networkSetup.broadcast_lists = broadcast_lists; + dfaSet->networkSetup.broadcast_lists_count = broadcast_lists_count; + dfaSet->networkSetup.broadcast_list_host_count = broadcast_list_host_count; + + return dfaSet; +} + diff --git a/src/libdfa/messages.c b/src/libdfa/messages.c new file mode 100644 index 0000000..ddb74de --- /dev/null +++ b/src/libdfa/messages.c @@ -0,0 +1,318 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +char * parse_addr(const char * address) { + char * strtok_buf = NULL; + char * addr_copy = strdup(address); + char * addr_s; + + if(addr_copy == NULL) { + perror("Out of memory in send_message"); + } + + addr_s = strtok_r(addr_copy, ":", &strtok_buf); + + if(addr_s == NULL) { + printf("Invalid address (%s) passed into parse_addr", address); + return NULL; + } + + /* The caller needs to call free on the pointer we return. That's the same pointer as addr_copy. */ + + /* addr_copy = strdup(addr_copy); */ + /* free(addr_copy); */ + + assert(addr_copy == addr_s); + + return addr_s; +} + +short parse_port(const char * address) { + char * strtok_buf = NULL; + char * addr_copy = strdup(address); + short port; + char * port_s; + + if(addr_copy == NULL) { + perror("Out of memory in send_message"); + } + + + /* This sets port_s to addr. The next copy returns the port */ + port_s = strtok_r(addr_copy, ":", &strtok_buf); + + if(port_s == NULL) { + printf("Invalid address (%s) passed into parse_port", address); + assert(0); + return -1; + } + + port_s = strtok_r(NULL, ":", &strtok_buf); + + if(port_s == NULL) { + printf("Invalid address (%s) passed into parse_port", address); + assert(0); + return -1; + } + + port = atoi(port_s); + free(addr_copy); + + return port; +} + +/* code to establish a socket; originally from bzs@bu-cs.bu.edu */ + +int establish(unsigned short portnum) { + /* char myname[HOST_NAME_MAX+1]; */ + int s; + + struct sockaddr_in sa; + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = INADDR_ANY; + + sa.sin_port= htons(portnum); /* this is our port number */ + + if ((s= socket(AF_INET, SOCK_DGRAM, 0)) < 0) { /* create socket */ + perror("establish:socket()"); + return(-1); + } + + /* bind address to socket */ + + if (bind(s,(struct sockaddr *)&sa,sizeof(struct sockaddr_in)) < 0) { + perror("establish:bind()"); + close(s); + return(-1); + } + + listen(s, 5); /* max # of queued connects */ + return(s); +} + + +int init_network(NetworkSetup * ns, unsigned short portnum) { + return init_network_broadcast(ns, portnum, NULL, NULL, 0, NULL); +} +int init_network_broadcast(NetworkSetup * ns, unsigned short portnum, char * localhost, char *** broadcast_lists, + int broadcast_lists_count, int * broadcast_list_host_count) { + + ns->localport = portnum; + ns->localhost = localhost; + ns->broadcast_lists = broadcast_lists; + ns->broadcast_lists_count = broadcast_lists_count; + ns->broadcast_list_host_count = broadcast_list_host_count; + + return (ns->socket = establish(portnum)); + +} +int __send_message(const NetworkSetup *ns, Message *message, const char *to) ; + +int send_message(const NetworkSetup *ns, Message *message, const char *to) { + + return __send_message(ns, message, to); +} +int _send_message(const NetworkSetup *ns, Message *message, const char *to); + + +int __send_message(const NetworkSetup *ns, Message *message, const char *to) { + + + printf("Sending %ld-%d: to %s:%ld\n", message->from_machine_id, message->type ,to, message->to_machine_id); + + if(strncmp(to, "bc:", 3)==0) { + + int i; + int list_number = parse_port(to); + + if(list_number < 0 || list_number >= ns->broadcast_lists_count) { + printf("Invalid list number %d passed into send_message: %s\n", list_number, to); + return -1; + } + if(ns->broadcast_list_host_count[list_number] == 0) { + printf("Sending to empty broadcast list! Address was %s\n", to); + } + for(i =0; i < ns->broadcast_list_host_count[list_number]; i++) { + int ret; + if((ret = __send_message(ns, message, ns->broadcast_lists[list_number][i])) < 0) { + return ret; + } + } + } else { + return _send_message(ns, message, to); + } + return 0; +} + +int _send_message(const NetworkSetup *ns, Message *message, const char *to) { + int ret; + char *addr; + short port; + int err; + + /* TODO: Right size? */ + struct sockaddr_in * to_sa = malloc(sizeof(struct sockaddr_in)); + + + to_sa->sin_family = AF_INET; + + addr = parse_addr(to); + port = parse_port(to); + + if(addr == NULL) { + printf("Send failed. Could not parse addr.\n"); + return -1; + } + + if(port == -1) { + printf("Send failed. Could not parse port.\n"); + free(addr); + return -1; + } + to_sa->sin_port = htons(port); + err=inet_aton(addr, &(to_sa->sin_addr)); + + if(err == 0) { + perror("inet_aton"); + free(addr); + return -1; + } + + free(addr); + message->to_machine_id = htonl(message->to_machine_id); + message->from_machine_id = htonl(message->from_machine_id); + + ret = sendto(ns->socket, message, sizeof(Message), 0, (struct sockaddr*)to_sa, sizeof(struct sockaddr_in)); + + message->to_machine_id = ntohl(message->to_machine_id); + message->from_machine_id = ntohl(message->from_machine_id); + + if(ret < 0) { + perror("send_message"); + } + if(ret != sizeof(Message)) { + printf("send_message sent partial message!\n"); + + return -1; + } + return ret; +} + +/** Synchronously get a UDP packet. Blocks. @return 1 on success, 0 + * on corrupted packet / timeout, < 0 on network erro. + * + * @param from A char array of length MAX_ADDRESS_LENGTH+1 that will + * be clobbered and set to a null terminated string. + */ +/*int recieve_message(NetworkSetup *ns, Message *m, struct sockaddr_in *from, socklen_t fromlen) { */ +int receive_message(NetworkSetup *ns, Message *message, char *from) { + size_t max_len = sizeof(Message); + /* int flags = MSG_TRUNC ; */ + int flags = 0 ; + ssize_t message_size ; + struct sockaddr_in from_sockaddr; + socklen_t from_len = sizeof(struct sockaddr_in); + char portstr[6]; + bzero(&from_sockaddr, sizeof(struct sockaddr_in)); + + /* printf("recv'ing\n"); + fflush(NULL); */ + /* FIXME! */ + /* message_size = sizeof(Message); */ + message_size = recvfrom(ns->socket, message, max_len, flags, + (struct sockaddr*)&from_sockaddr, &from_len); + if(message_size < 0) { + perror("recvfrom"); + fflush(NULL); + assert(0); + } + /* printf("recv'ed\n"); + fflush(NULL); */ + + /* TODO: Check error fields from recvfrom */ + + /* Fix the state machine number... */ + message->to_machine_id = ntohl(message->to_machine_id); + message->from_machine_id = ntohl(message->from_machine_id); + + /* Fill out the address string. */ + + strcpy(from, inet_ntoa((from_sockaddr).sin_addr)); + strcat(from, ":"); + sprintf(portstr, "%d", ntohs((from_sockaddr).sin_port)); + strcat(from, portstr); + + if(message_size != sizeof(Message)) { + /* drop packet */ + printf("Size mismatch: %d, %d\n", message_size, sizeof(Message)); + return 0; + } else { + /* TODO: Callback to security stuff / crypto here? */ + return 1; + } + +} + +int get_index(char ** table, int table_length, const char *address) { + int i; + + for(i = 0; i < table_length; i++) { + if(0 == strcmp(table[i], address)) { + return i; + } + } + return -1; +} diff --git a/src/libdfa/monotree.c b/src/libdfa/monotree.c new file mode 100644 index 0000000..bce5849 --- /dev/null +++ b/src/libdfa/monotree.c @@ -0,0 +1,354 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "monotree.h" +#include +#include +#include +#include +#include +#define EPOCH ((time_t)0) + +int getMachineIndex(MonoTree * rb, state_machine_id id); +void compactBuffer(MonoTree * rb); +/** + Called when a new MonoTree is initialized (NOT after recovery.) + + This code takes a pointer to a MonoTree as an argument, since the + MonoTree should be allocated elsewhere (by the transactional + layer). +*/ + +void initStateMachine(StateMachine * stateMachine) { + + stateMachine->machine_id = ULONG_MAX; + stateMachine->last_transition = EPOCH; + stateMachine->page = NULL; + /* stateMachine->page_id; */ + stateMachine->current_state = NULL_STATE; + stateMachine->pending = 0; + + /* Intentionally does not free mutexes. */ +} + +void init_MonoTree(MonoTree * rb, int size) { + int i; + + for(i = 0; i < size; i++) { + StateMachine * stateMachine = &(rb->buffer[i]); + initStateMachine(stateMachine); + + + } + rb->size = size; + rb->low_water_mark = 0; + rb->high_water_mark = 0; + rb->next_id = 0; +} + +StateMachine * allocMachine(MonoTree * rb/*, state_machine_id id*/) { + + StateMachine * new; + + if(rb->high_water_mark >= rb->size) { + compactBuffer(rb); + } + if(rb->high_water_mark >= rb->size) { + return (StateMachine *)0; + } + new = &(rb->buffer[rb->high_water_mark]); + rb->high_water_mark++; + new->machine_id = rb->next_id; + new->mutex = malloc(sizeof(pthread_mutex_t)); + new->sleepCond = malloc(sizeof(pthread_cond_t)); + + pthread_mutex_init(new->mutex, NULL); + pthread_cond_init(new->sleepCond, NULL); + + rb->next_id++; + new->current_state = START_STATE; + + return new; +} + +StateMachine * insertMachine(MonoTree * rb, state_machine_id id) { + int new_index; + StateMachine * new; + int insertion_point; + /* allocMachine is much less expensive than insertMachine, so this + check is probably worth the trouble + + I don't understand why, but this optimization was causing 2pc to + fail, so I commented it out. + + -Rusty. + */ + /* if(id == rb->next_id) { + return allocMachine(rb); + } */ + if(rb->high_water_mark >= rb->size) { + compactBuffer(rb); + } + if(rb->high_water_mark >= rb->size) { + return (StateMachine *)0; + } + /* Look up the new machine */ + + new_index = getMachineIndex(rb, id); + + if(new_index < 0) { + insertion_point = -(1+new_index); + memmove(&(rb->buffer[insertion_point+1]), + &(rb->buffer[insertion_point]), + sizeof(StateMachine) * (rb->high_water_mark - insertion_point)); + rb->high_water_mark++; + } else { + if(rb->buffer[new_index].current_state == NULL_STATE) { + insertion_point = new_index; + } else { + return 0; + } + } + + new = &(rb->buffer[insertion_point]); + new->machine_id = id; + new->current_state = START_STATE; + new->mutex = malloc(sizeof(pthread_mutex_t)); + new->sleepCond = malloc(sizeof(pthread_cond_t)); + pthread_mutex_init(new->mutex, NULL); + pthread_cond_init(new->sleepCond, NULL); + + return new; + +} + + +void freeMachine(MonoTree * rb, state_machine_id id) { + StateMachine * stateMachine; + int old_index = getMachineIndex(rb, id); + + /* Needed for optimization to garbage collector. */ + + if (old_index < rb->low_water_mark) { + rb->low_water_mark = old_index; + } + + stateMachine = &(rb->buffer[old_index]); + + /* If either of these fail, then there's a bug above this line, + or someone attempted to free a machine that doesn't exist (anymore?). */ + + assert(stateMachine->machine_id == id); + assert(stateMachine->current_state != NULL_STATE); + + /* Leave the machine's id intact for now so that it can be used for binary search. */ + stateMachine->current_state = NULL_STATE; + + /* Needed so that alloc_machine can be correctly implemented. */ + + if ((old_index + 1) == rb->high_water_mark) { + rb->high_water_mark--; + /* Since we're at the end of the array, we can do this. */ + stateMachine->machine_id = ULONG_MAX; + } + pthread_mutex_destroy(stateMachine->mutex); + pthread_cond_destroy(stateMachine->sleepCond); + free(stateMachine->mutex); + free(stateMachine->sleepCond); + + + /* The application is responsible for the memory management for page, so don't touch that either. */ +} + +StateMachine * getMachine(MonoTree * rb, state_machine_id id) { + int index = getMachineIndex(rb, id); + StateMachine * stateMachine; + if(index < 0) { + return 0; + } + stateMachine = &(rb->buffer[index]); + if (stateMachine->current_state == NULL_STATE) { + return 0; + } + assert(stateMachine->machine_id==id); + + return stateMachine; +} + +StateMachine * enumerateMachines(MonoTree * rb, int* count) { + compactBuffer(rb); + + *count = rb->high_water_mark; + + return rb->buffer; +} + +/*----------- PRIVATE FUNCTIONS ----------*/ + +/* Return the highest possible machine id if binary search + * falls off the end of the array. + */ +state_machine_id getMachineID(MonoTree * rb, int index) { + if(index >= rb->size) { + return ULONG_MAX; + } else { + return rb->buffer[index].machine_id; + } +} + +int __round_size_up_last_in = -1; +int __round_size_up_last_out = -1; + +/* Find the smallest power of 2 greater than orig_size. */ +int round_size_up(int orig_size) { + int power_of_two = 0; + + int size = orig_size-1; + + if(orig_size == __round_size_up_last_in) { + return __round_size_up_last_out; + } + + + assert(orig_size >= 0); + + if(orig_size == 0) { + return 0; + } + + /* What is the first power of two > size? */ + while(size != 0) { + size /= 2; + power_of_two++; + } + + size = 1 << power_of_two; + __round_size_up_last_in = orig_size; + __round_size_up_last_out = size; + + return (int) size; + +} + +/** + Thanks to the spec of Java's Arrays.binarySearch() for this one. ;) + + This code doesn't check to see if the index that it returns is the + correct one, or even that it contains a real machine, or even that + it's less than the size of rb's buffer. + +*/ + +int getMachineIndex(MonoTree * rb, state_machine_id id) { + + int size = round_size_up(rb->size); + + int start = 0; + int stop = size; + int index; + state_machine_id index_id; + + while(stop - start > 1) { + assert(((start+stop) % 2) == 0); + index = (start + stop) / 2; + index_id = getMachineID(rb, index); + + if(index_id == id) { + start = index; + break; + } else if(index_id < id) { + start = index; + } else { + stop = index; + } + + + } + if(id == getMachineID(rb, start)) { + return start; + } else if(id == getMachineID(rb, stop)) { + return stop; + } else { + int insertionPoint; + int startID = getMachineID(rb,start); + int stopID = getMachineID(rb,stop); + if(id < startID) { + insertionPoint = start; + assert(start == 0 || getMachineID(rb, start-1) < id); + } else if(id < stopID) { + insertionPoint = stop; + } else { + assert(id < getMachineID(rb, stop+1)); + insertionPoint = stop+1; + } + return (-(insertionPoint) - 1); + } + +} + +void compactBuffer(MonoTree * rb) { + + int i; + int buffer_pos = 0; + int new_buffer_count = rb->high_water_mark-rb->low_water_mark; + size_t new_buffer_size = sizeof(StateMachine)*new_buffer_count; + StateMachine * new_buffer; + int number_of_machines = rb->low_water_mark; + if(rb->high_water_mark == rb->low_water_mark) { + return; + } + + new_buffer = malloc(new_buffer_size); + for(i = rb->low_water_mark; i < rb->high_water_mark; i++) { + if(rb->buffer[i].current_state != NULL_STATE) { + memcpy(&(new_buffer[buffer_pos]), &(rb->buffer[i]), sizeof(StateMachine)); + buffer_pos++; + number_of_machines++; + } + } + for(i = buffer_pos; i < new_buffer_count; i++) { + initStateMachine(&(new_buffer[i])); + } + memcpy(&(rb->buffer[rb->low_water_mark]), new_buffer, new_buffer_size); + free(new_buffer); + rb->low_water_mark = rb->high_water_mark = number_of_machines; + return; +} diff --git a/src/libdfa/monotree.h b/src/libdfa/monotree.h new file mode 100644 index 0000000..b06ccc6 --- /dev/null +++ b/src/libdfa/monotree.h @@ -0,0 +1,92 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#ifndef _MONOTREE_H +#define _MONOTREE_H +/** + Provides a binary tree that provides constant time insertion, but + only accepts monotonically increasing values. It's stored in an + array, and periodically compacts itself with a little garbage + collector. Even though items must be inserted in sorted order, but + can be removed in an arbitrary order. + + This data structure is hardcoded to operate on StateMachine + structs, but could be easily generalized with a small performance + hit. + + This library should be stable. + + TODO: If you pass NULL_STATE (ULONG_MAX) into any of these functions, the + result is undefined. This libary should check this instead of + causing arbitrary memory corruption. +*/ + +#include +#include + +typedef struct monoTree { + StateMachine * buffer; + int size; + int low_water_mark; + int high_water_mark; + state_machine_id next_id; +} MonoTree; + +/** + Usage: + + rb = malloc (sizeof(MonoTree)); + rb->buffer = malloc(sizeof(StateMachine) * rb_size); + + init_MonoTree(rb, rb_size); + +*/ +void init_MonoTree(MonoTree * rb, int size); +/** + Returns a pointer to a new machine, or null if the + buffer is full. +*/ +StateMachine * allocMachine (MonoTree * rb); +void freeMachine (MonoTree * rb, state_machine_id id); +StateMachine * getMachine (MonoTree * rb, state_machine_id id); +StateMachine * insertMachine(MonoTree * rb, state_machine_id id); +StateMachine * enumerateMachines(MonoTree * rb, int * count); +#endif diff --git a/src/libdfa/rw.c b/src/libdfa/rw.c new file mode 100644 index 0000000..003aab8 --- /dev/null +++ b/src/libdfa/rw.c @@ -0,0 +1,157 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +rwl *initlock (void) +{ + rwl *lock; + + lock = (rwl *)malloc (sizeof (rwl)); + if (lock == NULL) return (NULL); + lock->mut = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t)); + if (lock->mut == NULL) { free (lock); return (NULL); } + lock->writeOK = + (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (lock->writeOK == NULL) { free (lock->mut); free (lock); + return (NULL); } + lock->readOK = + (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (lock->writeOK == NULL) { free (lock->mut); free (lock->writeOK); + free (lock); return (NULL); } + + pthread_mutex_init (lock->mut, NULL); + pthread_cond_init (lock->writeOK, NULL); + pthread_cond_init (lock->readOK, NULL); + lock->readers = 0; + lock->writers = 0; + lock->waiting = 0; + + return (lock); +} + +/*void readlock(rwl *lock, int d) { + writelock(lock, d); + }*/ + +void readlock (rwl *lock, int d) +{ + /* printf("reader %d\n", d); */ + fflush(NULL); + + pthread_mutex_lock (lock->mut); + if (lock->writers || lock->waiting) { + do { + /* printf ("reader %d blocked. %d readers, %d writers, %d waiting\n", d, lock->readers, lock->writers, lock->waiting); */ + pthread_cond_wait (lock->readOK, lock->mut); + /* printf ("reader %d unblocked.\n", d); */ + } while (lock->writers); + } + lock->readers++; + pthread_mutex_unlock (lock->mut); + /* printf("reader %d done\n", d); */ + fflush(NULL); + + return; +} + +void writelock (rwl *lock, int d) +{ + /* printf("\nwritelock %d\n", d); */ + fflush(NULL); + pthread_mutex_lock (lock->mut); + lock->waiting++; + while (lock->readers || lock->writers) { + /* printf ("writer %d blocked. %d readers, %d writers, %d waiting\n", d, lock->readers, lock->writers, lock->waiting); */ + pthread_cond_wait (lock->writeOK, lock->mut); + /* printf ("writer %d unblocked.\n", d); */ + } + lock->waiting--; + lock->writers++; + pthread_mutex_unlock (lock->mut); + + /* printf("\nwritelock %d done\n", d); */ + fflush(NULL); + + return; +} + +/*void readunlock(rwl *lock) { + writeunlock(lock); + }*/ + +void readunlock (rwl *lock) +{ + pthread_mutex_lock (lock->mut); + lock->readers--; + pthread_cond_signal (lock->writeOK); + + /* Don't need to broadcast, since only one writer can run at + once. */ + + /* pthread_cond_broadcast (lock->writeOK); */ + + pthread_mutex_unlock (lock->mut); + /* printf("readunlock done\n"); */ +} + +void writeunlock (rwl *lock) +{ + /* printf("writeunlock done\n"); */ + fflush(NULL); + + pthread_mutex_lock (lock->mut); + lock->writers--; + /* Need this as well (in case there's another writer, which is blocking the all of the readers. */ + pthread_cond_signal (lock->writeOK); + pthread_cond_broadcast (lock->readOK); + pthread_mutex_unlock (lock->mut); +} + +void deletelock (rwl *lock) +{ + pthread_mutex_destroy (lock->mut); + pthread_cond_destroy (lock->readOK); + pthread_cond_destroy (lock->writeOK); + free (lock); + + return; +} diff --git a/src/libdfa/smash.c b/src/libdfa/smash.c new file mode 100644 index 0000000..125188e --- /dev/null +++ b/src/libdfa/smash.c @@ -0,0 +1,226 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include + +smash_t * init_Smash(int size) { + int xid = Tbegin(); + recordid store = Talloc(xid, sizeof(smash_t)); + smash_t * ret = calloc(1, sizeof(smash_t)); + + ret->size = size; + ret->contents = 0; + ret->next_sm_id = 0; + ret->store = store; + ret->hash = jbHtCreate(xid, 3499); + ret->xid = xid; + ret->lock = malloc(sizeof(pthread_mutex_t)); + ret->memHash = pblHtCreate(); + + pthread_mutex_init(ret->lock, NULL); + + Tset(xid, ret->store, ret); + + + + return ret; +} + + +void * _getSmash (smash_t * smash, state_machine_id id) { + /*extern void * pblHtLookup ( pblHashTable_t * h, void * key, size_t keylen );*/ + return pblHtLookup ( smash->memHash, &(id), sizeof(state_machine_id)); + /* return (-1 != jbHtLookup(smash->xid, smash->hash, &(id), sizeof(state_machine_id), machine)); */ +} + +StateMachine * _insertSmash(smash_t * smash, state_machine_id id) { + int ret; + + StateMachine * new; + + if(smash->contents+1 == smash->size) { + return NULL; + } + + smash->contents++; + new = malloc(sizeof (StateMachine)); + new->machine_id = id; + new->mutex = malloc(sizeof(pthread_mutex_t)); + new->sleepCond = malloc(sizeof(pthread_cond_t)); + new->pending = 0; + pthread_mutex_init(new->mutex, NULL); + pthread_cond_init(new->sleepCond, NULL); + + new->current_state = START_STATE; + /* printf("Insert %ld\n", id); */ + ret = (-1 != jbHtInsert(smash->xid, smash->hash, &id, sizeof(state_machine_id), new, sizeof(StateMachine))); + pblHtInsert(smash->memHash, &id, sizeof(state_machine_id), new); + /* Tcommit(smash->xid); + smash->xid = Tbegin(); */ + + return new; +} + + + +/** @return -1 on error, 0 if there isn't any more room, and 1 on success. */ +StateMachine * allocSmash (smash_t * smash) { + void * ret; + + pthread_mutex_lock(smash->lock); + + /* Make sure we don't clobber an existing state machine... */ + /* while(jbHtLookup(smash->xid, smash->hash, &(smash->next_sm_id), sizeof(state_machine_id), &junk) != -1) { + smash->next_sm_id++; + }*/ + + while(_getSmash(smash, smash->next_sm_id) != NULL) { + smash->next_sm_id++; + } + + /* printf("Alloc %ld\n", smash->next_sm_id); */ + + ret = _insertSmash(smash, smash->next_sm_id); + smash->next_sm_id++; + pthread_mutex_unlock(smash->lock); + + return ret; +} + + +/** @return -1 on error, 0 if there isn't any more room, and 1 on success. */ +StateMachine * insertSmash(smash_t * smash, state_machine_id id) { + void * ret; + StateMachine junk; + + pthread_mutex_lock(smash->lock); + + + if(jbHtLookup(smash->xid, smash->hash, &(smash->next_sm_id), sizeof(state_machine_id), &junk) != -1) { + pthread_mutex_unlock(smash->lock); + return NULL; + } + + ret= _insertSmash(smash, id); + pthread_mutex_unlock(smash->lock); + return ret; +} + +/** @return -1 on error, 0 if there isn't any more room, and 1 on success. */ +int freeSmash (smash_t * smash, state_machine_id id) { + StateMachine * old = getSmash(smash, id); + int ret; + pthread_mutex_lock(smash->lock); + + if(old == NULL) { + /* Bogus state machine id?? */ + + assert(0); + + } + + + smash->contents--; + pthread_mutex_destroy(old->mutex); + pthread_cond_destroy(old->sleepCond); + free(old->mutex); + free(old->sleepCond); + + pblHtRemove(smash->memHash, &(id), sizeof(state_machine_id)); + ret = jbHtRemove(smash->xid, smash->hash, &(id), sizeof(state_machine_id), NULL) != -1; + + free(old); + + /* Tcommit(smash->xid); + smash->xid = Tbegin();*/ + pthread_mutex_unlock(smash->lock); + return ret; + +} + + +void * getSmash (smash_t * smash, state_machine_id id) { + void * ret; + /* printf("Get smash: %ld\n", id); */ + + pthread_mutex_lock(smash->lock); + ret = _getSmash(smash, id); + pthread_mutex_unlock(smash->lock); + + return ret; +} + +int _setSmash(smash_t * smash, state_machine_id id) { + + StateMachine * machine; + machine = _getSmash(smash, id); + return (-1 != jbHtInsert(smash->xid, smash->hash, &id, sizeof(state_machine_id), machine, sizeof(StateMachine))); + +} + + +int setSmash (smash_t * smash, state_machine_id id) { + int ret; + /* printf("Set smash: %ld\n", machine->machine_id); */ + pthread_mutex_lock(smash->lock); + + ret = _setSmash(smash, id); + + pthread_mutex_unlock(smash->lock); + + return ret; +} + +int forceSmash (smash_t * smash) { + int ret; + + pthread_mutex_lock(smash->lock); + + Tcommit(smash->xid); + ret = (-1 != (smash->xid = Tbegin())); + + pthread_mutex_unlock(smash->lock); + + return ret; + +} diff --git a/src/lladd/1 b/src/lladd/1 new file mode 100644 index 0000000..891488e --- /dev/null +++ b/src/lladd/1 @@ -0,0 +1,4 @@ +Splint 3.1.1 --- 23 Apr 2004 + +2: +less: diff --git a/src/lladd/Makefile.am b/src/lladd/Makefile.am new file mode 100644 index 0000000..e3107e7 --- /dev/null +++ b/src/lladd/Makefile.am @@ -0,0 +1,8 @@ +#SUBDIRS=operations logger +#LDADD=$(top_builddir)/src/pbl/libpbl.a +lib_LIBRARIES=liblladd.a +#liblladd_a_LIBADD=logger/liblogger.a operations/liboperations.a +# removed: recovery.c transactional.c logger.c logger/logparser.c logger/logstreamer.c +liblladd_a_SOURCES=bufferManager.c linkedlist.c operations.c page.c recovery2.c transactional2.c logger/logEntry.c logger/logWriter.c logger/logHandle.c logger/logger2.c operations/decrement.c operations/increment.c operations/lladdhash.c operations/prepare.c operations/set.c operations/alloc.c +AM_CFLAGS= -g -Wall -pedantic -std=gnu99 + diff --git a/src/lladd/bufferManager.c b/src/lladd/bufferManager.c new file mode 100644 index 0000000..dc2a9a3 --- /dev/null +++ b/src/lladd/bufferManager.c @@ -0,0 +1,439 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/******************************* + * $Id$ + * + * implementation of the page buffer + * *************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +static pblHashTable_t *activePages; /* page lookup */ +static unsigned int bufferSize = 1; /* < MAX_BUFFER_SIZE */ +static Page *repHead, *repMiddle, *repTail; /* replacement policy */ + +static int stable = -1; +int blobfd0 = -1; +int blobfd1 = -1; + +static void pageMap(Page *ret) { + + int fileSize; + /* this was lseek(stable, SEEK_SET, pageid*PAGE_SIZE), but changed to + lseek(stable, pageid*PAGE_SIZE, SEEK_SET) by jkit (Wed Mar 24 12:59:18 PST 2004)*/ + fileSize = lseek(stable, 0, SEEK_END); + + if ((ret->id)*PAGE_SIZE >= fileSize) { + lseek(stable, (1 + ret->id)*PAGE_SIZE -1 , SEEK_SET); + write(stable, "", 1); + } + + if((ret->memAddr = mmap((void *) 0, PAGE_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, stable, (ret->id)*PAGE_SIZE)) == (void*)-1) { + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } +} + +int bufInit() { + + Page *first; + + bufferSize = 1; + stable = -1; + blobfd0 = -1; + blobfd1 = -1; + + + /* Create STORE_FILE, BLOB0_FILE, BLOB1_FILE if necessary, + then open it read/write + + If we're creating it, then put one all-zero record at the beginning of it. + (Need to have at least one record in the PAGE file?) + + It used to be that there was one file per page, and LSN needed to be set to -1. + + Now, zero means uninitialized, so this could probably be replaced + with a call to open(... O_CREAT|O_RW) or something like that... + */ + if( (stable = open(STORE_FILE, O_RDWR, 0)) == -1 ) { /* file may not exist */ + void *zero = mmap(0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); /* zero = /dev/zero */ + if( (stable = creat(STORE_FILE, 0666)) == -1 ) { /* cannot even create it */ + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + /* kick off a fresh page */ + if( write(stable, zero, PAGE_SIZE) != PAGE_SIZE ) { /* write zeros out */ + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + if( close(stable) || ((stable = open(STORE_FILE, O_RDWR, 0)) == -1) ) { /* need to reopen with read perms */ + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + } + + activePages = pblHtCreate(); + assert(activePages); + + first = pageAlloc(0); + pblHtInsert(activePages, &first->id, sizeof(int), first); + + first->prev = first->next = NULL; + pageMap(first); + + repHead = repTail = first; + repMiddle = NULL; + if( (blobfd0 = open(BLOB0_FILE, O_RDWR, 0)) == -1 ) { /* file may not exist */ + if( (blobfd0 = creat(BLOB0_FILE, 0666)) == -1 ) { /* cannot even create it */ + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + if( close(blobfd0) || ((blobfd0 = open(BLOB0_FILE, O_RDWR, 0)) == -1) ) { /* need to reopen with read perms */ + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + } + if( (blobfd1 = open(BLOB1_FILE, O_RDWR, 0)) == -1 ) { /* file may not exist */ + if( (blobfd1 = creat(BLOB1_FILE, 0666)) == -1 ) { /* cannot even create it */ + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + if( close(blobfd1) || ((blobfd1 = open(BLOB1_FILE, O_RDWR, 0)) == -1) ) { /* need to reopen with read perms */ + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + } + + return 0; +} + +static void headInsert(Page *ret) { + + assert(ret != repMiddle); + assert(ret != repTail); + assert(ret != repHead); + + repHead->prev = ret; + ret->next = repHead; + ret->prev = NULL; + repHead = ret; +} + +static void middleInsert(Page *ret) { + + assert( bufferSize == MAX_BUFFER_SIZE ); + + assert(ret != repMiddle); + assert(ret != repTail); + assert(ret != repHead); + + ret->prev = repMiddle->prev; + ret->next = repMiddle; + repMiddle->prev = ret; + ret->prev->next = ret; + ret->queue = 2; + + repMiddle = ret; + assert(ret->next != ret && ret->prev != ret); +} + +static void qRemove(Page *ret) { + + assert( bufferSize == MAX_BUFFER_SIZE ); + assert(ret->next != ret && ret->prev != ret); + + if( ret->prev ) + ret->prev->next = ret->next; + else /* is head */ + repHead = ret->next; /* won't have head == tail because of test in loadPage */ + if( ret->next ) { + ret->next->prev = ret->prev; + /* TODO: these if can be better organizeed for speed */ + if( ret == repMiddle ) + /* select new middle */ + repMiddle = ret->next; + } + else /* is tail */ + repTail = ret->prev; + + assert(ret != repMiddle); + assert(ret != repTail); + assert(ret != repHead); +} + +static Page *kickPage(int pageid) { + /* LRU-2S from Markatos "On Caching Searching Engine Results" */ + Page *ret = repTail; + + assert( bufferSize == MAX_BUFFER_SIZE ); + + qRemove(ret); + pblHtRemove(activePages, &ret->id, sizeof(int)); + if( munmap(ret->memAddr, PAGE_SIZE) ) + assert( 0 ); + + pageRealloc(ret, pageid); + + middleInsert(ret); + pblHtInsert(activePages, &pageid, sizeof(int), ret); + + return ret; +} + + +int lastPageId = -1; +Page * lastPage = 0; + +static Page *loadPagePtr(int pageid) { + /* lock activePages, bufferSize */ + Page *ret; + + if(lastPage && lastPageId == pageid) { + return lastPage; + } else { + ret = pblHtLookup(activePages, &pageid, sizeof(int)); + } + + if( ret ) { + if( bufferSize == MAX_BUFFER_SIZE ) { /* we need to worry about page sorting */ + /* move to head */ + if( ret != repHead ) { + qRemove(ret); + headInsert(ret); + assert(ret->next != ret && ret->prev != ret); + + if( ret->queue == 2 ) { + /* keep first queue same size */ + repMiddle = repMiddle->prev; + repMiddle->queue = 2; + + ret->queue = 1; + } + } + } + + lastPage = ret; + lastPageId = pageid; + + return ret; + } else if( bufferSize == MAX_BUFFER_SIZE ) { /* we need to kick */ + ret = kickPage(pageid); + } else if( bufferSize == MAX_BUFFER_SIZE-1 ) { /* we need to setup kickPage mechanism */ + int i; + Page *iter; + + ret = pageAlloc(pageid); + headInsert(ret); + assert(ret->next != ret && ret->prev != ret); + + pblHtInsert( activePages, &pageid, sizeof(int), ret ); + + bufferSize++; + + /* split up queue: + * "in all cases studied ... fixing the primary region to 30% ... + * resulted in the best performance" + */ + repMiddle = repHead; + for( i = 0; i < MAX_BUFFER_SIZE / 3; i++ ) { + repMiddle->queue = 1; + repMiddle = repMiddle->next; + } + + for( iter = repMiddle; iter; iter = iter->next ) { + iter->queue = 2; + } + + } else { /* we are adding to an nonfull queue */ + + bufferSize++; + + ret = pageAlloc(pageid); + headInsert(ret); + assert(ret->next != ret && ret->prev != ret); + assert(ret->next != ret && ret->prev != ret); + pblHtInsert( activePages, &pageid, sizeof(int), ret ); + } + + /* we now have a page we can dump info into */ + assert( ret->id == pageid ); + + pageMap(ret); + + lastPage = ret; + lastPageId = pageid; + + return ret; +} + +Page loadPage (int pageid) { + return *loadPagePtr(pageid); +} + +/*int lastGoodPageKey = 0; */ + +Page * lastRallocPage = 0; + +recordid ralloc(int xid, size_t size) { + static unsigned int lastFreepage = 0; + Page p; + int blobSize = 0; + + if (size >= BLOB_THRESHOLD_SIZE) { /* TODO combine this with if below */ + blobSize = size; + size = BLOB_REC_SIZE; + } + + while(freespace(p = loadPage(lastFreepage)) < size ) { lastFreepage++; } + + if (blobSize >= BLOB_THRESHOLD_SIZE) { + int fileSize = (int) lseek(blobfd1, 0 , SEEK_END); + /* fstat(blobfd1, &sb); + fileSize = (int) sb.st_size; */ + lseek(blobfd0, fileSize+blobSize-1, SEEK_SET); + write(blobfd0, "", 1); + lseek(blobfd1, fileSize+blobSize-1, SEEK_SET); + write(blobfd1, "", 1); + + return pageBalloc(p, blobSize, fileSize); + } else { + return pageRalloc(p, size); + } + +} +long readLSN(int pageid) { + + return pageReadLSN(loadPage(pageid)); +} + +void writeLSN(long LSN, int pageid) { + Page *p = loadPagePtr(pageid); + p->LSN = LSN; + pageWriteLSN(*p); +} +void writeRecord(int xid, recordid rid, const void *dat) { + + Page *p = loadPagePtr(rid.page); + assert( (p->id == rid.page) && (p->memAddr != NULL) ); + + pageWriteRecord(xid, *p, rid, dat); /* Used to attempt to return this. */ +} +void readRecord(int xid, recordid rid, void *buf) { + pageReadRecord(xid, loadPage(rid.page), rid, buf); /* Used to attempt to return this. */ +} + +int flushPage(Page page) { + + if( munmap(page.memAddr, PAGE_SIZE) ) + return MEM_WRITE_ERROR; + + return 0; +} + +int bufTransCommit(int xid) { + + fdatasync(blobfd0); + fdatasync(blobfd1); + + pageCommit(xid); + + return 0; +} + +int bufTransAbort(int xid) { + + pageAbort(xid); + + return 0; +} + +void bufDeinit() { + int ret; + Page *p; + + for( p = (Page*)pblHtFirst( activePages ); p; p = (Page*)pblHtRemove( activePages, 0, 0 )) { + if( p->dirty && (ret = flushPage(*p))) { + printf("ERROR: flushPage on %s line %d", __FILE__, __LINE__); + exit(ret); + } + /* free(p); */ + } + pblHtDelete(activePages); + + if( close(stable) ) { + printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__); + exit(errno); + } + + close(blobfd0); + close(blobfd1); + + return; +} +/** + Just close file descriptors, don't do any other clean up. (For + testing.) +*/ +void simulateBufferManagerCrash() { + close(blobfd0); + close(blobfd1); + close(stable); + blobfd0 = -1; + blobfd1 = -1; + stable = -1; + + +} diff --git a/src/lladd/linkedlist.c b/src/lladd/linkedlist.c new file mode 100644 index 0000000..6afa927 --- /dev/null +++ b/src/lladd/linkedlist.c @@ -0,0 +1,162 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/****************************** + * $Id$ + * + * simple linked list + *****************************/ + +#include +#include + +#include "linkedlist.h" + +#ifndef NULL +#define NULL 0 +#endif + + +void printList(LinkedList *l) { + LinkedListPtr tmp = l; + printf ("List is "); + while (tmp!=NULL) { + printf ("%d ", tmp->val); + tmp = tmp->next; + } + printf (".\n"); +} +void addVal(LinkedList **list, int val) { + LinkedListPtr new = (LinkedListPtr)malloc(sizeof(LinkedList)); + new->val = val; + new->next = NULL; + if (*list==NULL) { + *list = new; + } + else { + new->next = *list; + *list = new; + } +} +void removeVal(LinkedList **list, int val) { + LinkedListPtr tmp, tmpprev; + if (*list==NULL) return; + if ((*list!=NULL) && ((*list)->val==val)) { + tmp = *list; + *list = (*list)->next; + free(tmp); + return; + } + tmp = (*list)->next; + tmpprev = *list; + while (tmp!=NULL) { + if (tmp->val==val) { + tmpprev->next = tmp->next; + free(tmp); + return; + } + tmpprev = tmp; + tmp = tmp->next; + } +} +int popMaxVal(LinkedList **list) { + LinkedListPtr tmp; + int tmpval; + if (*list!=NULL) { + tmp = *list; + (*list) = (*list)->next; + tmpval = tmp->val; + free(tmp); + return tmpval; + } + else return -1; /*this should be an error! */ +} + +void addSortedVal(LinkedList **list, int val) { + LinkedListPtr tmp, tmpprev; + LinkedListPtr new = (LinkedListPtr)malloc(sizeof(LinkedList)); + new->val = val; + /*see if new entry should come in the beginning*/ + if ((*list==NULL) || ((*list)->valnext = *list; + *list = new; + return; + } + /*else determine where to put new entry*/ + tmp = (*list)->next; + tmpprev = *list; + while (tmp!=NULL) { + if (tmp->valnext = new; + new->next = tmp; + return; + } + tmpprev = tmp; + tmp = tmp->next; + } + /*if gotten here, tmp is null so put item at the end of the list*/ + new->next = NULL; + tmpprev->next = new; +} +/* + return 1 if val is in the list, 0 otherwise +*/ +int findVal(LinkedList *list, int val) { + LinkedListPtr tmp = list; + while (tmp!=NULL) { + if (tmp->val==val) + return 1; + tmp = tmp->next; + } + return 0; +} + +/* Deallocates all nodes in the list, and sets list to null + */ +void destroyList (LinkedList *list) { + LinkedListPtr tmp; + while (list!=NULL) { + tmp = list->next; + free(list); + list=tmp; + } + list = NULL; +} diff --git a/src/lladd/linkedlist.h b/src/lladd/linkedlist.h new file mode 100644 index 0000000..977c0c1 --- /dev/null +++ b/src/lladd/linkedlist.h @@ -0,0 +1,97 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + + +#ifndef __LINKEDLIST_H__ +#define __LINKEDLIST_H__ + +/** + @file + + Implements a simple sorted linked list. Written for LLADD's + recovery algorithms. + + */ +#include +BEGIN_C_DECLS + +struct Nodetmp { + int val; + struct Nodetmp *next; +}; + +typedef struct Nodetmp LinkedList; +typedef LinkedList *LinkedListPtr; + +void printList(LinkedList *l) ; + +void addVal(LinkedList **list, int val); + +/** + @return 1 if val is in the list, 0 otherwise +*/ +int findVal(LinkedList *list, int val); + +/** + Deallocates all nodes in the list, and sets list to null +*/ +void destroyList (LinkedList *list); + +/** + * Add a value to the list in descending order + */ +void addSortedVal(LinkedList **list, int val); + +/** + * Remove a value from the list + */ +void removeVal(LinkedList **list, int val); + +/** + * Remove the max value (first on list), assuming list is not null and has been + * sorted + */ +int popMaxVal(LinkedList **list); + +END_C_DECLS + +#endif diff --git a/src/lladd/logger/.deps/logger.Po b/src/lladd/logger/.deps/logger.Po new file mode 100644 index 0000000..791cb8e --- /dev/null +++ b/src/lladd/logger/.deps/logger.Po @@ -0,0 +1,129 @@ +logger.o logger.o: logger.c /usr/include/stdlib.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/sys/types.h /usr/include/bits/types.h \ + /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h \ + /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h /usr/include/alloca.h \ + ../../../lladd/transactional.h ../../../lladd/common.h \ + ../../../lladd/config.h /usr/include/stdio.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ + /usr/include/gconv.h /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/string.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h \ + /usr/include/unistd.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h /usr/include/getopt.h \ + ../../../lladd/page.h ../../../lladd/operations.h \ + ../../../lladd/constants.h ../../../lladd/operations/increment.h \ + ../../../lladd/bufferManager.h ../../../lladd/operations/decrement.h \ + ../../../lladd/operations/set.h ../../../lladd/operations/prepare.h \ + ../../../lladd/operations/lladdhash.h ../../../lladd/logger.h \ + logparser.h logstreamer.h + +/usr/include/stdlib.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/sys/types.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/alloca.h: + +../../../lladd/transactional.h: + +../../../lladd/common.h: + +../../../lladd/config.h: + +/usr/include/stdio.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/page.h: + +../../../lladd/operations.h: + +../../../lladd/constants.h: + +../../../lladd/operations/increment.h: + +../../../lladd/bufferManager.h: + +../../../lladd/operations/decrement.h: + +../../../lladd/operations/set.h: + +../../../lladd/operations/prepare.h: + +../../../lladd/operations/lladdhash.h: + +../../../lladd/logger.h: + +logparser.h: + +logstreamer.h: diff --git a/src/lladd/logger/.deps/logparser.Po b/src/lladd/logger/.deps/logparser.Po new file mode 100644 index 0000000..844c0a8 --- /dev/null +++ b/src/lladd/logger/.deps/logparser.Po @@ -0,0 +1,107 @@ +logparser.o logparser.o: logparser.c /usr/include/stdlib.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/sys/types.h /usr/include/bits/types.h \ + /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h \ + /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h /usr/include/alloca.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/include/bits/wchar.h /usr/include/gconv.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/string.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h logparser.h \ + ../../../lladd/page.h ../../../lladd/common.h ../../../lladd/config.h \ + /usr/include/unistd.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h /usr/include/getopt.h \ + ../../../lladd/constants.h logstreamer.h + +/usr/include/stdlib.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/sys/types.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/alloca.h: + +/usr/include/stdio.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +logparser.h: + +../../../lladd/page.h: + +../../../lladd/common.h: + +../../../lladd/config.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/constants.h: + +logstreamer.h: diff --git a/src/lladd/logger/.deps/logstreamer.Po b/src/lladd/logger/.deps/logstreamer.Po new file mode 100644 index 0000000..2d9612d --- /dev/null +++ b/src/lladd/logger/.deps/logstreamer.Po @@ -0,0 +1,92 @@ +logstreamer.o logstreamer.o: logstreamer.c /usr/include/stdio.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/wordsize.h \ + /usr/include/bits/typesizes.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ + /usr/include/gconv.h /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/assert.h /usr/include/stdlib.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h \ + /usr/include/alloca.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h ../../../lladd/constants.h logstreamer.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/assert.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/alloca.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/constants.h: + +logstreamer.h: diff --git a/src/lladd/logger/Makefile.am-old b/src/lladd/logger/Makefile.am-old new file mode 100644 index 0000000..a198b1c --- /dev/null +++ b/src/lladd/logger/Makefile.am-old @@ -0,0 +1,3 @@ +lib_LIBRARIES=liblogger.a +liblogger_a_SOURCES=logger.c logparser.c logstreamer.c +AM_CFLAGS= -g -Wall -pedantic diff --git a/src/lladd/logger/logEntry.c b/src/lladd/logger/logEntry.c new file mode 100644 index 0000000..4b229f8 --- /dev/null +++ b/src/lladd/logger/logEntry.c @@ -0,0 +1,132 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#include +#include +#include +#include +#include + +LogEntry * allocCommonLogEntry(lsn_t prevLSN, int xid, unsigned int type) { + LogEntry * ret = malloc(sizeof(struct __raw_log_entry)); + ret->LSN = -1; + ret->prevLSN = prevLSN; + ret->xid = xid; + ret->type = type; + return ret; +} + +const byte * getUpdateArgs(const LogEntry * ret) { + assert(ret->type == UPDATELOG); + if(ret->contents.update.argSize == 0) { + return NULL; + } else { + return ((byte*)ret) + sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry); + } +} + +const byte * getUpdatePreImage(const LogEntry * ret) { + assert(ret->type == UPDATELOG); + if(operationsTable[ret->contents.update.funcID].undo != NO_INVERSE) { + /* if(ret->contents.update.invertible) { */ + return NULL; + } else { + return ((byte*)ret) + sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry) + ret->contents.update.argSize; + } +} + +LogEntry * allocUpdateLogEntry(lsn_t prevLSN, int xid, + unsigned int funcID, recordid rid, + const byte * args, unsigned int argSize, const byte * preImage) { + int invertible = operationsTable[funcID].undo != NO_INVERSE; + + LogEntry * ret = malloc(sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry) + argSize + ((!invertible) ? rid.size : 0)); + ret->LSN = -1; + ret->prevLSN = prevLSN; + ret->xid = xid; + ret->type = UPDATELOG; + ret->contents.update.funcID = funcID; + /* ret->contents.update.invertible = invertible; */ + ret->contents.update.rid = rid; + ret->contents.update.argSize = argSize; + + if(argSize) { + memcpy((void*)getUpdateArgs(ret), args, argSize); + } + if(!invertible) { + memcpy((void*)getUpdatePreImage(ret), preImage, rid.size); + } + + return ret; + +} + +LogEntry * allocCLRLogEntry (lsn_t prevLSN, int xid, + lsn_t thisUpdateLSN, recordid rid, lsn_t undoNextLSN) { + LogEntry * ret = malloc(sizeof(struct __raw_log_entry) + sizeof(CLRLogEntry)); + ret->LSN = -1; + ret->prevLSN = prevLSN; + ret->xid = xid; + ret->type = CLRLOG; + + ret->contents.clr.thisUpdateLSN = thisUpdateLSN; + ret->contents.clr.rid = rid; + ret->contents.clr.undoNextLSN = undoNextLSN; + + return ret; +} + + + +size_t sizeofLogEntry(const LogEntry * log) { + switch (log->type) { + case CLRLOG: + return sizeof(struct __raw_log_entry) + sizeof(CLRLogEntry); + case UPDATELOG: + return sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry) + log->contents.update.argSize + + ((operationsTable[log->contents.update.funcID].undo == NO_INVERSE) ? log->contents.update.rid.size : 0); + default: + return sizeof(struct __raw_log_entry); + } +} + diff --git a/src/lladd/logger/logHandle.c b/src/lladd/logger/logHandle.c new file mode 100644 index 0000000..f6bdc26 --- /dev/null +++ b/src/lladd/logger/logHandle.c @@ -0,0 +1,125 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include +#include + +/** + Sets the next and prev field of h, but does not set h.file_offset. + That should probably be set before calling this function. +*/ + +static void set_offsets(LogHandle * h, LogEntry * e, lsn_t lastRead); + +/*-------------------------------------------------------*/ + +LogHandle getLogHandle() { + return getGuardedHandle(sizeof(lsn_t), NULL, NULL); +} + +LogHandle getLSNHandle(lsn_t lsn) { + return getGuardedHandle(lsn, NULL, NULL); +} + +LogHandle getGuardedHandle(lsn_t lsn, guard_fcn_t * guard, void * guard_state) { + LogHandle ret; + ret.next_offset = lsn; + ret.prev_offset = lsn; + ret.guard = guard; + ret.guard_state = guard_state; + return ret; +} + +LogEntry * nextInLog(LogHandle * h) { + LogEntry * ret = readLSNEntry(h->next_offset); + if(ret != NULL) { + set_offsets(h, ret, h->next_offset); + } + + if(h->guard) { + if(!(h->guard(ret, h->guard_state))) { + free(ret); + ret = NULL; + } + } + + + return ret; +} + +LogEntry * previousInTransaction(LogHandle * h) { + LogEntry * ret = NULL; + if(h->prev_offset > 0) { + /* printf("A"); fflush(NULL); */ + ret = readLSNEntry(h->prev_offset); + set_offsets(h, ret, h->prev_offset); + /*printf("B"); fflush(NULL); */ + + if(h->guard) { + /*printf("C"); fflush(NULL);*/ + + if(!h->guard(ret, h->guard_state)) { + free(ret); + ret = NULL; + } + /*printf("D"); fflush(NULL);*/ + + } + } + + return ret; + +} + +/** + @todo The next_offset field is set in a way that assumes a + particular layout of log entries. If we want to support other + loggers, then the lsn of the next entry should be calculated by the + logging implementation, not here. (One possibility is to have + readLSNEntry return it explicitly.) +*/ +static void set_offsets(LogHandle * h, LogEntry * e, lsn_t lastRead) { + h->next_offset = lastRead + sizeofLogEntry(e)+sizeof(lsn_t); + h->prev_offset = (e->type==CLRLOG) ? e->contents.clr.undoNextLSN : e->prevLSN ; +} + diff --git a/src/lladd/logger/logWriter.c b/src/lladd/logger/logWriter.c new file mode 100644 index 0000000..a80033d --- /dev/null +++ b/src/lladd/logger/logWriter.c @@ -0,0 +1,203 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#include +#include + +#include +#include +/** + Invariant: This file stream is at EOF, or positioned so that the + next read will pull in the size of the next log entry. + + @todo Should the log file be global? +*/ +static FILE * log; + + +int openLogWriter() { + log = fopen(LOG_FILE, "a+"); + if (log==NULL) { + assert(0); + /*there was an error opening this file */ + return FILE_WRITE_OPEN_ERROR; + } + + /* Note that the position of the file between calls to this library + does not matter, since none of the functions in logWriter.h + assume anything about the position of the stream before they are + called. + + However, we need to do this seek to check the length of the file. + + */ + fseek(log, 0, SEEK_END); + + if (ftell(log)==0) { + /*if file is empty, write an LSN at the 0th position. LSN 0 is + invalid, and this prevents us from using it. Also, the LSN at + this position can be used after log truncation to define a + global offset for the truncated log. (Not implemented yet) + */ + lsn_t zero = 0; + int nmemb = fwrite(&zero, sizeof(lsn_t), 1, log); + if(nmemb != 1) { + perror("Couldn't start new log file!"); + assert(0); + return FILE_WRITE_OPEN_ERROR; + } + } + + return 0; +} + +int writeLogEntry(LogEntry * e) { + int nmemb; + const size_t size = sizeofLogEntry(e); + + /* Set the log entry's LSN. */ + fseek(log, 0, SEEK_END); + e->LSN = ftell(log); + + /* Print out the size of this log entry. (not including this item.) */ + nmemb = fwrite(&size, sizeof(size_t), 1, log); + + if(nmemb != 1) { + perror("writeLog couldn't write next log entry size!"); + assert(0); + return FILE_WRITE_ERROR; + } + + nmemb = fwrite(e, size, 1, log); + + if(nmemb != 1) { + perror("writeLog couldn't write next log entry!"); + assert(0); + return FILE_WRITE_ERROR; + } + + /* We're done. */ + return 0; +} + +void syncLog() { + fflush(log); +#ifdef HAVE_FDATASYNC + /* Should be available in linux >= 2.4 */ + fdatasync(fileno(log)); +#else + /* Slow - forces fs implementation to sync the file metadata to disk */ + fsync(fileno(log)); +#endif +} +void closeLogWriter() { + /* Get the whole thing to the disk before closing it. */ + syncLog(); + fclose(log); +} + +void deleteLogWriter() { + remove(LOG_FILE); +} + +static LogEntry * readLogEntry() { + LogEntry * ret = NULL; + size_t size; + int nmemb; + + if(feof(log)) return NULL; + + nmemb = fread(&size, sizeof(size_t), 1, log); + + if(nmemb != 1) { + if(feof(log)) return NULL; + if(ferror(log)) { + perror("Error reading log!"); + assert(0); + return 0; + } + } + + ret = malloc(size); + + nmemb = fread(ret, size, 1, log); + + if(nmemb != 1) { + /* Partial log entry. */ + if(feof(log)) return NULL; + if(ferror(log)) { + perror("Error reading log!"); + assert(0); + return 0; + } + assert(0); + return 0; + } + + /** Sanity check -- Did we get the whole entry? */ + assert(size == sizeofLogEntry(ret)); + + return ret; +} + +LogEntry * readLSNEntry(lsn_t LSN) { + LogEntry * ret; + + fseek(log, LSN, SEEK_SET); + ret = readLogEntry(); + + return ret; +} + +/*lsn_t nextLSN() { + lsn_t orig_pos = ftell(log); + lsn_t ret; + + fseek(log, 0, SEEK_END); + + ret = ftell(log); + + fseek(log, orig_pos, SEEK_SET); + + return ret; + }*/ diff --git a/src/lladd/logger/logger.c b/src/lladd/logger/logger.c new file mode 100644 index 0000000..bce3aa3 --- /dev/null +++ b/src/lladd/logger/logger.c @@ -0,0 +1,142 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/***************** + * @file + * $Id$ + * + * C implementation of logger.h + * + * @deprecated + * @see logger2.c + ******************/ +#include + +#include +#include +#include "logparser.h" +#include "logstreamer.h" +#include + +static long LogCommonWriterNoExtra(long prevLSN, int xid, int type); /*defined later*/ + +long LogTransBegin(Transaction t) { + return -1; +} + +/* jason please review and delete comment when done + * to recover: pageRalloc(loadPage(rid.page), rid.size) + */ +long LogTransAlloc(long prevLSN, int xid, recordid rid) { + char *extra; + int sizeOfExtra = allocPartsToString(&extra, rid); + return writeNewLog(prevLSN, xid, XALLOC, extra, sizeOfExtra); +} + + +long LogTransCommit(long prevLSN, int xid) { + long newLSN = LogCommonWriterNoExtra(prevLSN, xid, XCOMMIT); + flushLog(); + return newLSN; +} + +long LogTransAbort(long prevLSN, int xid) { + return LogCommonWriterNoExtra(prevLSN, xid, XABORT); +} + +long LogUpdate (long prevLSN, int xid, recordid rid, Operation op, const void *args) { + char *extra; + /* size_t sizeOfData, sizeOfExtra; */ + int sizeOfData, sizeOfExtra; + void *preImage = 0; + int invertible; + if (op.sizeofData==SIZEOF_RECORD) { + /*then get the size of this record */ + sizeOfData = rid.size; + } + else sizeOfData = op.sizeofData; + /*heck to see if op is invertible */ + if (op.undo==NO_INVERSE) { + invertible = 0; + preImage = (void *)malloc(rid.size); + readRecord(xid, rid, preImage); + } + else invertible = 1; + /*will put all of the parts special to an update log record into extra */ + sizeOfExtra = updatePartsToString(&extra, op.id, rid, args, sizeOfData, invertible, preImage); + /*extra has been malloced, but writeNewLog will free it*/ + if(preImage) { + free(preImage); + } + return writeNewLog(prevLSN, xid, UPDATELOG, extra, sizeOfExtra); +} + +long LogCLR (long prevLSN, int xid, long ulLSN, recordid ulRID, long ulPrevLSN) { +#define CLRSIZEOFEXTRA 20 + char *extra; + CLRPartsToString(&extra, ulLSN, ulRID, ulPrevLSN); + /*extra has been malloced, but writeNewLog will free it*/ + return writeNewLog(prevLSN, xid, CLRLOG, extra, CLRSIZEOFEXTRA); +} + +long LogEnd (long prevLSN, int xid) { + return LogCommonWriterNoExtra(prevLSN, xid, XEND); +} +/* + LogCommonWriterNoExtra writes the log record in the log tail when there is no extra data + being put in the log record -- a special case, and therefore just calls the more generalized LogCommongWriter + */ +static long LogCommonWriterNoExtra(long prevLSN, int xid, int type) { + return writeNewLog(prevLSN, xid, type, 0, 0); +} + +void logInit() { + startLogStream(); +} + +void logDeinit() { + closeLogStream(); + /** FOR NOW, don't delete the log stream at the end, even if all transactions + * are committed because we want to debug + */ + /*deleteLogStream();*/ +} diff --git a/src/lladd/logger/logger2.c b/src/lladd/logger/logger2.c new file mode 100644 index 0000000..6ba9fdc --- /dev/null +++ b/src/lladd/logger/logger2.c @@ -0,0 +1,112 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include +#include + +TransactionLog LogTransBegin(int xid) { + TransactionLog tl; + tl.xid = xid; + + DEBUG("Log Begin %d\n", xid); + tl.prevLSN = -1; + return tl; +} + +static void LogTransCommon(TransactionLog * l, int type) { + LogEntry * e = allocCommonLogEntry(l->prevLSN, l->xid, type); + writeLogEntry(e); + l->prevLSN = e->LSN; + DEBUG("Log Common %d, LSN: %ld type: %ld (prevLSN %ld)\n", e->xid, + (long int)e->LSN, (long int)e->type, (long int)e->prevLSN); + free(e); +} + +void LogTransCommit(TransactionLog * l) { + LogTransCommon(l, XCOMMIT); +} + +void LogTransAbort(TransactionLog * l) { + LogTransCommon(l, XABORT); +} + +LogEntry * LogUpdate(TransactionLog * l, recordid rid, int operation, const byte * args) { + void * preImage = NULL; + size_t argSize = 0; + LogEntry * e; + + if(operationsTable[operation].sizeofData == SIZEOF_RECORD) { + argSize = rid.size; + } else { + argSize = operationsTable[operation].sizeofData; + } + + if(operationsTable[operation].undo == NO_INVERSE) { + preImage = malloc(rid.size); + readRecord(l->xid, rid, preImage); + } + + e = allocUpdateLogEntry(l->prevLSN, l->xid, operation, rid, args, argSize, preImage); + writeLogEntry(e); + DEBUG("Log Common %d, LSN: %ld type: %ld (prevLSN %ld)\n", e->xid, + (long int)e->LSN, (long int)e->type, (long int)e->prevLSN); + + if(preImage) { + free(preImage); + } + + l->prevLSN = e->LSN; + return e; +} + +lsn_t LogCLR(/*TransactionLog * l,*/ LogEntry * undone) { + lsn_t ret; + LogEntry * e = allocCLRLogEntry(-1, undone->xid, undone->LSN, undone->contents.update.rid, undone->prevLSN); + writeLogEntry(e); + DEBUG("Log CLR %d, LSN: %ld type: %ld (undoing: %ld, next to undo: %ld)\n", e->xid, + (long int)e->LSN, (long int)e->type, (long int)undone->LSN, (long int)undone->prevLSN); + + ret = e->LSN; + free(e); + return ret; +} diff --git a/src/lladd/logger/logparser.c b/src/lladd/logger/logparser.c new file mode 100644 index 0000000..9f67093 --- /dev/null +++ b/src/lladd/logger/logparser.c @@ -0,0 +1,316 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/***************** + * @file + * $Id$ + * + * corresponding C file of the log parser + * + * @deprecated + * @see logEntry.c + * *************/ +#define _GNU_SOURCE +#include +#include +#include + +#include "logparser.h" +#include "logstreamer.h" + +static CommonLog assembleLog (long prevLSN, int xid, int type, void *extra, int extraLength); +static void writeCommonLog (CommonLog comLog); +static UpdateLog assembleUpdateLog (int funcID, recordid rid, const void *args, int arglen, int invertible, const void *preimage); +static CLRLog assembleCLRLog (long thisUpdateLSN, recordid rid, long undoNextLSN); +static int updateLogToString (char **s, UpdateLog upLog); +static int CLRLogToString (char **s, CLRLog clrlog); +long writeNewLog (long prevLSN, int xid, int type, char *extra, int extraLength) { + long thisLSN = writeStreamPos(); + CommonLog tmpLog; + /* printf("LogType:%d\n", type); */ + tmpLog = assembleLog(prevLSN, xid, type, extra, extraLength); + writeCommonLog (tmpLog); + if (tmpLog.extraData !=0) + free(tmpLog.extraData ); /*free up any malloc'ed string if it is there*/ + if (extra != 0) + free(extra); /*free up extra space that might have been malloced previously*/ + return thisLSN; +} + +int updatePartsToString (char **buf, int funcID, recordid rid, const char *args, int arglen, int invertible, const void *preImage) { + UpdateLog ul; + int sizeOfString; + ul = assembleUpdateLog(funcID, rid, args, arglen, invertible, preImage); + sizeOfString = updateLogToString(buf, ul); + /* if (ul.args!=0) + free(ul.args); //deallocate the update log's arg string that was malloc'ed in assembleUpdateLog (assembleupdate log no longer mallocs. ) + if (!invertible) + free(ul.preImage); */ + return sizeOfString; +} + +int CLRPartsToString (char **txt, long thisUpdateLSN, recordid rid, long undoNextLSN) { + return CLRLogToString(txt, assembleCLRLog(thisUpdateLSN, rid, undoNextLSN)); +} + +CommonLog readNextCommonLog() { + return readCommonLogFromLSN(readPos()); +} + +CommonLog readCommonLogFromLSN(long LSN) { + byte * buf;/* char *buf;*/ + long junk; + int bufPos, numObjs, extraSize; + CommonLog commonStuff; + commonStuff.LSN = LSN; + commonStuff.type = 0; + /*seekandreadlog will allocate space for buffer */ + junk = seekAndReadLog(LSN, &buf); + if (junk==0) { + commonStuff.valid=0; + free(buf); + return commonStuff; + } + numObjs = sscanf ((char*)buf, "%ld %d %d", &(commonStuff.prevLSN), &(commonStuff.xid), &(commonStuff.type)); + + if (numObjs!=3) { + commonStuff.valid = 0; + free(buf); + return commonStuff; /*if we don't have the 3 basic ingredients, invalid log entry or at end of file, etc*/ + } + commonStuff.valid = 1; + /*try to read extra data, if possible (will first have a size in bytes of the future data) + check if there is data beyond the 3 fields for optional data, and if so note where to put the data in buf*/ + if (sscanf((char*)buf, "%ld %*d %*d %d %n", &junk, &extraSize, &bufPos)==2) { /*note: pos does not increase the object count of sscanf*/ + /*then there is an extra string*/ + commonStuff.extraData = (void*)malloc(extraSize); + commonStuff.extraDataSize = extraSize; + memcpy(commonStuff.extraData, buf+bufPos, extraSize); + /*printf ("reading extradata=%d %d; extrasize=%d, bufpos=%d\n", *(int *)commonStuff.extraData, *(int *)(commonStuff.extraData+4), extraSize, bufPos);*/ + } + else { + + commonStuff.extraData = NULL; + commonStuff.extraDataSize = 0; + } + free(buf); + return commonStuff; +} + +UpdateLog updateStringToParts(byte *txt) { + UpdateLog thisUpdate; + int txtPos; + long int tmp_size; + /*read in the fixed size parts and get the position of where the data begins*/ + sscanf ((char*)txt, "%d %d %d %ld %d %d%n", &(thisUpdate.funcID), &(thisUpdate.rid.page), + &(thisUpdate.rid.slot), &tmp_size,/*(thisUpdate.rid.size),*/ &(thisUpdate.invertible), &thisUpdate.argSize, &txtPos); + thisUpdate.rid.size = (size_t) tmp_size; + txtPos++; /*there is an additional space between the argSize and the arg data*/ + thisUpdate.args = (void*)malloc(thisUpdate.argSize); + memcpy((byte*)thisUpdate.args, txt+txtPos, thisUpdate.argSize); + txtPos += 1+thisUpdate.argSize; + if (!thisUpdate.invertible) { + thisUpdate.preImage = (void*)malloc(thisUpdate.rid.size); + /* Remove the const qualifier from preImage so that we can initialize the malloced memory. */ + memcpy((void*)thisUpdate.preImage, txt+txtPos, thisUpdate.rid.size); + } + return thisUpdate; +} + +CLRLog CLRStringToParts (void *txt) { + CLRLog clrlog; + long int size_tmp; + sscanf(txt, "%ld %d %d %ld %ld", &(clrlog.thisUpdateLSN), &(clrlog.rid.page), &(clrlog.rid.slot), &(size_tmp), &(clrlog.undoNextLSN)); + clrlog.rid.size = (size_t) size_tmp; + return clrlog; + +} + +/* TODO: Fix string buffer size!!! */ +int allocPartsToString (char **txt, recordid rid) { + + return asprintf(txt, "%d %d %ld", rid.page, rid.slot, (long int)rid.size); + /* *txt = malloc(2*sizeof(int)+sizeof(long)+200); + sprintf (*txt, "%d %d %ld", rid.page, rid.slot, rid.size); */ + /*memcpy(txt, &rid, sizeof(recordid)); + printf ("writing rid=%d,%d,%ld\n", rid.page, rid.slot, rid.size);*/ + /*return sizeof(recordid);*/ +} + +recordid allocStringToRID (void *txt) { + recordid tmp; + long int tmp2; + sscanf(txt, "%d %d %ld", &tmp.page, &tmp.slot, &tmp2); + tmp.size = (size_t)tmp2; + /*memcpy(&tmp, txt, sizeof(recordid)); + printf ("reading rid=%d,%d,%ld\n", tmp.page, tmp.slot, tmp.size);*/ + return tmp; +} + +/************ PRIVATE WRITING-RELATED FUNCTIONS ********************/ +/* + put the pieces of a complete (common) log into the structure +*/ +static CommonLog assembleLog (long prevLSN, int xid, int type, void *extra, int extraLength) { + CommonLog tmp; + tmp.prevLSN = prevLSN; + tmp.xid = xid; + tmp.type = type; + tmp.valid = 1; + tmp.extraDataSize = extraLength; + if (extraLength==0) + tmp.extraData = NULL; + else { + tmp.extraData = (void*)malloc(extraLength); + memcpy(tmp.extraData, extra, extraLength); + } + return tmp; +} + +/* + marshal an common log into the log file +*/ +static void writeCommonLog (CommonLog comLog) { + char *buf; + int bytesWritten; + if (comLog.extraDataSize==0) { + /*TODO: Fix buffer size! (Throughout file) */ + /* buf = malloc(2*sizeof(int)+sizeof(long)+200); */ + bytesWritten = asprintf (&buf, "%ld %d %d", comLog.prevLSN, comLog.xid, comLog.type); + } + else { + char * buf2; + /* buf = malloc(3*sizeof(int)+sizeof(long)+200+4+comLog.extraDataSize); */ + /*first print all the ordinary components plus a space, then size of extra; note the last byte put into sprintf*/ + bytesWritten = asprintf (&buf, "%ld %d %d %d ", comLog.prevLSN, comLog.xid, comLog.type, comLog.extraDataSize); + buf2 = malloc(bytesWritten + comLog.extraDataSize); + memcpy (buf2, buf, bytesWritten); + free(buf); + buf = buf2; + /*directly write the data into the buffer after the rest of the stuff*/ + memcpy (buf+bytesWritten, comLog.extraData, comLog.extraDataSize); + /*printf("writing extra=%d %d\n", *(int *)comLog.extraData, *(int *)(comLog.extraData+4));*/ + } + writeLog(buf, bytesWritten+comLog.extraDataSize); + free(buf); +} + +/* + Given all the components of an update log, will produce an update log + + Returns an UpdateLog + NOTE: mallocates the output log's args string, so must be freed after use (Not true any more.) +*/ +static UpdateLog assembleUpdateLog (int funcID, recordid rid, const void *args, int arglen, int invertible, const void *preimage) { + UpdateLog tmpLog; + tmpLog.funcID = funcID; + tmpLog.rid = rid; + /* tmpLog.args = (void*)malloc(arglen); */ + tmpLog.argSize = arglen; + tmpLog.invertible = invertible; + /* memcpy (tmpLog.args, args, arglen); */ + + tmpLog.args = args; + + if (!invertible) { + /*Don't need this? Just set the pointer... */ + /* tmpLog.preImage = (void*)malloc(rid.size); + memcpy(tmpLog.preImage, preimage, rid.size); */ + tmpLog.preImage = preimage; + } else { + tmpLog.preImage = 0; + } + return tmpLog; +} + +static CLRLog assembleCLRLog (long thisUpdateLSN, recordid rid, long undoNextLSN) { + CLRLog tmpLog; + tmpLog.thisUpdateLSN = thisUpdateLSN; + tmpLog.rid = rid; + tmpLog.undoNextLSN = undoNextLSN; + return tmpLog; +} +/* + marshal an update log into a string (assume the string space has been allocated) + returns number of bytes written to the string +*/ +static int updateLogToString (char **s, UpdateLog upLog) { + int bytesWritten; + /* int maxDigitsForInt = 25; //32767 is 5 digits, plus a negative + int maxDigitsForLong = 25; + int estSize = 5*maxDigitsForInt+maxDigitsForLong+6+upLog.argSize;*/ + + char *tmp; + + /* if (!upLog.invertible) + estSize+=1+upLog.rid.size; */ + + + bytesWritten = asprintf (&tmp, "%d %d %d %ld %d %d ", upLog.funcID, upLog.rid.page, upLog.rid.slot, (long int)upLog.rid.size, upLog.invertible, upLog.argSize); + + *s = malloc(bytesWritten + upLog.argSize); + memcpy(*s, tmp, bytesWritten); + free (tmp); + memcpy(*s+bytesWritten, upLog.args, upLog.argSize); + bytesWritten+=upLog.argSize; + if (!upLog.invertible) { + tmp = *s; + *s = malloc(bytesWritten+1 +upLog.rid.size); + memcpy(*s, tmp, bytesWritten); + free (tmp); + + sprintf (*s+bytesWritten, " "); + memcpy(*s+bytesWritten+1, upLog.preImage, upLog.rid.size); + bytesWritten += 1 + upLog.rid.size; + } + return bytesWritten; +} + +static int CLRLogToString (char **s, CLRLog clrlog) { + /* int estSize = 3*sizeof(long)+2*sizeof(int)+400; */ + int bytesWritten; + /* *s = malloc(estSize); */ + bytesWritten = asprintf (s, "%ld %d %d %ld %ld ", clrlog.thisUpdateLSN, clrlog.rid.page, clrlog.rid.slot, (long int)clrlog.rid.size, clrlog.undoNextLSN); + /* if (bytesWritten!=estSize) { + //error! + }*/ + return bytesWritten; +} diff --git a/src/lladd/logger/logparser.h b/src/lladd/logger/logparser.h new file mode 100644 index 0000000..986d689 --- /dev/null +++ b/src/lladd/logger/logparser.h @@ -0,0 +1,206 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + + +/** + * @file + * + * logparser implements the specific formats of the log entrys to be read and + * written in the log file. + * + * All log entries have some fields in common (always) - a previous LSN, a + * transaction id, a log type, and any extra text specific to the type of entry. + * The extra text may be NULL, in which case there is no extra text! If there is + * extra text, additional public functions are written to put together and take + * apart the string into its object. + * + * This has been entirely rewritten. Don't use it. + * + * @deprecated @see logEntry.h + * + * Proposed api: + + + All of these return a pointer to a single malloced region that should be freed. + + allocCommonLogEntry(LSN, prevLSN, xid, type); + allocUpdateLogEntry(LSN, prevLSN, xid, type=UPDATE, funcID, rid, args, argSize, preImage); + allocCLRLogEntry (LSN, prevLSN, xid, type=CLR, thisUpdateLSN, rid, undoNextLSN); + + struct { + thisUpdateLSN; + rid; + undoNextLSN; + } CLRLogEntry; + + struct { + funcID; + rid; + argSize; + / * Implicit members: + args; @ ((byte*)ule) + sizeof(UpdateLogEntry) + preImage; @ ((byte*)ule) + sizeof(UpdateLogEntry) + ule.argSize * / + } UpdateLogEntry; + + struct { + LSN; + prevLSN; + xid; + type; + union { + UpdateLogEntry update; + CLRLogEntry clr; + } contents; + } LogEntry; + + sizeofLogEntry(LogEntry *); + size_t getUpdateArgs(LogEntry *); + size_t getUpdatePreImage(LogEntry *); + + * + * $Id$ + **/ + +#ifndef __LOGPARSER_H__ +#define __LOGPARSER_H__ + +#include +#include + +/* max the log line can be is 2 pages (set redo and undo data possibly) plus + * some more log stuff */ +/*#define maxLogLineLength 2*PAGE_SIZE + 100 */ + +/* + fields common to all log entries + extra could be null, indicating no extra data needed +*/ +typedef struct { + /**LSN field is ignored when writing to log, since it is determined + by the writer */ + long LSN; + long prevLSN; + int xid; + int type; + void *extraData; + int extraDataSize; + int valid; +} CommonLog; + +/** + Update Log components (that are normally stored in the 'extra' field of a common log + + The preimage is used for undos of operations with no inverses, and + the args field is used for the redo process, and inverse functions. +*/ +typedef struct { + /**what function it is*/ + int funcID; + /**page and slot number*/ + recordid rid; + /**binary data of the function arguments*/ + const byte *args; + int argSize; + int invertible; + /**if funcID is not invertible will store a preImage with size=rid.size*/ + const byte *preImage; +} UpdateLog; + +typedef struct { + /* UpdateLog ul; //has everything in an update log */ + long thisUpdateLSN; + recordid rid; + long undoNextLSN; +} CLRLog; + + +/********* PUBLIC WRITING-RELATED FUNCTIONS **************/ +/** + Given all the necessary components of a log entry, assemble it and then write it to the log file + + return the LSN of this new log entry + +*/ +long writeNewLog (long prevLSN, int xid, int type, char *extra, int extraLength); + +/** + put all of the components of the extra part of an update log into a buffer + returns the length of the string written to buf + + @ todo Logparser shouldn't write to char** +*/ +int updatePartsToString (char **buf, int funcID, recordid rid, const char *args, int arglen, int invertible, const void *preImage); + +/** + Takes in a buffer and a record id and copies the recordid into the buffer +*/ +int allocPartsToString (char **txt, recordid rid); + +/** + +*/ +int CLRPartsToString (char **txt, long thisUpdateLSN, recordid rid, long undoNextLSN); +/********* PUBLIC READING-RELATED FUNCTIONS **************/ +/** + parse a log line that only parses entries common to all log records into its structure. Can specify an LSN + + NOTE: the extra part of CommonLog might have a malloc'ed string in it; should be freed after use +*/ +CommonLog readNextCommonLog(); +CommonLog readCommonLogFromLSN(long LSN); + + +CLRLog readCLRLogFromLSN(long LSN); +/** + parse the extra part of an update log record into an UpdateLog structure + + NOTE: the args part of the UpdateLog has a malloc'ed string in it; should be freed after use +*/ +UpdateLog updateStringToParts(byte *txt); + +CLRLog CLRStringToParts (void *txt); +/** + Read a buffer and parse it into a recordid +*/ +recordid allocStringToRID (void *txt); + +#endif diff --git a/src/lladd/logger/logstreamer.c b/src/lladd/logger/logstreamer.c new file mode 100644 index 0000000..430f3bd --- /dev/null +++ b/src/lladd/logger/logstreamer.c @@ -0,0 +1,148 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/***************** + $Id$ + + the C implementation of logstreamer.h + ******************/ + +#include +#include +#include +#include + + +#include +#include "logstreamer.h" + +static FILE *log; + +int startLogStream() { + log = fopen(LOG_FILE, "a+"); + if (log==NULL) { + /*there was an error opening this file */ + return FILE_WRITE_OPEN_ERROR; + } + /*if file is empty, write a null at the 0th character */ + if (streamPos()==0) + fputs("0", log); + /*start reading at the 1st character*/ + fseek(log, 1, SEEK_SET); + return 0; /*otherwise return 0 for no errors*/ +} + +int writeLog(void *s, int length) { + /* int i; */ + fprintf(log, "%d ", length); /*print out the size of this log entry (not including this item and the \n */ + + if(1 != fwrite(s, length, 1, log)) { + + /* for( i = 0; i < length; i++ ) { + if(fputc(*(char*)(s+i), log) == EOF) { //write the string to the log tail*/ + perror("logstreamer: fputc"); + assert(0); + /* } */ + } + fprintf (log, "\n"); /*then write a carriage return just for our viewing pleasure*/ + return 0; /*otherwise, no errors*/ +} + +void flushLog() { + fflush(log); + /* fsync(fileno(log)); */ + fdatasync(fileno(log)); +} + +void closeLogStream() { + fclose(log); +} + +void deleteLogStream() { + remove(LOG_FILE); +} + +long streamPos() { + return ftell(log); +} + + +/* Assumes we're already @ EOF. */ +long writeStreamPos() { + /* long cur = ftell(log); + fseek(log, 0, SEEK_END); + assert(cur == ftell(log));*/ + return ftell(log); + /* long curPos = streamPos(); + long returnVal; + fseek(log, 0, SEEK_END); + returnVal = ftell(log); + fseek(log, curPos, SEEK_SET); + return returnVal;*/ +} +int readLog(byte **buffer) { + int length, i; + *buffer = 0; + if (feof(log)) return 0; + fscanf(log, "%d ", &length); + if (feof(log)) return 0; + /*get length characters from the log at this point and put them + into the buffer */ + *buffer = malloc(length+5); /*5 extra just to be safe*/ + for (i=0; i +#include +/* + start a new log stream by opening the log file for reading + + returns 0 on success, or an error code define above +*/ +int startLogStream(); + +/* + passed an address with data in it, writes it out to the log tail (not yet + flushed) + + returns 0 on success, or an error code defined above +*/ +int writeLog(void *s, int length); + +/* + flush the entire log (tail) that is currently in memory to disk +*/ +void flushLog(); + +/* + Close the log stream +*/ +void closeLogStream(); + +/* + Get the current position of the stream (in terms of bytes) +*/ +long getFilePos(); + +/* + Actually deletes the log file that may have been written to disk! Danger!! + Only use after calling closeLogStream AND you are sure there are no active (or + future active) transactions! +*/ +void deleteLogStream(); + +/* + * Returns the current position of the stream no matter where it is + */ +long streamPos(); + +/* + * Returns the position of the stream if it were to read. + */ +long writeStreamPos(); + +/* + * readLog reads a line from the log puts it in a string + * + * returns the number of bytes read and put into buffer + * */ +int readLog(byte **buffer); + +/* + * seek to a position in the log file and read it into the buffer + * + * returns the number of bytes read and put into buffer + * */ +int seekAndReadLog(long pos, byte **buffer); + +/* + * tell the current position in the log file + * */ +long readPos (); + +void seekInLog(long pos); +#endif diff --git a/src/lladd/operations.c b/src/lladd/operations.c new file mode 100644 index 0000000..7c055e2 --- /dev/null +++ b/src/lladd/operations.c @@ -0,0 +1,113 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#include +#include +#include + +Operation operationsTable[MAX_OPERATIONS]; + +void doUpdate(const LogEntry * e) { + operationsTable[e->contents.update.funcID].run(e->xid, e->contents.update.rid, getUpdateArgs(e)); +} + +void redoUpdate(const LogEntry * e) { + if(e->type == UPDATELOG) { +#ifdef DEBUGGING + recordid rid = e->contents.update.rid; +#endif + if(e->LSN > readLSN(e->contents.update.rid.page)) { + DEBUG("Redo, %ld {%d %d %d}\n", e->LSN, rid.page, rid.slot, rid.size); + doUpdate(e); + } else { + DEBUG("Skipping redo, %ld {%d %d %d}\n", e->LSN, rid.page, rid.slot, rid.size); + } + } else if(e->type == CLRLOG) { + LogEntry * f = readLSNEntry(e->contents.clr.thisUpdateLSN); +#ifdef DEBUGGING + recordid rid = f->contents.update.rid; +#endif + /* See if the page contains the result of the undo that this CLR is supposed to perform. If it + doesn't, then undo the original operation. */ + if(f->LSN > readLSN(e->contents.update.rid.page)) { + + DEBUG("Undoing for clr, %ld {%d %d %d}\n", f->LSN, rid.page, rid.slot, rid.size); + undoUpdate(f); + } else { + DEBUG("Skiping undo for clr, %ld {%d %d %d}\n", f->LSN, rid.page, rid.slot, rid.size); + } + } else { + assert(0); + } + +} + + +void undoUpdate(const LogEntry * e) { + + int undo = operationsTable[e->contents.update.funcID].undo; + /* printf("FuncID: %d Undo op: %d\n",e->contents.update.funcID, undo); fflush(NULL); */ + if(e->LSN <= readLSN(e->contents.update.rid.page)) { +#ifdef DEBUGGING + recordid rid = e->contents.update.rid; +#endif + + + + /* Actually execute the undo */ + if(undo == NO_INVERSE) { + /* Physical undo */ + + DEBUG("Physical undo, %ld {%d %d %d}\n", e->LSN, rid.page, rid.slot, rid.size); + /** @todo Why were we passing in RECOVERY_XID? */ + writeRecord(e->xid, e->contents.update.rid, getUpdatePreImage(e)); + } else { + /* @see doUpdate() */ + /* printf("Logical undo"); fflush(NULL); */ + DEBUG("Logical undo, %ld {%d %d %d}\n", e->LSN, rid.page, rid.slot, rid.size); + operationsTable[undo].run(e->xid, e->contents.update.rid, getUpdateArgs(e)); + } + } + /* printf("Undo done."); fflush(NULL); */ + +} diff --git a/src/lladd/operations/.deps/decrement.Po b/src/lladd/operations/.deps/decrement.Po new file mode 100644 index 0000000..60245a8 --- /dev/null +++ b/src/lladd/operations/.deps/decrement.Po @@ -0,0 +1,122 @@ +decrement.o decrement.o: decrement.c \ + ../../../lladd/operations/decrement.h ../../../lladd/constants.h \ + ../../../lladd/operations.h ../../../lladd/common.h \ + ../../../lladd/config.h /usr/include/stdio.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/wordsize.h \ + /usr/include/bits/typesizes.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ + /usr/include/gconv.h /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h /usr/include/stdlib.h /usr/include/alloca.h \ + /usr/include/string.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h ../../../lladd/page.h \ + ../../../lladd/operations/increment.h ../../../lladd/bufferManager.h \ + ../../../lladd/operations/set.h ../../../lladd/operations/prepare.h \ + ../../../lladd/operations/lladdhash.h ../../../lladd/transactional.h + +../../../lladd/operations/decrement.h: + +../../../lladd/constants.h: + +../../../lladd/operations.h: + +../../../lladd/common.h: + +../../../lladd/config.h: + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/stdlib.h: + +/usr/include/alloca.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/page.h: + +../../../lladd/operations/increment.h: + +../../../lladd/bufferManager.h: + +../../../lladd/operations/set.h: + +../../../lladd/operations/prepare.h: + +../../../lladd/operations/lladdhash.h: + +../../../lladd/transactional.h: diff --git a/src/lladd/operations/.deps/increment.Po b/src/lladd/operations/.deps/increment.Po new file mode 100644 index 0000000..638f20f --- /dev/null +++ b/src/lladd/operations/.deps/increment.Po @@ -0,0 +1,122 @@ +increment.o increment.o: increment.c \ + ../../../lladd/operations/increment.h ../../../lladd/constants.h \ + ../../../lladd/operations.h ../../../lladd/common.h \ + ../../../lladd/config.h /usr/include/stdio.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/wordsize.h \ + /usr/include/bits/typesizes.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ + /usr/include/gconv.h /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h /usr/include/stdlib.h /usr/include/alloca.h \ + /usr/include/string.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h ../../../lladd/page.h \ + ../../../lladd/operations/decrement.h ../../../lladd/bufferManager.h \ + ../../../lladd/operations/set.h ../../../lladd/operations/prepare.h \ + ../../../lladd/operations/lladdhash.h ../../../lladd/transactional.h + +../../../lladd/operations/increment.h: + +../../../lladd/constants.h: + +../../../lladd/operations.h: + +../../../lladd/common.h: + +../../../lladd/config.h: + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/stdlib.h: + +/usr/include/alloca.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/page.h: + +../../../lladd/operations/decrement.h: + +../../../lladd/bufferManager.h: + +../../../lladd/operations/set.h: + +../../../lladd/operations/prepare.h: + +../../../lladd/operations/lladdhash.h: + +../../../lladd/transactional.h: diff --git a/src/lladd/operations/.deps/lladdhash.Po b/src/lladd/operations/.deps/lladdhash.Po new file mode 100644 index 0000000..082e13d --- /dev/null +++ b/src/lladd/operations/.deps/lladdhash.Po @@ -0,0 +1,127 @@ +lladdhash.o lladdhash.o: lladdhash.c \ + ../../../lladd/operations/lladdhash.h ../../../lladd/transactional.h \ + ../../../lladd/common.h ../../../lladd/config.h /usr/include/stdio.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/wordsize.h \ + /usr/include/bits/typesizes.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ + /usr/include/gconv.h /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h /usr/include/stdlib.h /usr/include/alloca.h \ + /usr/include/string.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h ../../../lladd/page.h ../../../lladd/operations.h \ + ../../../lladd/constants.h ../../../lladd/operations/increment.h \ + ../../../lladd/bufferManager.h ../../../lladd/operations/decrement.h \ + ../../../lladd/operations/set.h ../../../lladd/operations/prepare.h \ + /usr/include/assert.h /usr/include/memory.h + +../../../lladd/operations/lladdhash.h: + +../../../lladd/transactional.h: + +../../../lladd/common.h: + +../../../lladd/config.h: + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/stdlib.h: + +/usr/include/alloca.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/page.h: + +../../../lladd/operations.h: + +../../../lladd/constants.h: + +../../../lladd/operations/increment.h: + +../../../lladd/bufferManager.h: + +../../../lladd/operations/decrement.h: + +../../../lladd/operations/set.h: + +../../../lladd/operations/prepare.h: + +/usr/include/assert.h: + +/usr/include/memory.h: diff --git a/src/lladd/operations/.deps/prepare.Po b/src/lladd/operations/.deps/prepare.Po new file mode 100644 index 0000000..96a72aa --- /dev/null +++ b/src/lladd/operations/.deps/prepare.Po @@ -0,0 +1,125 @@ +prepare.o prepare.o: prepare.c ../../../lladd/operations/prepare.h \ + ../../../lladd/constants.h ../../../lladd/operations.h \ + ../../../lladd/common.h ../../../lladd/config.h /usr/include/stdio.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/wordsize.h \ + /usr/include/bits/typesizes.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ + /usr/include/gconv.h /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h /usr/include/stdlib.h /usr/include/alloca.h \ + /usr/include/string.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h ../../../lladd/page.h \ + ../../../lladd/operations/increment.h ../../../lladd/bufferManager.h \ + ../../../lladd/operations/decrement.h ../../../lladd/operations/set.h \ + ../../../lladd/operations/lladdhash.h ../../../lladd/transactional.h \ + ../logger/logstreamer.h + +../../../lladd/operations/prepare.h: + +../../../lladd/constants.h: + +../../../lladd/operations.h: + +../../../lladd/common.h: + +../../../lladd/config.h: + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/stdlib.h: + +/usr/include/alloca.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/page.h: + +../../../lladd/operations/increment.h: + +../../../lladd/bufferManager.h: + +../../../lladd/operations/decrement.h: + +../../../lladd/operations/set.h: + +../../../lladd/operations/lladdhash.h: + +../../../lladd/transactional.h: + +../logger/logstreamer.h: diff --git a/src/lladd/operations/.deps/set.Po b/src/lladd/operations/.deps/set.Po new file mode 100644 index 0000000..bfbefc8 --- /dev/null +++ b/src/lladd/operations/.deps/set.Po @@ -0,0 +1,123 @@ +set.o set.o: set.c ../../../lladd/operations/set.h \ + ../../../lladd/constants.h ../../../lladd/operations.h \ + ../../../lladd/common.h ../../../lladd/config.h /usr/include/stdio.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h \ + /usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/wordsize.h \ + /usr/include/bits/typesizes.h /usr/include/libio.h \ + /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ + /usr/include/gconv.h /usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h /usr/include/stdlib.h /usr/include/alloca.h \ + /usr/include/string.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h ../../../lladd/page.h \ + ../../../lladd/operations/increment.h ../../../lladd/bufferManager.h \ + ../../../lladd/operations/decrement.h \ + ../../../lladd/operations/prepare.h \ + ../../../lladd/operations/lladdhash.h ../../../lladd/transactional.h + +../../../lladd/operations/set.h: + +../../../lladd/constants.h: + +../../../lladd/operations.h: + +../../../lladd/common.h: + +../../../lladd/config.h: + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/gnu/stubs.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/include/bits/wchar.h: + +/usr/include/gconv.h: + +/usr/lib/gcc-lib/i486-linux/3.3.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sched.h: + +/usr/include/stdlib.h: + +/usr/include/alloca.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../../../lladd/page.h: + +../../../lladd/operations/increment.h: + +../../../lladd/bufferManager.h: + +../../../lladd/operations/decrement.h: + +../../../lladd/operations/prepare.h: + +../../../lladd/operations/lladdhash.h: + +../../../lladd/transactional.h: diff --git a/src/lladd/operations/Makefile.am-old b/src/lladd/operations/Makefile.am-old new file mode 100644 index 0000000..bef60ec --- /dev/null +++ b/src/lladd/operations/Makefile.am-old @@ -0,0 +1,3 @@ +lib_LIBRARIES=liboperations.a +liboperations_a_SOURCES=decrement.c increment.c lladdhash.c prepare.c set.c +AM_CFLAGS= -g -Wall -pedantic diff --git a/src/lladd/operations/alloc.c b/src/lladd/operations/alloc.c new file mode 100644 index 0000000..d1d3bab --- /dev/null +++ b/src/lladd/operations/alloc.c @@ -0,0 +1,69 @@ +#include +#include +#include + +/** + Implementation of Talloc() as an operation + + This is a bit strange compared to other operations, as it happens + in two phases. The buffer manager reserves space for a record + before the log entry is allocated. Then, the recordid of this + space is written to the log. Finally, alloc tells bufferManager + that it will use the space. + + @todo Currently, if the system crashes during an alloc, (before the + log is flushed, but after bufferManager returns a rid), then the + space alloced during the crash is leaked. This doesn't seem to be + too big of a deal, but it should be fixed someday. + +*/ + +static int operate(int xid, recordid rid, const void * dat) { + Page loadedPage = loadPage(rid.page); + /** Has no effect during normal operation. */ + pageSlotRalloc(loadedPage, rid); + return 0; +} + +/** @todo Currently, we just lead store space on dealloc. */ +static int deoperate(int xid, recordid rid, const void * dat) { + Page loadedPage = loadPage(rid.page); + /** Has no effect during normal operation. */ + pageSlotRalloc(loadedPage, rid); + return 0; +} + +Operation getAlloc() { + Operation o = { + OPERATION_ALLOC, /* ID */ + 0, + OPERATION_DEALLOC, + &operate + }; + return o; +} + +recordid Talloc(int xid, size_t size) { + recordid rid; + + rid = ralloc(xid, size); + + Tupdate(xid,rid, NULL, OPERATION_ALLOC); + + return rid; + +} + +Operation getDealloc() { + Operation o = { + OPERATION_DEALLOC, + 0, + OPERATION_ALLOC, + &deoperate + }; + return o; +} + +void Tdealloc(int xid, recordid rid) { + Tupdate(xid, rid, NULL, OPERATION_DEALLOC); +} diff --git a/src/lladd/operations/decrement.c b/src/lladd/operations/decrement.c new file mode 100644 index 0000000..fa4ea33 --- /dev/null +++ b/src/lladd/operations/decrement.c @@ -0,0 +1,69 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************************** + * $Id$ + * + * Decrements the given reference by one + *********************************************/ + +#include +#include + +static int operate(int xid, recordid r, const void *d) { + int i; + + readRecord(xid, r, &i); + i--; + writeRecord(xid, r, &i); + + return 0; +} + +Operation getDecrement() { + Operation o = { + OPERATION_DECREMENT, /* id */ + 0, /* sizeofData (this doesn't take any args) */ + OPERATION_INCREMENT, /* we're not doing undo functions yet */ + &operate /* Function */ + }; + return o; +} diff --git a/src/lladd/operations/increment.c b/src/lladd/operations/increment.c new file mode 100644 index 0000000..cfb54da --- /dev/null +++ b/src/lladd/operations/increment.c @@ -0,0 +1,68 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************************** + * $Id$ + * + * Increments the given reference by one + **********************************************/ + +#include +#include +static int operate(int xid, recordid r, const void *d) { + int i; + + readRecord(xid, r, &i); + i++; + writeRecord(xid, r, &i); + + return 0; +} + +Operation getIncrement() { + Operation o = { + OPERATION_INCREMENT, /* id */ + 0, /* sizeofData (this doesn't take any args) */ + OPERATION_DECREMENT, /* we're not doing undo functions yet */ + &operate /* Function */ + }; + return o; +} diff --git a/src/lladd/operations/lladdhash.c b/src/lladd/operations/lladdhash.c new file mode 100644 index 0000000..21acea0 --- /dev/null +++ b/src/lladd/operations/lladdhash.c @@ -0,0 +1,456 @@ +#include + +#include +#include +#include +#include + + +#include + +static const recordid ZERO_RECORDID = {0,0,0}; + +typedef struct { + int ht; + size_t keylen; + size_t datlen; +} lladdHashRec_t; + +static lladdHash_t * lladdHashes[MAX_LLADDHASHES]; +int next_lladdHash = 0; + +lladdHash_t * lHtCreate(int xid, int size) { + + lladdHash_t *ht; + + ht = lladdHashes[next_lladdHash] = (lladdHash_t*)malloc(sizeof(lladdHash_t)); + + + if( ht ) { + recordid * hm = malloc(sizeof(recordid) * size); + if(hm) { + memset(hm, 0, sizeof(recordid)*size); + + ht->size = size; + ht->store = next_lladdHash; /*Talloc(xid, sizeof(lladdHash_t));*/ + ht->hashmap_record = Talloc(xid, sizeof(recordid) * size); + /*ht->hashmap = NULL;*/ /* Always should be NULL in the store, so that we know if we need to read it in */ + /* Tset(xid, ht->store, ht); */ + ht->hashmap = hm; + Tset(xid, ht->hashmap_record, ht->hashmap); + ht->iterIndex = 0; + ht->iterData = NULL; + + next_lladdHash++; + + return ht; + } else { + free(ht); + return NULL; + } + } + + return NULL; +} + +int lHtValid(int xid, lladdHash_t *ht) { + /* + int ret; + lladdHash_t *test ; = (lladdHash_t*)malloc(sizeof(lladdHash_t)); + Tread(xid, ht->store, test); + ret = ( test->store.size == ht->store.size + && test->store.slot == ht->store.slot + && test->store.page == ht->store.page ); */ + /* TODO: Check hashmap_record? */ + /* free(test); */ + + assert(0); /* unimplemented! */ + + return 1; +} + +/** + * Hash function generator, taken directly from pblhash + */ +static int hash( const unsigned char * key, size_t keylen, int size ) { + int ret = 104729; + + for( ; keylen-- > 0; key++ ) + { + if( *key ) + { + ret *= *key + keylen; + ret %= size; + } + } + + return( ret % size ); +} + +/** Should be called the first time ht->hashmap is accessed by a library function. + Checks to see if the hashmap record has been read in, reads it if necessary, and then + returns a pointer to it. */ +static recordid* _getHashMap(int xid, lladdHash_t *ht) { + if(! ht->hashmap) { + printf("Reading in hashmap.\n"); + ht->hashmap = malloc(sizeof(recordid) * ht->size); + Tread(xid, ht->hashmap_record, ht->hashmap); + } + + + return ht->hashmap; +} +/* TODO: Insert and Remove need to bypass Talloc(), so that recovery won't crash. (Otherwise, we double-free records...This + was not noticed before, since recovery never freed pages.) */ +int _lHtInsert(int xid, recordid garbage, lladdHashRec_t * arg) { + + /* recordid ht_rec = arg->ht; */ + + size_t keylen = arg->keylen; + size_t datlen = arg->datlen; + void * key = ((void*)arg) + sizeof(lladdHashRec_t); + void * dat = ((void*)arg) + sizeof(lladdHashRec_t) + keylen; + + + lladdHash_t * ht; + int index; + recordid rid; + void *newd; + lladdHashItem_t newi; + + +// printf("Inserting %d -> %d\n", *(int*)key, *(int*)dat); + + ht = lladdHashes[arg->ht]; + + /* Tread(xid, ht_rec, &ht); */ + + index = hash( key, keylen, ht->size); + rid = _getHashMap(xid, ht)[index]; + + /* printf("Inserting %d -> %s %d {%d %d %d}\n", *(int*)key, dat, index, rid.page, rid.slot, rid.size); */ + + + if( rid.size == 0 ) { /* nothing with this hash has been inserted */ + + newi.store = Talloc(xid, sizeof(lladdHashItem_t)+keylen+datlen); + newd = malloc(sizeof(lladdHashItem_t)+keylen+datlen); + newi.keylen = keylen; + newi.datlen = datlen; + newi.next = ZERO_RECORDID; + memcpy(newd, &newi, sizeof(lladdHashItem_t)); + memcpy(newd+sizeof(lladdHashItem_t), key, keylen); + memcpy(newd+sizeof(lladdHashItem_t)+keylen, dat, datlen); + writeRecord(xid, newi.store, newd); + + ht->hashmap[index] = newi.store; + /* Tset(xid, ht->store, ht); */ + /* printf("Writing hashmap slot {%d %d %d}[%d] = {%d,%d,%d}.\n", + ht.hashmap_record.page,ht.hashmap_record.slot,ht.hashmap_record.size, + index, + ht.hashmap[index].page,ht.hashmap[index].slot,ht.hashmap[index].size); */ + writeRecord(xid, ht->hashmap_record, ht->hashmap); + + free(newd); + + } else { + + void *item = NULL; + + do { + + free(item); /* NULL ignored by free */ + item = malloc(rid.size); + Tread(xid, rid, item); + if( ((lladdHashItem_t*)item)->keylen == keylen && !memcmp(key, item+sizeof(lladdHashItem_t), keylen)) { + memcpy(item+sizeof(lladdHashItem_t)+keylen, dat, ((lladdHashItem_t*)item)->datlen); + writeRecord(xid, ((lladdHashItem_t*)item)->store, item); + free(item); + return 0; + } + rid = ((lladdHashItem_t*)item)->next; /* could go off end of list */ + } while( ((lladdHashItem_t*)item)->next.size != 0 ); + /* now item is the tail */ + + newi.store = Talloc(xid, sizeof(lladdHashItem_t)+keylen+datlen); + newd = malloc(sizeof(lladdHashItem_t)+keylen+datlen); + newi.keylen = keylen; + newi.datlen = datlen; + newi.next = ZERO_RECORDID; + memcpy(newd, &newi, sizeof(lladdHashItem_t)); + memcpy(newd+sizeof(lladdHashItem_t), key, keylen); + memcpy(newd+sizeof(lladdHashItem_t)+keylen, dat, datlen); + writeRecord(xid, newi.store, newd); + + ((lladdHashItem_t*)item)->next = newi.store; + writeRecord(xid, ((lladdHashItem_t*)item)->store, item); + free(item); + free(newd); + } + return 0; +} +/**Todo: ht->iterData is global to the hash table... seems like a bad idea! */ +int lHtPosition( int xid, lladdHash_t *ht, const void *key, size_t key_length ) { + int index = hash(key, key_length, ht->size); + + recordid rid = _getHashMap(xid, ht)[index]; + + if(rid.size == 0) { + printf("rid,size = 0\n"); + return -1; + } else { + //void * item = NULL; + lladdHashItem_t * item = malloc(rid.size); + + + for(Tread(xid, rid, item) ; + !(item->keylen == key_length && !memcmp(key, ((void*)item)+sizeof(lladdHashItem_t), key_length)) ; + rid = item->next) { + if(rid.size == 0) { + printf("Found bucket, but item not here!\n"); + return -1; // Not in hash table. + } + free(item); + item = malloc(rid.size); + Tread(xid, rid, item); + } + /* item is what we want.. */ + ht->iterIndex = index+1; //iterIndex is the index of the next interesting hash bucket. + ht->iterData = item; //Freed in lHtNext + return 0; + } + +} +int lHtLookup( int xid, lladdHash_t *ht, const void *key, size_t keylen, void *buf ) { + + int index = hash(key, keylen, ht->size); + recordid rid = _getHashMap(xid, ht)[index]; + /* printf("lookup: %d -> %d {%d %d %d} \n", *(int*)key, index, rid.page, rid.slot, rid.size); */ + if( rid.size == 0 ) { /* nothing inserted with this hash */ + return -1; + } else { + void *item = NULL; + item = malloc(rid.size); + Tread(xid, rid, item); + + for( ; !(((lladdHashItem_t*)item)->keylen == keylen && !memcmp(key, item+sizeof(lladdHashItem_t), keylen)); + rid = ((lladdHashItem_t*)item)->next ) { + if( rid.size == 0) { /* at the end of the list and not found */ + return -1; + } + free(item); + item = malloc(rid.size); + Tread(xid, rid, item); + } + /* rid is what we want */ + + memcpy(buf, item+sizeof(lladdHashItem_t)+((lladdHashItem_t*)item)->keylen, ((lladdHashItem_t*)item)->datlen); + free(item); + return 0; + } + + return 0; +} + +int _lHtRemove( int xid, recordid garbage, lladdHashRec_t * arg) { + + size_t keylen = arg->keylen; + void * key = ((void*)arg) + sizeof(lladdHashRec_t); + + lladdHash_t * ht = lladdHashes[arg->ht]; + + int index; + recordid rid; + +// printf("Removing %d\n", *(int*)key); + + index = hash(key, keylen, ht->size); + rid = _getHashMap(xid, ht)[index]; + + if( rid.size == 0) { /* nothing inserted with this hash */ + return -1; + } else { + void *del = malloc(rid.size); + Tread(xid, rid, del); + if( ((lladdHashItem_t*)del)->keylen == keylen && !memcmp(key, del+sizeof(lladdHashItem_t), keylen) ) { + /* the head is the entry to be removed */ + /* if( buf ) { + memcpy( buf, del+sizeof(lladdHashItem_t*)+keylen, ((lladdHashItem_t*)del)->datlen); + } */ + ht->hashmap[index] = ((lladdHashItem_t*)del)->next; + /* Tset(xid, ht->store, ht); */ + writeRecord(xid, ht->hashmap_record, ht->hashmap); + + /* TODO: dealloc rid */ + return 0; + } else { + void * prevd = NULL; + while( ((lladdHashItem_t*)del)->next.size ) { + free(prevd); /* free will ignore NULL args */ + prevd = del; + rid = ((lladdHashItem_t*)del)->next; + del = malloc(rid.size); + Tread(xid, rid, del); + if( ((lladdHashItem_t*)del)->keylen == keylen && !memcmp(key, del+sizeof(lladdHashItem_t), keylen) ) { + /* if( buf ) { + memcpy( buf, del+sizeof(lladdHashItem_t)+keylen, ((lladdHashItem_t*)del)->datlen); + } */ + ((lladdHashItem_t*)prevd)->next = ((lladdHashItem_t*)del)->next; + writeRecord(xid, ((lladdHashItem_t*)prevd)->store, prevd); + /* TODO: dealloc rid */ + free(prevd); + free(del); + return 0; + } + } + /* could not find exact key */ + + free(prevd); + free(del); + return -1; + } + } + + assert( 0 ); /* should not get here */ + return -1; +} + +int lHtFirst( int xid, lladdHash_t *ht, void *buf ) { + + ht->iterIndex = 0; + ht->iterData = NULL; + return lHtNext( xid, ht, buf); +} + +int lHtNext( int xid, lladdHash_t *ht, void *buf ) { + _getHashMap(xid, ht); + if( ht->iterData && (((lladdHashItem_t*)(ht->iterData))->next.size != 0) ) { + recordid next = ((lladdHashItem_t*)(ht->iterData))->next; + free( ht->iterData ); + ht->iterData = malloc(next.size); + Tread(xid, next, ht->iterData); + } else { + while(ht->iterIndex < ht->size) { + if( ht->hashmap[ht->iterIndex].size ) + break; + else + ht->iterIndex++; + } + if( ht->iterIndex == ht->size) /* went through and found no data */ + return -1; + + free( ht->iterData ); + ht->iterData = malloc(ht->hashmap[ht->iterIndex].size); /* to account for the last post incr */ + Tread(xid, ht->hashmap[ht->iterIndex++], ht->iterData); /* increment for next round */ + } + + return lHtCurrent(xid, ht, buf); +} + +int lHtCurrent(int xid, lladdHash_t *ht, void *buf) { + + if( ht->iterData ) { + if(buf) + memcpy(buf, ht->iterData + sizeof(lladdHashItem_t) + ((lladdHashItem_t*)(ht->iterData))->keylen, ((lladdHashItem_t*)(ht->iterData))->datlen); + return 0; + } + return -1; +} + + +int lHtCurrentKey(int xid, lladdHash_t *ht, void *buf) { + + if( ht->iterData ) { + memcpy(buf, ht->iterData + sizeof(lladdHashItem_t), ((lladdHashItem_t*)(ht->iterData))->keylen); + return 0; + } + return -1; +} + +int lHtDelete(int xid, lladdHash_t *ht) { + + /* deralloc ht->store */ + + if(ht->hashmap) { free(ht->hashmap); } + free(ht); + + return 0; +} + + +int lHtInsert(int xid, lladdHash_t *ht, const void *key, size_t keylen, void *dat, size_t datlen) { + recordid rid; + void * log_r; + lladdHashRec_t lir; + rid.page = 0; + rid.slot = 0; + rid.size = sizeof(lladdHashRec_t) + keylen + datlen; + + lir.ht = ht->store; + lir.keylen = keylen; + lir.datlen = datlen; + + log_r = malloc(rid.size); + memcpy(log_r, &lir, sizeof(lladdHashRec_t)); + memcpy(log_r+sizeof(lladdHashRec_t), key, keylen); + memcpy(log_r+sizeof(lladdHashRec_t)+keylen, dat, datlen); + + /* printf("Tupdating: %d -> %s\n", *(int*)key, dat); */ + + Tupdate(xid,rid,log_r, OPERATION_LHINSERT); + return 0; + +} +int lHtRemove( int xid, lladdHash_t *ht, const void *key, size_t keylen, void *buf, size_t buflen ) { + + recordid rid; + void * log_r; + lladdHashRec_t lrr; + int ret = lHtLookup(xid, ht, key, keylen, buf); + +/* printf("Looked up: %d\n", *(int*)buf); */ + + if(ret >= 0) { + rid.page = 0; + rid.slot = 0; + rid.size = sizeof(lladdHashRec_t) + keylen + buflen; + + lrr.ht = ht->store; + lrr.keylen = keylen; + lrr.datlen = buflen; + + log_r = malloc(sizeof(lladdHashRec_t) + keylen + buflen); + memcpy(log_r, &lrr, sizeof(lladdHashRec_t)); + memcpy(log_r+sizeof(lladdHashRec_t), key, keylen); + memcpy(log_r+sizeof(lladdHashRec_t)+keylen, buf, buflen); + + lrr.datlen = buflen; + + Tupdate(xid,rid,log_r, OPERATION_LHREMOVE); + + free (log_r); + } + return ret; +} + +Operation getLHInsert() { + Operation o = { + OPERATION_LHINSERT, + SIZEOF_RECORD, /* use the size of the record as size of arg (nasty, ugly evil hack, since we end up passing in record = {0, 0, sizeof() */ + OPERATION_LHREMOVE, + (Function)&_lHtInsert + }; + return o; + +} + +Operation getLHRemove() { + Operation o = { + OPERATION_LHREMOVE, + SIZEOF_RECORD, /* use the size of the record as size of arg (nasty, ugly evil hack.) */ + OPERATION_LHINSERT, + (Function)&_lHtRemove + }; + return o; + +} diff --git a/src/lladd/operations/prepare.c b/src/lladd/operations/prepare.c new file mode 100644 index 0000000..5f4adf5 --- /dev/null +++ b/src/lladd/operations/prepare.c @@ -0,0 +1,116 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/********************************************** + * $Id$ + * + * sets the given reference to dat + **********************************************/ + +#include +/*#include "../logger/logstreamer.h"*/ +#include +#include + +recordid prepare_bogus_rec = { 0, 0, 0}; + +static int operate(int xid, recordid rid, const void *dat) { + syncLog(); + return 0; +} +/*static int no_op(int xid, recordid rid, const void *dat) { + return 0; + }*/ + +/** + Tprepare notes: + + - Just a Tupdate, with a log flush as its operationsTable[] + function. (done) + + - After recovery, all of the xacts pages will have been 'stolen', + (if recovery flushes dirty pages) (done) + + - Recovery function needs to distinguish between actions before and + after the last Tprepare log entry. + + - The switch in recovUndo needs to treat Tprepares as follows: + + - If we're really doing recovery, don't push the prevLSN onto + transRecLSN's. Instead, add it to the active transaction table + in transactional.c + + - If not, do nothing, but push the prevLSN onto transRecLSN's + +*/ + +Operation getPrepare() { + Operation o = { + OPERATION_PREPARE, /* id */ + 0, /* No extra data. */ + OPERATION_PREPARE, /*&no_op,*/ /* Otherwise, it will need to store a pre-image of something... */ + &operate /* Function */ + }; + return o; +} + +/** PrepareGuardState is 1 if the iterator should continue on the next + (previous) log entry, 0 otherwise. */ +typedef int PrepareGuardState; + +void * getPrepareGuardState() { + PrepareGuardState * s = malloc (sizeof(PrepareGuardState)); + *s = 1; + return s; +} + + +int prepareGuard(LogEntry * e, void * state) { + PrepareGuardState * pgs = state; + int ret = *pgs; + if(e->type == UPDATELOG) { + if(e->contents.update.funcID == OPERATION_PREPARE) { + *pgs = 0; + } + } + return ret; +} diff --git a/src/lladd/operations/set.c b/src/lladd/operations/set.c new file mode 100644 index 0000000..d79a69c --- /dev/null +++ b/src/lladd/operations/set.c @@ -0,0 +1,63 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************************** + * $Id$ + * + * sets the given reference to dat + **********************************************/ + +#include +#include +static int operate(int xid, recordid rid, const void *dat) { + writeRecord(xid, rid, dat); + return 0; +} + +Operation getSet() { + Operation o = { + OPERATION_SET, /* id */ + SIZEOF_RECORD, /* use the size of the record as size of arg */ + NO_INVERSE, + &operate /* Function */ + }; + return o; +} diff --git a/src/lladd/page.c b/src/lladd/page.c new file mode 100644 index 0000000..805aaa7 --- /dev/null +++ b/src/lladd/page.c @@ -0,0 +1,826 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/************************************************ + * $Id$ + * + * implementation of pages + ************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +/*#include "linkedlist.h"*/ +#include +#include + +/* TODO: Combine with buffer size... */ +static int nextPage = 0; + + +/************************************************************************ + + STRUCTURE OF A PAGE + + +-------------------------------------------+-----------------------+--+ + | DATA SECTION +--------->| RID: (PAGE, 0) | | + | +-----------------+ | +-----------------------+ | + | +-->| RID: (PAGE, 1) | | | + | | +-----------------+ | | + | | | | + | +-----------------+ | +----------------------------+ + | | | +--->| RID: (PAGE, n) | + | | | | +----------------------------+ + |======================================================================| + |^ FREE SPACE | | | | + |+-----------------------|-------|---|--------------------+ | + | | | | | | + | +-------------|-------|---+ | | + | | | | | | + | +---|---+-----+---|---+---|---+--------------+-----|------+-----+ + | | slotn | ... | slot1 | slot0 | num of slots | free space | LSN | + +------+-------+-----+-------+-------+--------------+------------+-----+ + + NOTE: + - slots are zero indexed. + - slots are of implemented as (offset, length) + +************************************************************************/ + +static const byte *slotMemAddr(const byte *memAddr, int slotNum) ; + +/** @todo: Why does only one of the get/set First/Second HalfOfWord take an unsigned int? */ +static int getFirstHalfOfWord(unsigned int *memAddr); +static int getSecondHalfOfWord(int *memAddr); +static void setFirstHalfOfWord(int *memAddr, int value); +static void setSecondHalfOfWord(int *memAddr, int value); + +static int readFreeSpace(byte *memAddr); +static void writeFreeSpace(byte *memAddr, int newOffset); +static int readNumSlots(byte *memAddr); +static void writeNumSlots(byte *memAddr, int numSlots); + +static int getSlotOffset(byte *memAddr, int slot) ; +static int getSlotLength(byte *memAddr, int slot) ; +static void setSlotOffset(byte *memAddr, int slot, int offset) ; +static void setSlotLength(byte *memAddr, int slot, int length) ; + +static int SLOT_OFFSET_SIZE; +static int SLOT_LENGTH_SIZE; +static int SLOT_SIZE; + +static int LSN_SIZE; +static int FREE_SPACE_SIZE; +static int NUMSLOTS_SIZE; + +static int START_OF_LSN; +static int START_OF_FREE_SPACE; +static int START_OF_NUMSLOTS; + +static int MASK_0000FFFF; +static int MASK_FFFF0000; + + +int isValidSlot(byte *memAddr, int slot); +void invalidateSlot(byte *memAddr, int slot); +void pageDeRalloc(Page page, recordid rid); + +void pageCompact(Page page); + +touchedBlob_t *touched; +size_t touchedLen; + + +/** + * pageInit() initializes all the important variables needed in + * all the functions dealing with pages. + */ +void pageInit() { + + nextPage = 0; + /** + * For now, we will assume that slots are 4 bytes long, and that the + * first two bytes are the offset, and the second two bytes are the + * the length. There are some functions at the bottom of this file + * that may be useful later if we decide to dynamically choose + * sizes for offset and length. + */ + + /** + * the largest a slot length can be is the size of the page, + * and the greatest offset at which a record could possibly + * start is at the end of the page + */ + SLOT_LENGTH_SIZE = SLOT_OFFSET_SIZE = 2; /* in bytes */ + SLOT_SIZE = SLOT_OFFSET_SIZE + SLOT_LENGTH_SIZE; + + LSN_SIZE = sizeof(long); + FREE_SPACE_SIZE = NUMSLOTS_SIZE = 2; + + /* START_OF_LSN is the offset in the page to the lsn */ + START_OF_LSN = PAGE_SIZE - LSN_SIZE; + START_OF_FREE_SPACE = START_OF_LSN - FREE_SPACE_SIZE; + START_OF_NUMSLOTS = START_OF_FREE_SPACE - NUMSLOTS_SIZE; + + MASK_0000FFFF = (1 << (2*BITS_PER_BYTE)) - 1; + MASK_FFFF0000 = ~MASK_0000FFFF; + + touchedLen = DEFAULT_TOUCHED; + touched = calloc(touchedLen, sizeof(touchedBlob_t)); + + /* if( (blob_0_fd = open(BLOB0_FILE, O_RDWR, 0)) == -1 ) { + perror("page.c:opening blob file 0"); + exit(-1); + } + if( (blob_1_fd = open(BLOB1_FILE, O_RDWR, 0)) == -1 ) { + perror("page.c:opening blob file 1"); + exit(-1); + } */ + +} + +static void rehashTouch() { + + int i; + touchedBlob_t *touched_old = touched; + touchedLen *= 2; + touched = calloc(touchedLen, sizeof(touchedBlob_t)); + assert(touched); + + for( i = 0; i < touchedLen/2; i++ ) { + if( touched_old[i].records ) { + touched[touched_old[i].xid%touchedLen] = touched_old[i]; + } + } + + free(touched_old); +} + +static int touchBlob(int xid, recordid rid) { + + touchedBlob_t *t = &touched[xid%touchedLen]; + if( t->records ) { + if( t->xid == xid ) { + recordid ret = t->records[(rid.page+rid.slot)%t->len]; + if( ret.size ) { + if( ret.page == rid.page && ret.slot == rid.slot ) { + return 1; + } else { /* there's another entry for this space */ + int i; + recordid *old = t->records; + t->len *= 2; + t->records = calloc(t->len, sizeof(recordid)); + for( i = 0; i < t->len/2; i++ ) { + if( old[i].size ) { + t->records[ (old[i].page+old[i].slot) % t->len ] = old[i]; + } + } + return touchBlob(xid, rid); + } + } else { /* space is free, mark it */ + t->records[(rid.page+rid.slot)%t->len] = rid; + return 0; + } + } else { /* this is not our transaction */ + do { + rehashTouch(); + } while( touchBlob(xid, rid) ); + return 0; + } + } else { /* we haven't allocated for this xid */ + t->records = calloc(DEFAULT_TOUCHED, sizeof(recordid)); + t->records[(rid.page+rid.slot)%DEFAULT_TOUCHED] = rid; + t->len = DEFAULT_TOUCHED; + t->xid = xid; + return 0; + } + + assert(0); + return 0; +} + +static void rmTouch(int xid) { + + touchedBlob_t *t = &touched[xid%touchedLen]; + if( t ) { + free( t->records ); + t->records = NULL; + /* touched[xid%touchedLen].xid = -1; TODO: necessary? */ + } +} + +void pageCommit(int xid) { + rmTouch(xid); +} + +void pageAbort(int xid) { + rmTouch(xid); +} + +/*#define getFirstHalfOfWord(memAddr) (((*(int*)memAddr) >> (2*BITS_PER_BYTE)) & MASK_0000FFFF) */ + +static int getFirstHalfOfWord(unsigned int *memAddr) { + unsigned int word = *memAddr; + word = (word >> (2*BITS_PER_BYTE)); /* & MASK_0000FFFF; */ + return word; +} + + +static int getSecondHalfOfWord(int *memAddr) { + int word = *memAddr; + word = word & MASK_0000FFFF; + return word; +} + + +void setFirstHalfOfWord(int *memAddr, int value){ + int word = *memAddr; + word = word & MASK_0000FFFF; + word = word | (value << (2*BITS_PER_BYTE)); + *memAddr = word; +} + + +void setSecondHalfOfWord(int *memAddr, int value) { + int word = *memAddr;; + word = word & MASK_FFFF0000; + word = word | (value & MASK_0000FFFF); + *memAddr = word; +} + +/** + * slotMemAddr() calculates the memory address of the given slot. It does this + * by going to the end of the page, then walking backwards, past the LSN field + * (LSN_SIZE), past the 'free space' and 'num of slots' fields (NUMSLOTS_SIZE), + * and then past a slotNum slots (slotNum * SLOT_SIZE). + */ +static const byte *slotMemAddr(const byte *memAddr, int slotNum) { + return (memAddr + PAGE_SIZE) - (LSN_SIZE + FREE_SPACE_SIZE + NUMSLOTS_SIZE + ((slotNum+1) * SLOT_SIZE)); +} + +/** + * pageReadLSN() assumes that the page is already loaded in memory. It takes + * as a parameter a Page and returns the LSN that is currently written on that + * page in memory. + */ +long pageReadLSN(Page page) { + return *(long *)(page.memAddr + START_OF_LSN); +} + +/** + * pageWriteLSN() assumes that the page is already loaded in memory. It takes + * as a parameter a Page. The Page struct contains the new LSN and the page + * number to which the new LSN must be written to. + */ +void pageWriteLSN(Page page) { + *(long *)(page.memAddr + START_OF_LSN) = page.LSN; +} + +/** + * freeSpace() assumes that the page is already loaded in memory. It takes + * as a parameter a Page, and returns an estimate of the amount of free space + * available to a new slot on this page. (This is the amount of unused space + * in the page, minus the size of a new slot entry.) This is either exact, + * or an underestimate. + */ +size_t freespace(Page page) { + int space = (slotMemAddr(page.memAddr, readNumSlots(page.memAddr)) - (page.memAddr + readFreeSpace(page.memAddr))); + return (space < 0) ? 0 : space; +} + +/** + * readFreeSpace() assumes that the page is already loaded in memory. It takes + * as a parameter the memory address of the loaded page in memory and returns + * the offset at which the free space section of this page begins. + */ +static int readFreeSpace(byte *memAddr) { + return getSecondHalfOfWord((int*)(memAddr + START_OF_NUMSLOTS)); +} + +/** + * writeFreeSpace() assumes that the page is already loaded in memory. It takes + * as parameters the memory address of the loaded page in memory and a new offset + * in the page that will denote the point at which free space begins. + */ +static void writeFreeSpace(byte *memAddr, int newOffset) { + setSecondHalfOfWord((int*)(memAddr + START_OF_NUMSLOTS), newOffset); +} + +/** + * readNumSlots() assumes that the page is already loaded in memory. It takes + * as a parameter the memory address of the loaded page in memory, and returns + * the memory address at which the free space section of this page begins. + */ +static int readNumSlots(byte *memAddr) { + return getFirstHalfOfWord((unsigned int*)(memAddr + START_OF_NUMSLOTS)); +} + +/** + * writeNumSlots() assumes that the page is already loaded in memory. It takes + * as parameters the memory address of the loaded page in memory and an int + * to which the value of the numSlots field in the page will be set to. + */ +static void writeNumSlots(byte *memAddr, int numSlots) { + setFirstHalfOfWord((int*)(unsigned int*)(memAddr + START_OF_NUMSLOTS), numSlots); +} + +/** + * pageRalloc() assumes that the page is already loaded in memory. It takes + * as parameters a Page and the size in bytes of the new record. pageRalloc() + * returns a recordid representing the newly allocated record. + * + * NOTE: might want to pad records to be multiple of words in length, or, simply + * make sure all records start word aligned, but not necessarily having + * a length that is a multiple of words. (Since Tread(), Twrite() ultimately + * call memcpy(), this shouldn't be an issue) + * + * NOTE: pageRalloc() assumes that the caller already made sure that sufficient + * amount of freespace exists in this page. (REF: freespace()) + */ +recordid pageRalloc(Page page, size_t size) { + int freeSpace = readFreeSpace(page.memAddr); + int numSlots = readNumSlots(page.memAddr); + recordid rid; + + rid.page = page.id; + rid.slot = numSlots; + rid.size = size; + /*int i; */ + + /* Make sure there's enough free space... */ + /* assert (freespace(page) >= (int)size); */ + + /* Reuse an old (invalid) slot entry */ + /* for (i = 0; i < numSlots; i++) { + if (!isValidSlot(page.memAddr, i)) { + rid.slot = i; + break; + } + } + + if (rid.slot == numSlots) {*/ + writeNumSlots(page.memAddr, numSlots+1); + /* }*/ + + setSlotOffset(page.memAddr, rid.slot, freeSpace); + setSlotLength(page.memAddr, rid.slot, rid.size); + writeFreeSpace(page.memAddr, freeSpace + rid.size); + + return rid; +} + + +/** Only used for recovery, to make sure that consistent RID's are created + * on log playback. */ +recordid pageSlotRalloc(Page page, recordid rid) { + int freeSpace = readFreeSpace(page.memAddr); + int numSlots = readNumSlots(page.memAddr); + + /* assert(rid.slot >= numSlots); */ + if(rid.slot >= numSlots) { + + if (freeSpace < rid.size) { + pageCompact(page); + freeSpace = readFreeSpace(page.memAddr); + assert (freeSpace < rid.size); + } + + setSlotOffset(page.memAddr, rid.slot, freeSpace); + setSlotLength(page.memAddr, rid.slot, rid.size); + writeFreeSpace(page.memAddr, freeSpace + rid.size); + } else { + /* assert(rid.size == getSlotLength(page.memAddr, rid.slot)); */ /* Fails. Why? */ + } + return rid; +} + + +int isValidSlot(byte *memAddr, int slot) { + return getSlotOffset(memAddr, slot) != INVALID_SLOT ? 1 : 0; +} + +void invalidateSlot(byte *memAddr, int slot) { + setSlotOffset(memAddr, slot, INVALID_SLOT); +} + + +void pageDeRalloc(Page page, recordid rid) { + invalidateSlot(page.memAddr, rid.slot); +} + +/** + + Move all of the records to the beginning of the page in order to + increase the available free space. + + TODO: If we were supporting multithreaded operation, this routine + would need to pin the pages that it works on. +*/ +void pageCompact(Page page) { + + int i; + byte buffer[PAGE_SIZE]; + /* char *buffer = (char *)malloc(PAGE_SIZE); */ + int freeSpace = 0; + int numSlots = readNumSlots(page.memAddr); + int meta_size = LSN_SIZE + FREE_SPACE_SIZE + NUMSLOTS_SIZE + (SLOT_SIZE*numSlots); + int slot_length; + int last_used_slot = 0; + /* Can't compact in place, slot numbers can come in different orders than + the physical space allocated to them. */ + memcpy(buffer + PAGE_SIZE - meta_size, page.memAddr + PAGE_SIZE - meta_size, meta_size); + + for (i = 0; i < numSlots; i++) { + if (isValidSlot(page.memAddr, i)) { + slot_length = getSlotLength(page.memAddr, i); + memcpy(buffer + freeSpace, page.memAddr + getSlotOffset(page.memAddr, i), slot_length); + setSlotOffset(buffer, i, freeSpace); + freeSpace += slot_length; + last_used_slot = i; + } + } + + if (last_used_slot < numSlots) { + writeNumSlots(buffer, last_used_slot + 1); + } + + memcpy(page.memAddr, buffer, PAGE_SIZE); +} + +/** + * getSlotOffset() assumes that the page is already loaded in memory. It takes + * as parameters the memory address of the page loaded in memory, and a slot + * number. It returns the offset corresponding to that slot. + */ +static int getSlotOffset(byte *memAddr, int slot) { + return getFirstHalfOfWord((unsigned int*)slotMemAddr(memAddr, slot)); +} + +/** + * getSlotLength() assumes that the page is already loaded in memory. It takes + * as parameters the memory address of the page loaded in memory, and a slot + * number. It returns the length corresponding to that slot. + */ +static int getSlotLength(byte *memAddr, int slot) { + return getSecondHalfOfWord((int*)(unsigned int*)slotMemAddr(memAddr, slot)); +} + +/** + * setSlotOffset() assumes that the page is already loaded in memory. It takes + * as parameters the memory address of the page loaded in memory, a slot number, + * and an offset. It sets the offset of the given slot to the offset passed in + * as a parameter. + */ +static void setSlotOffset(byte *memAddr, int slot, int offset) { + setFirstHalfOfWord((int*)slotMemAddr(memAddr, slot), offset); +} + +/** + * setSlotLength() assumes that the page is already loaded in memory. It takes + * as parameters the memory address of the page loaded in memory, a slot number, + * and a length. It sets the length of the given slot to the length passed in + * as a parameter. + */ +static void setSlotLength(byte *memAddr, int slot, int length) { + setSecondHalfOfWord((int*)(unsigned int*)slotMemAddr(memAddr, slot), length); +} + +int isBlobSlot(byte *pageMemAddr, int slot) { + return BLOB_SLOT == getSlotLength(pageMemAddr, slot); +} + +/** + Blob format: + + If the slot entry's size is BLOB_SLOT, then the slot points to a blob record instead of data. The format of this record is: + + Int: Version number (0/1) + Int: Archive offset + Int: Blob size. + + TODO: BufferManager should pass in file descriptors so that this function doesn't have to open and close the file on each call. + +*/ +void pageReadRecord(int xid, Page page, recordid rid, byte *buff) { + byte *recAddress = page.memAddr + getSlotOffset(page.memAddr, rid.slot); + + /*look at record, if slot offset == blob_slot, then its a blob, else its normal. */ + if(isBlobSlot(page.memAddr, rid.slot)) { + int fd = -1; + int version; + int offset; + int length; + + version = *(int *)recAddress; + offset = *(int *)(recAddress + 4); + length = *(int *)(recAddress + 8); + + fd = version == 0 ? blobfd0 : blobfd1; + + /* if( (fd = open(version == 0 ? BLOB0_FILE : BLOB1_FILE, O_RDWR, 0)) == -1 ) { + printf("page.c:pageReadRecord error and exiting\n"); + exit(-1); + } */ + lseek(fd, offset, SEEK_SET); + read(fd, buff, length); + /* close(fd); */ + } else { + int size = getSecondHalfOfWord((int*)slotMemAddr(page.memAddr, rid.slot)); + + memcpy(buff, recAddress, size); + } +} + +void pageWriteRecord(int xid, Page page, recordid rid, const byte *data) { + byte *rec; + int version = -1; + int fd = -1; + int blobRec[3]; + + if (isBlobSlot(page.memAddr, rid.slot)) { + /* TODO: Rusty's wild guess as to what's supposed to happen. Touch blob appears to lookup the blob, + and allocate it if its not there. It returns 0 if it's a new blob, 1 otherwise, so I think we + just ignore its return value...*/ + + if( !touchBlob(xid, rid) ) { + /* record hasn't been touched yet */ + rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot); + version = *(int *)rec; + blobRec[0] = version == 0 ? 1 : 0; + blobRec[1] = *(int *)(rec + 4); + blobRec[2] = *(int *)(rec + 8); + memcpy(rec, blobRec, BLOB_REC_SIZE); + + } else { + rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot); + } + + fd = version == 0 ? blobfd0 : blobfd1; + + if(-1 == lseek(fd, *(int *)(rec +4), SEEK_SET)) { + perror("lseek"); + } + if(-1 == write(fd, data, *(int *)(rec +8))) { + perror("write"); + } + + /* Flush kernel buffers to hard drive. TODO: the + (standard) fdatasync() call only flushes the data + instead of the data + metadata. Need to have + makefile figure out if it's available, and do some + macro magic in order to use it, if possible... + + This is no longer called here, since it is called at commit. + */ + /* fsync(fd); */ + } else { /* write a record that is not a blob */ + rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot); + + if(memcpy(rec, data, rid.size) == NULL ) { + printf("ERROR: MEM_WRITE_ERROR on %s line %d", __FILE__, __LINE__); + exit(MEM_WRITE_ERROR); + } + } +} + + +/* Currently not called any where, or tested. */ +byte * pageMMapRecord(int xid, Page page, recordid rid) { + byte *rec; + int version = -1; + int fd = -1; + int blobRec[3]; + byte * ret; + if (isBlobSlot(page.memAddr, rid.slot)) { + /* TODO: Rusty's wild guess as to what's supposed to happen. Touch blob appears to lookup the blob, + and allocate it if its not there. It returns 0 if it's a new blob, 1 otherwise, so I think we + just ignore its return value...*/ + + if( !touchBlob(xid, rid) ) { + /* record hasn't been touched yet */ + rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot); + version = *(int *)rec; + blobRec[0] = version == 0 ? 1 : 0; + blobRec[1] = *(int *)(rec + 4); + blobRec[2] = *(int *)(rec + 8); + memcpy(rec, blobRec, BLOB_REC_SIZE); + + } else { + rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot); + } + + fd = version == 0 ? blobfd0 : blobfd1; + + if((ret = mmap((byte*) 0, *(int *)(rec +8), (PROT_READ | PROT_WRITE), MAP_SHARED, fd, *(int *)(rec +4))) == (byte*)-1) { + perror("pageMMapRecord"); + } + + /* if(-1 == lseek(fd, *(int *)(rec +4), SEEK_SET)) { + perror("lseek"); + } + if(-1 == write(fd, data, *(int *)(rec +8))) { + perror("write"); + } */ + + /* Flush kernel buffers to hard drive. TODO: the + (standard) fdatasync() call only flushes the data + instead of the data + metadata. Need to have + makefile figure out if it's available, and do some + macro magic in order to use it, if possible...*/ + /* fsync(fd); */ + + } else { /* write a record that is not a blob */ + rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot); + + ret = rec; + /* if(memcpy(rec, data, rid.size) == NULL ) { + printf("ERROR: MEM_WRITE_ERROR on %s line %d", __FILE__, __LINE__); + exit(MEM_WRITE_ERROR); + }*/ + } + return ret; +} + +void pageRealloc(Page *p, int id) { + p->id = id; + p->LSN = 0; + p->dirty = 0; +} + +Page pool[MAX_BUFFER_SIZE]; + +/** + Allocate a new page. + @param id The id of the new page. + @return A pointer to the new page. This memory is part of a pool, + and should not be freed by the application. + */ +Page *pageAlloc(int id) { + Page *p = &(pool[nextPage]); + nextPage++; + assert(nextPage <= MAX_BUFFER_SIZE); + /* + Page *p = (Page*)malloc(sizeof(Page));*/ /* freed in bufDeinit */ + /* assert(p); */ + pageRealloc(p, id); + return p; +} + +void printPage(byte *memAddr) { + int i = 0; + for (i = 0; i < PAGE_SIZE; i++) { + if((*(char *)(memAddr+i)) == 0) { + printf("#"); + }else { + printf("%c", *(char *)(memAddr+i)); + } + if((i+1)%4 == 0) + printf(" "); + } +} + +#define num 20 +int pageTest() { + + Page page; + + recordid rid[num]; + char *str[num] = {"one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", + "eighteen", + "nineteen", + "twenty"}; + int i; + + page.memAddr = (byte *)malloc(PAGE_SIZE); + memset(page.memAddr, 0, PAGE_SIZE); + for (i = 0; i < num; i++) { + rid[i] = pageRalloc(page, strlen(str[i]) + 1); + pageWriteRecord(0, page, rid[i], (byte*)str[i]); + } + printPage(page.memAddr); + + for (i = 0; i < num; i+= 2) + pageDeRalloc(page, rid[i]); + + pageCompact(page); + printf("\n\n\n"); + printPage(page.memAddr); + return 0; +} + +/** + * + */ +recordid pageBalloc(Page page, int size, int fileOffset) { + int freeSpace = readFreeSpace(page.memAddr); + int numSlots = readNumSlots(page.memAddr); + recordid rid; + + int i; + + rid.page = page.id; + rid.slot = numSlots; + rid.size = size; + + if (freespace(page) < BLOB_REC_SIZE) { + printf("Error in pageRalloc()\n"); + exit(-1); + } + + for (i = 0; i < numSlots; i++) { + if (!isValidSlot(page.memAddr, i)) { + rid.slot = i; + break; + } + } + + if (rid.slot == numSlots) { + writeNumSlots(page.memAddr, numSlots+1); + } + + setSlotOffset(page.memAddr, rid.slot, freeSpace); + setSlotLength(page.memAddr, rid.slot, BLOB_SLOT); + writeFreeSpace(page.memAddr, freeSpace + BLOB_REC_SIZE); + + + *(int *)(page.memAddr + freeSpace) = 0; + *(int *)(page.memAddr + freeSpace + 4) = fileOffset; + *(int *)(page.memAddr + freeSpace + 8) = size; + + return rid; +} + +int getBlobOffset(int page, int slot) { +printf("Error: not yet implemented!!\n"); +exit(-1); +} + +int getBlobSize(int page, int slot) { +printf("Error: not yet implemented!!\n"); +exit(-1); +} + diff --git a/src/lladd/recovery.c b/src/lladd/recovery.c new file mode 100644 index 0000000..41581d2 --- /dev/null +++ b/src/lladd/recovery.c @@ -0,0 +1,460 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/***************** + * @file + * $Id$ + * + * Implements recovery for a NO STEAL system -- we won't need any undo functions, CLRs, or to redo any aborted/uncommitted transactions + * + * @deprecated + * @see recovery2.c + * *************/ + +#include + +#include "recovery.h" +#include +#include +#include "linkedlist.h" +#include +#include "logger/logparser.h" +#include "logger/logstreamer.h" +#include +#include +#include +#include +/* just set an arbitrary recovery xid */ +#define RECOVERY_XID 69 +/* moved from recovery.h, sice this is the only file that uses it. */ + +static void undoUpdateRec(CommonLog cl, UpdateLog ul); + + + +/* map from page number to the recLSN that dirtied it */ +static pblHashTable_t *dirtyPages; +/* sorted list of recLSNs of active transactiosn */ + +static LinkedListPtr transRecLSNs=NULL; + +/* map from transID to status of the transaction: U (to be undone), or not in + * there, or committed but not ended (C) + * */ +static pblHashTable_t *transTable; + +/* the LSN of the dirty page with the smallest corresponding LSN */ +static long minDirtyLSN; + + +void undoUpdateRec(CommonLog cl, UpdateLog ul) { + int undoIndex = operationsTable[ul.funcID].undo; + long CLRLSN; + CLRLSN = LogCLR(-1, cl.xid, cl.LSN, ul.rid, cl.prevLSN); + /*printf ("Undoing LSN=%ld (and writing new pageLSN=%ld\n", cl.LSN, CLRLSN); */ + if (undoIndex==NO_INVERSE) + writeRecord(RECOVERY_XID, ul.rid, ul.preImage); /*if there's no inverse we directly write the preimage to the record*/ + else operationsTable[undoIndex].run(RECOVERY_XID, ul.rid, ul.args); + writeLSN(CLRLSN, ul.rid.page); +} +/** + * Do this CLR action, and return the undoNextLSN listed in this clrlog + */ +/*static long DoCLRAction(CLRLog clrlog) { + UpdateLog ul; + CommonLog commonLog = readCommonLogFromLSN(clrlog.thisUpdateLSN); + if (commonLog.type!=UPDATELOG) { + printf ("Don't know how to undo a non-update log (LSN=%ld)! Aborting undo...\n", commonLog.LSN); + return -1; + } + ul = updateStringToParts(commonLog.extraData); + undoUpdate(commonLog, ul); + return clrlog.undoNextLSN; + }*/ + +/** + * Redo this clrlog, and it doesn't write out any CLR for the CLR. For now copy + * and pasted form undoUpdate, make it cleaner in the future. + */ +static void RedoCLRAction(CLRLog clrlog) { + int undoIndex; + UpdateLog ul; + CommonLog commonLog = readCommonLogFromLSN(clrlog.thisUpdateLSN); + if (commonLog.type!=UPDATELOG) { + printf ("Don't know how to undo a non-update log (LSN=%ld)! Aborting undo...\n", commonLog.LSN); + return; + } + ul = updateStringToParts(commonLog.extraData); + undoIndex = operationsTable[ul.funcID].undo; + printf ("ReUndoing LSN=%ld\n", commonLog.LSN); + if (undoIndex==NO_INVERSE) + writeRecord(RECOVERY_XID, ul.rid, ul.preImage); /*if there's no inverse we directly write the preimage to the record*/ + else operationsTable[undoIndex].run(RECOVERY_XID, ul.rid, ul.args); + writeLSN(commonLog.LSN, clrlog.rid.page); +} +static void recovInit() { + /* startLogStream(); */ /* This is now called after Tinit() opens the log (to support Tprepare, and to fix the reused XID bug) */ + dirtyPages = pblHtCreate(); + transTable = pblHtCreate(); + +} +/* + loadCheckPoint scans the log from the end to find the most recent checkpoint + loads the dirty page table from the checkpoint + set the lsn to start to be one after the end_checkpoint log **check this-i think it should be one after begin_checkpoint + if there are no checkpoints, LSN starts is 0 + */ +static void loadCheckPoint (long *endCheckptLSN) { + /*for now just assume no checkpoints + therefore committedtrans table and DPT are empty + start recovery at LSN 0 */ + *endCheckptLSN = 1; +} + +/* + At end of recovery, wrap up -- + delete the committed transaction list + + possibly in the future: delete the log file + */ +static void CleanUp() { + /* void *trans; */ + destroyList(transRecLSNs); + transRecLSNs = 0; + /*any pages that were dirty should be flushed to disk and then the + corresponding transaction ended */ + /*flushAllPages(); */ + /*trans = pblHtFirst(transTable); + while (trans!=NULL) { + LogEnd(-1, *(int *)pblHtCurrentKey(transTable)); + trans = pblHtNext(transTable); + }*/ + pblHtDelete(dirtyPages); + pblHtDelete(transTable); + flushLog(); + /* closeLogStream(); */ + bufTransCommit(RECOVERY_XID); /*What is this? */ +} + +/* + Returns true ifa page must be redone + loads the page into loadedPage if it needs to be redone + */ +static int MustBeRedone(long entryLSN, int page, Page *loadedPage) { + /* if this log entry's page is dirty */ + long tmp; + long *recLSN = pblHtLookup(dirtyPages, &page, sizeof(int)); + if (recLSN!=NULL) { + /*unmalloc this entry in the table, don't need it anymore */ + tmp = *recLSN; + /* if the log entry's LSN is less than the recLSN of the dirty page */ + if (entryLSN <= tmp) { + /*load page into memory, if the log's LSN is greater than (more recent) the LSN of that actual page (as it was on disk) */ + *loadedPage = loadPage(page); + if (entryLSN > readLSN(page)) + return 1; + } + } + return 0; +} + +/* + Given a page number and the log's LSN, analyze the page, aka + look it up in the dirty page table and add it if it's not there, and + have the table reflect the most recent LSN + + also keeps track of the smallest dirty LSN + */ +static void analyzePage(int page, long curLSN) { + long *LSNCopy; + /*add page to the dirty page table if not there already with recLSN equal to this LSN */ + long *oldLSN = pblHtLookup(dirtyPages, &page, sizeof(int)); + if (oldLSN==NULL) { + /*make a new entry */ + LSNCopy = (long *)malloc(sizeof(long)); + *LSNCopy = curLSN; + pblHtInsert( dirtyPages, &page, sizeof(int), LSNCopy); + } else { + /*update the old entry to have the most recent LSN */ + *oldLSN = curLSN; + } + /*if it's the smallest dirty LSN, make note of it */ + if (minDirtyLSN==-1 || curLSN < minDirtyLSN) + minDirtyLSN = curLSN; +} + +/** + * Analysis is the first phase: + * 1) determines the point in the log at which to start the Redo pass + * 2) determines (a conservative superset of the) pages in the buffer pool + * that were dirty at the time of the crash + * + * At the end of Analysis, transaction table contains accurate list of all + * transactions that were active at the time of the crash, and dirty page table + * includes all pages that were dirty ta time of crash (plus maybe some that + * were written to disk) + */ +static void RecovAnalysis () { + long curLSN, *thisTLSN; + int highestXid = -1; + CommonLog logEntry; + UpdateLog ul; + recordid thisRid; + CLRLog clrlog; + char *status; + pblHashTable_t *transMaxLSN = pblHtCreate(); + minDirtyLSN = -1; + loadCheckPoint(&curLSN); /*sets DPT, AT and the current LSN to the last checkpoint if there is on */ + /*scan through the log until the end*/ + logEntry = readCommonLogFromLSN(curLSN); + while (logEntry.valid==1) { + if(highestXid < logEntry.xid) { + highestXid = logEntry.xid; + } + if ((status = (char *)pblHtLookup(transTable, &logEntry.xid, sizeof(int)))==NULL) { + status = malloc(sizeof(char)); + *status = 'U'; /*default is to be undone */ + pblHtInsert(transTable, &logEntry.xid, sizeof(int), status); + } + if ((thisTLSN = (long *)pblHtLookup(transMaxLSN, &logEntry.xid, sizeof(int))) != NULL) { + removeVal(&transRecLSNs, *thisTLSN); /*it's not the max anymore -- will add another val in later */ + } + else { + thisTLSN = (long *)malloc(sizeof(long)); + *thisTLSN = -1; + pblHtInsert(transMaxLSN, &logEntry.xid, sizeof(int), thisTLSN); + } + curLSN = logEntry.LSN; + switch(logEntry.type) { + case XCOMMIT: + *status = 'C'; + break; + case XEND: + pblHtRemove(transTable, &logEntry.xid, sizeof(int)); /*not a transaction anymore, remove it from the transaction table */ + pblHtRemove(transMaxLSN, &logEntry.xid, sizeof(int)); + break; + case UPDATELOG: + /*determine what page it modified*/ + ul = updateStringToParts(logEntry.extraData); + analyzePage(ul.rid.page, logEntry.LSN); + free(logEntry.extraData); + /*removeVal(&transRecLSNs, *thisTLSN);*/ + addSortedVal(&transRecLSNs, logEntry.LSN); + *thisTLSN = logEntry.LSN; + break; + case XALLOC: + thisRid = allocStringToRID(logEntry.extraData); + analyzePage(thisRid.page, logEntry.LSN); + free(logEntry.extraData); + /*removeVal(&transRecLSNs, *thisTLSN); */ + addSortedVal(&transRecLSNs, logEntry.LSN); + *thisTLSN = logEntry.LSN; + break; + case CLRLOG: + clrlog = CLRStringToParts(logEntry.extraData); + analyzePage(clrlog.rid.page, logEntry.LSN); + addSortedVal(&transRecLSNs, logEntry.LSN); + *thisTLSN = logEntry.LSN; + break; + } + /*printList(transRecLSNs); */ + logEntry = readNextCommonLog(); + } + TsetXIDCount(highestXid); + pblHtDelete(transMaxLSN); +} + +/** + * Redo applies updates of all committed transactions if they haven't been flushed to disk yet + * + */ +static void RecovRedo () { + long curLSN = minDirtyLSN; /* start with smallest recLSN in dirty page table */ + UpdateLog ul; + /* long *recLSN, */ + long nextLSN; + Page loadedPage; + CLRLog clrlog; + recordid rec; + int i; + CommonLog logEntry; + /* starting from there, scan forward until end of log */ + logEntry = readCommonLogFromLSN(curLSN); + while (logEntry.valid!=0) { + /*for each redoable log record, check whether logged action must be redone - redoable actions are update logs/alloc logs and must be a committed transaction*/ + if (pblHtLookup(transTable, &logEntry.xid, sizeof(int))!=NULL) { + switch (logEntry.type) { /*only look at redoable log entries */ + case UPDATELOG: + ul = updateStringToParts(logEntry.extraData); + + if (MustBeRedone(logEntry.LSN, ul.rid.page, &loadedPage)==1) { + /*reapply logged action, AND set LSN on page to the LSN of the redone log record, flush to disk(?) + note that this is going around logging (which is done in transactional) so this will be unlogged*/ + printf ("redoing op %d at LSN=%ld (>%ld), rid (page, slot, size)=%d,%d,%d. args (length %d)=", ul.funcID, logEntry.LSN, loadedPage.LSN, ul.rid.page, ul.rid.slot, ul.rid.size, ul.argSize); + for (i=0; i%ld), rid=%d,%d,%ld...", logEntry.LSN, loadedPage.LSN, clrlog.rid.page, clrlog.rid.slot, (long int)clrlog.rid.size); + nextLSN = streamPos(); + RedoCLRAction(clrlog); + seekInLog(nextLSN); + writeLSN(logEntry.LSN, clrlog.rid.page); + } + break; + } /* switch*/ + } /* committed trans IF */ + if (logEntry.extraData) + free(logEntry.extraData); + logEntry = readNextCommonLog(); + } /* while */ +} + +/** + * Looking at the set of lastLSN values for all 'loser' (non ending) + * transactions, pick the most recent LSN, undo it (if it is an update log) and + * add in prevLSN to the set of to be looked at LSNs, or add undoNextLSN if it + * is a CLR log + */ +static void RecovUndo(int recovering) { + long LSNToLookAt; + CommonLog comLog; + UpdateLog ul; + CLRLog clrlog; + recordid rec; + Page loadedPage; + while (transRecLSNs!=NULL) { + LSNToLookAt = popMaxVal(&transRecLSNs); + comLog = readCommonLogFromLSN(LSNToLookAt); + switch (comLog.type) { + case UPDATELOG: + ul = updateStringToParts(comLog.extraData); + undoUpdateRec(comLog, ul); + if ((ul.funcID != OPERATION_PREPARE) || + (!recovering)) { + if (comLog.prevLSN>0) /*0 or -1 are invalid LSNs*/ + addSortedVal(&transRecLSNs, comLog.prevLSN); + /*else LogEnd(-1, comLog.xid);*/ + } else if (ul.funcID == OPERATION_PREPARE) { + /* TODO: Ugly! */ + printf("Reviving XID: %d\n", comLog.xid); + Trevive(comLog.xid, LSNToLookAt); + } else { + printf("EEK!\n"); + } + /*else LogEnd(-1, comLog.xid);*/ + break; + case CLRLOG: + clrlog = CLRStringToParts(comLog.extraData); + if (clrlog.undoNextLSN>0) + addSortedVal(&transRecLSNs, clrlog.undoNextLSN); + /*else LogEnd(-1, comLog.xid);*/ + break; + case XALLOC: + rec = allocStringToRID(comLog.extraData); + + loadedPage = loadPage(rec.page); + printf ("NOT undoing record allocation at LSN=%ld: rid=%d,%d,%ld where pageid=%d.\n", comLog.LSN, rec.page, rec.slot, (long int)rec.size, loadedPage.id); + /* If page is already in memory (likely), then this just gets a pointer to it. */ + /* The next line is correct, but commented because it causes trouble with LLADD hash. */ + /* pageDeRalloc(loadedPage, rec); */ + if (comLog.prevLSN>0) /*0 or -1 are invalid LSNs*/ + addSortedVal(&transRecLSNs, comLog.prevLSN); + break; + default: printf ("Unknown log type to undo (TYPE=%d, XID= %d, LSN=%ld), skipping...\n", comLog.type, comLog.xid, comLog.LSN); + if (comLog.prevLSN>0) + addSortedVal(&transRecLSNs, comLog.prevLSN); + /*else LogEnd(-1, comLog.xid);*/ + break; + } + + } +} + +/** + * because this messes with transRecLSNs, + * should NOT be called by recovery. Call it from + * non-recovery code! + */ +void undoTrans(Transaction t) { + if (transRecLSNs) { + destroyList(transRecLSNs); + } + transRecLSNs = 0; + if(t.LSN > 0) { + addSortedVal(&transRecLSNs, t.LSN); + } else { + /* printf ("Nothing to undo for xid %d\n", t.xid); I think this is normal for the sequence Tbegin, Tread, Tabort -- Rusty */ + } + RecovUndo(0); +} + +void InitiateRecovery () { + recovInit(); + printf ("Analysis\n"); + RecovAnalysis(); + printf ("Redo\n"); + RecovRedo(); + printf ("Undo\n"); + RecovUndo(1); + CleanUp(); +} diff --git a/src/lladd/recovery.h b/src/lladd/recovery.h new file mode 100644 index 0000000..2f6d21c --- /dev/null +++ b/src/lladd/recovery.h @@ -0,0 +1,65 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + @file + + Used to implement recovery. + + @deprecated + @see recovery2.h +*/ + +#ifndef __RECOVERY_H__ +#define __RECOVERY_H__ + +#include "logger/logparser.h" +#include +/* + Initiate the recovery method! + When finished, pages on disk fully reflect all committed transactions in the log +*/ +void InitiateRecovery (); + +void undoTrans(Transaction t); + +#endif diff --git a/src/lladd/recovery2.c b/src/lladd/recovery2.c new file mode 100644 index 0000000..4a962e5 --- /dev/null +++ b/src/lladd/recovery2.c @@ -0,0 +1,270 @@ +/** + + Replacement for recovery.c + + A lot of refactoring has been done to simplify the contents of recovery.c + + Hopefully, this file will be nice and clean. :) + +*/ + +#include +#include "linkedlist.h" +#include +#include +#include +#include + +#include +#include + +/** @todo This include is an artifact of our lack of infrastructure to support log iterator guards. */ +#include + +/** Maps from xid (int) to status: + NULL - Haven't seen XID + U - XID is scheduled for UNDO + C - XID committed, but not ended. (End records are written once + the XID is flushed to disk. They are only written during the + recovery process, and shutdown since LLADD follows a no force + policy.) @todo Implement end records. + + @todo We don't ever read values out of this hash table... could it + be replaced entirely with transactionLSN? + +*/ +/*static pblHashTable_t * transactionStatus; */ +static pblHashTable_t * transactionLSN; +static LinkedListPtr rollbackLSNs = NULL; +/** + Determines which transactions committed, and which need to be redone. + + In the original version, this function also: + - Determined the point in the log at which to start the Redo pass. + - Calculated a list of all dirty pages. + + It no longer does either of these things: + - A checkpointing algorithm could figure out where the redo pass + should begin. (It would then truncate the log at that point.) This + function could be called before analysis if efficiency is a concern. + - We were using the list of dirty pages as an optimization to prevent + the pages from being read later during recovery. Since this function + no longer reads the pages in, there's no longer any reason to build + the list of dirty pages. + +*/ +static void Analysis () { + + LogEntry * e; + + LogHandle lh = getLogHandle(); + + /** After recovery, we need to know what the highest XID in the + log was so that we don't accidentally reuse XID's. This keeps + track of that value. */ + int highestXid = 0; + + /** @todo loadCheckPoint() - Jump forward in the log to the last + checkpoint. (Maybe getLogHandle should do this automatically, + since the log will be truncated on checkpoint anyway.) */ + + while((e = nextInLog(&lh))) { + + lsn_t * xactLSN = (lsn_t*)pblHtLookup(transactionLSN, &(e->xid), sizeof(int)); + /* recordid rid = e->contents.update.rid; */ + + if(highestXid < e->xid) { + highestXid = e->xid; + } + + /** Track LSN's in two data structures: + - map: xid -> max LSN + - sorted list of maxLSN's + */ + + if(xactLSN == NULL) { + xactLSN = malloc(sizeof(lsn_t)); + pblHtInsert(transactionLSN, &(e->xid), sizeof(int), xactLSN); + + } else { + /* We've seen this xact before, and must have put a value in + rollbackLSNs for it. That value is now stale, so remove + it. */ + + DEBUG("Removing %ld\n", *xactLSN); + removeVal(&rollbackLSNs, *xactLSN); + } + + /* Now, rollbackLSNs certainly does not contain an LSN for this + transaction, and *xactLSN points to a value in the hash, so + writing to it updates the hash. This doesn't update the + rollbackLSN data structure, so it doesn't hurt to update this + value for all log entries. */ + + *xactLSN = e->LSN; + + switch(e->type) { + case XCOMMIT: + /* We've removed this XACT's last LSN from the list of LSN's to + be rolled back, so we're done. */ + break; + case XEND: + /* + XEND means this transaction reached stable storage. + Therefore, we can skip redoing any of its operations. (The + timestamps on each page guarantee that the redo phase will + not overwrite this transaction's work with stale data.) + + The redo phase checks for a transaction's presence in + transactionLSN before redoing its actions. Therefore, if + we remove this transaction from the transactionStatus hash, + it will not be redone. + */ + pblHtRemove(transactionLSN, &(e->xid), sizeof(int)); + break; + case UPDATELOG: + case CLRLOG: + /* + If the last record we see for a transaction is an update or clr, + then the transaction must not have committed, so it must need + to be rolled back. + + Add it to the appropriate list + + */ + DEBUG("Adding %ld\n", e->LSN); + + addSortedVal(&rollbackLSNs, e->LSN); + break; + case XABORT: + /* Don't want this XID in the list of rolled back lsn's since + this XACT will be rolled back during redo. */ + break; + + /* case XALLOC: */ /* @todo Don't use XALLOC anymore, dont need it here. */ + /* assert (0); */ + default: + assert (0); + } + free (e); + } + TsetXIDCount(highestXid); +} + +static void Redo() { + LogHandle lh = getLogHandle(); + LogEntry * e; + + while((e = nextInLog(&lh))) { + /* int garbage; */ + /* Check to see if this log entry is part of a transaction that needs to be redone. */ + if(pblHtLookup(transactionLSN, &(e->xid), sizeof(int)) != NULL) { + /* Check to see if this log entry contains an action that needs to be redone. */ + if(e->type == UPDATELOG || + e->type == CLRLOG) { + /* redoOperation checks the page that contains e->rid, so we + don't need to check to see if the page is newer than this + log entry. */ + redoUpdate(e); + } + } + } +} + +static void Undo(int recovery) { + LogHandle lh; + void * prepare_guard_state; + + + /* printf("!"); fflush(NULL); */ + + prepare_guard_state = getPrepareGuardState(); + + while(rollbackLSNs != NULL) { + LogEntry * e; + lsn_t rollback = popMaxVal(&rollbackLSNs); + + DEBUG("Undoing LSN %ld\n", (long int)rollback); + if(recovery) { + /** @todo shouldn't be hardcoded here! */ + lh = getGuardedHandle(rollback, &prepareGuard, prepare_guard_state); + } else { + /** @todo probably want guards that are run during normal operation. */ + lh = getLSNHandle(rollback); + } + e = readLSNEntry(rollback); + /* printf("#"); fflush(NULL); */ + + + /* printf("e->prev_offset: %ld\n", e->prevLSN); + printf("prev_offset: %ld\n", lh.prev_offset); */ + + while((e = previousInTransaction(&lh))) { + lsn_t this_lsn, clr_lsn; + /* printf("."); fflush(NULL); */ + switch(e->type) { + case UPDATELOG: + /* Sanity check. If this fails, we've already undone this + update, or something is wrong with the redo phase. */ + this_lsn= readLSN(e->contents.update.rid.page); + /* printf("1"); fflush(NULL); */ + assert(e->LSN <= this_lsn); + /* printf("1a"); fflush(NULL); */ + + /* Need to log a clr here. */ + + clr_lsn = LogCLR(e); + writeLSN(clr_lsn, e->contents.update.rid.page); + undoUpdate(e); + /* printf("1b"); fflush(NULL); */ + break; + case CLRLOG: + /* Don't need to do anything special to handle CLR's. + Iterator will correctly jump to clr's previous undo record. */ + /* printf("2"); fflush(NULL); */ + break; + /* case XALLOC: */ + /* Don't use xalloc anymore. */ + /*assert(0);*/ + break; + default: + printf ("Unknown log type to undo (TYPE=%d, XID= %d, LSN=%ld), skipping...\n", e->type, e->xid, e->LSN); + break; + } + } + /* printf("$"); fflush(NULL); */ + } + free(prepare_guard_state); +} + +void InitiateRecovery() { + + transactionLSN = pblHtCreate(); + DEBUG("Analysis started\n"); + Analysis(); + DEBUG("Redo started\n"); + Redo(); + DEBUG("Undo started\n"); + Undo(1); + DEBUG("Recovery complete.\n"); + /** @todo Should we manually empty the hash table? */ + pblHtDelete(transactionLSN); + + /** @todo CleanUp(); */ +} + + +void undoTrans(TransactionLog transaction) { + if(rollbackLSNs) { + destroyList(rollbackLSNs); + } + rollbackLSNs = 0; + if(transaction.prevLSN > 0) { + /* printf("scheduling lsn %ld for undo.\n", transaction.prevLSN); */ + addSortedVal(&rollbackLSNs, transaction.prevLSN); + } else { + /* Nothing to undo. (Happens for read-only xacts. */ + } + + Undo(0); +} diff --git a/src/lladd/transactional.c b/src/lladd/transactional.c new file mode 100644 index 0000000..004f5cc --- /dev/null +++ b/src/lladd/transactional.c @@ -0,0 +1,182 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + + +/** + * @file + * $Id$ + * + * implements main interface to tranactional pages + * + * @deprecated + * @see transactional2.c + * ************************************************/ +#include +#include +#include +#include + +#include +#include +#include +#include +#include "recovery.h" + +Transaction XactionTable[MAX_TRANSACTIONS]; +int numActiveXactions = 0; +int xidCount = 0; +#define INVALID_XTABLE_XID -1 + +int Tinit() { + + memset(XactionTable, INVALID_XTABLE_XID, sizeof(Transaction)*MAX_TRANSACTIONS); + operationsTable[OPERATION_SET] = getSet(); + operationsTable[OPERATION_INCREMENT] = getIncrement(); + operationsTable[OPERATION_DECREMENT] = getDecrement(); + operationsTable[OPERATION_PREPARE] = getPrepare(); + operationsTable[OPERATION_LHINSERT] = getLHInsert(); + operationsTable[OPERATION_LHREMOVE] = getLHRemove(); + + + pageInit(); + bufInit(); + logInit(); + + return 0; +} + +int Tbegin() { + + int i, index = 0; + + if( numActiveXactions == MAX_TRANSACTIONS ) + return EXCEED_MAX_TRANSACTIONS; + else + numActiveXactions++; + + for( i = 0; i < MAX_TRANSACTIONS; i++ ) { + xidCount++; + if( XactionTable[xidCount%MAX_TRANSACTIONS].xid == INVALID_XTABLE_XID ) { + index = xidCount%MAX_TRANSACTIONS; + break; + } + } + + assert( i < MAX_TRANSACTIONS ); + + XactionTable[index].xid = xidCount; + XactionTable[index].LSN = LogTransBegin(XactionTable[index]); + + return XactionTable[index].xid; +} + +void Tupdate(int xid, recordid rid, const void *dat, int op) { + assert(numActiveXactions <= MAX_TRANSACTIONS); + writeLSN(XactionTable[xid%MAX_TRANSACTIONS].LSN = LogUpdate(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid, rid, operationsTable[op], dat), rid.page); + operationsTable[op].run(xid, rid, dat); +} + +recordid Talloc(int xid, size_t size) { + recordid ret; + + ret = ralloc(xid, size); + + writeLSN(XactionTable[xid%MAX_TRANSACTIONS].LSN = LogTransAlloc(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid, ret), ret.page); + return ret; +} +void Tread(int xid, recordid rid, void *dat) { + + readRecord(xid, rid, dat); +} + +int Tcommit(int xid) { + + LogTransCommit(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid); + bufTransCommit(xid); /* unlocks pages */ + XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID; + numActiveXactions--; + assert( numActiveXactions >= 0 ); + return 0; +} + +int Tabort(int xid) { + /* should call undoTrans after log trans abort. undoTrans will cause pages to contain CLR values corresponding to */ + undoTrans(XactionTable[xid%MAX_TRANSACTIONS]); + LogTransAbort(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid); + bufTransAbort(xid); + XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID; + numActiveXactions--; + assert( numActiveXactions >= 0 ); + return 0; +} + +int Tdeinit() { + int i; + + for( i = 0; i < MAX_TRANSACTIONS; i++ ) { + if( XactionTable[i].xid != INVALID_XTABLE_XID ) { + Tabort(XactionTable[i].xid); + } + } + assert( numActiveXactions == 0 ); + + bufDeinit(); + logDeinit(); + + return 0; +} + +void Trevive(int xid, long lsn) { + int index = xid % MAX_TRANSACTIONS; + if(XactionTable[index].xid != INVALID_XTABLE_XID) { + printf("Clashing Tprepare()'ed XID's encountered on recovery!!\n"); + exit(-1); + } + XactionTable[index].xid = xid; + XactionTable[index].LSN = lsn; + numActiveXactions++; +} + +void TsetXIDCount(xid) { + xidCount = xid; +} + diff --git a/src/lladd/transactional2.c b/src/lladd/transactional2.c new file mode 100644 index 0000000..4aa6250 --- /dev/null +++ b/src/lladd/transactional2.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include +#include + +TransactionLog XactionTable[MAX_TRANSACTIONS]; +int numActiveXactions = 0; +int xidCount = 0; +#define INVALID_XTABLE_XID -1 + +int Tinit() { + + memset(XactionTable, INVALID_XTABLE_XID, sizeof(TransactionLog)*MAX_TRANSACTIONS); + operationsTable[OPERATION_SET] = getSet(); + operationsTable[OPERATION_INCREMENT] = getIncrement(); + operationsTable[OPERATION_DECREMENT] = getDecrement(); + operationsTable[OPERATION_PREPARE] = getPrepare(); + operationsTable[OPERATION_LHINSERT] = getLHInsert(); + operationsTable[OPERATION_LHREMOVE] = getLHRemove(); + operationsTable[OPERATION_ALLOC] = getAlloc(); + operationsTable[OPERATION_DEALLOC] = getDealloc(); + + pageInit(); + bufInit(); + + openLogWriter(); + + InitiateRecovery(); + /* logInit(); */ + + return 0; +} + + +int Tbegin() { + + int i, index = 0; + + if( numActiveXactions == MAX_TRANSACTIONS ) + return EXCEED_MAX_TRANSACTIONS; + else + numActiveXactions++; + + for( i = 0; i < MAX_TRANSACTIONS; i++ ) { + xidCount++; + if( XactionTable[xidCount%MAX_TRANSACTIONS].xid == INVALID_XTABLE_XID ) { + index = xidCount%MAX_TRANSACTIONS; + break; + } + } + + assert( i < MAX_TRANSACTIONS ); + + XactionTable[index] = LogTransBegin(xidCount); + + return XactionTable[index].xid; +} + +void Tupdate(int xid, recordid rid, const void *dat, int op) { + LogEntry * e; + assert(numActiveXactions <= MAX_TRANSACTIONS); + e = LogUpdate(&XactionTable[xid % MAX_TRANSACTIONS], rid, op, dat); + + assert(XactionTable[xid % MAX_TRANSACTIONS].prevLSN == e->LSN); + + /* printf("e->LSN: %ld\n", e->LSN); */ + + writeLSN(e->LSN, rid.page); + doUpdate(e); +} + +/* @todo what about locking? */ +void Tread(int xid, recordid rid, void * dat) { + readRecord(xid, rid, dat); +} + +int Tcommit(int xid) { + assert(numActiveXactions <= MAX_TRANSACTIONS); + LogTransCommit(&XactionTable[xid % MAX_TRANSACTIONS]); + bufTransCommit(xid); /* unlocks pages */ + XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID; + numActiveXactions--; + assert( numActiveXactions >= 0 ); + return 0; +} + +int Tabort(int xid) { + /* should call undoTrans after log trans abort. undoTrans will cause pages to contain CLR values corresponding to */ + undoTrans(XactionTable[xid%MAX_TRANSACTIONS]); + LogTransAbort(&XactionTable[xid%MAX_TRANSACTIONS]); + bufTransAbort(xid); + XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID; + numActiveXactions--; + assert( numActiveXactions >= 0 ); + return 0; +} + +int Tdeinit() { + int i; + + for( i = 0; i < MAX_TRANSACTIONS; i++ ) { + if( XactionTable[i].xid != INVALID_XTABLE_XID ) { + Tabort(XactionTable[i].xid); + } + } + assert( numActiveXactions == 0 ); + + bufDeinit(); + /* logDeinit(); */ + closeLogWriter(); + + return 0; +} + +void Trevive(int xid, long lsn) { + int index = xid % MAX_TRANSACTIONS; + if(XactionTable[index].xid != INVALID_XTABLE_XID) { + if(xid != XactionTable[index].xid) { + printf("Clashing Tprepare()'ed XID's encountered on recovery!!\n"); + assert(0); + } + assert(XactionTable[index].xid == xid); + assert(XactionTable[index].prevLSN == lsn); + } else { + XactionTable[index].xid = xid; + XactionTable[index].prevLSN = lsn; + numActiveXactions++; + } +} + +void TsetXIDCount(int xid) { + xidCount = xid; +} diff --git a/src/pbl/ISAM0001.TST b/src/pbl/ISAM0001.TST new file mode 100644 index 0000000..107fc98 --- /dev/null +++ b/src/pbl/ISAM0001.TST @@ -0,0 +1,1366 @@ +########################################################################### +## +## PBL - Program Base Library, Copyright 2002 Peter Graf +## +## This file is part of PBL - The Program Base Library. +## PBL is free software. +## +## 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 +## +## For more information on the Program Base Library or Peter Graf, +## please see: http://mission.base.com/. +## +## ISAM file implementation test case, this test case is set up for +## a regression test of the ISAM library, don't change it unless you +## know what you are doing! +## +## Usage: +## +## 1. Build the pbliftst executable. make all +## 2. Create the sub directory isamtest. mkdir isamtest +## 3. Clear the sub directory isamtest. rm imamtest/* +## 4. Run the test frame on this file. pbliftst ISAM0001.TST +## 5. Compare ISAM0001.TST and pbliftst.log diff ISAM0001.TST pbliftst.log +## +## There should be no differences reported, if so your build of the +## PBL library is most likely ok! +## +########################################################################### +## +## Test case 1 - basic test of functionality +## +## Open the file isam file isamtest/0001main with three index files +## 0001key0, 0001dup1 and 0001key2 +## open the file for update, create if necessary +## the index 0001key0 contains unique keys +## the index 0001dup1 can contain duplicate keys, +## ( the test frame allows that because its name contains the string 'dup' ) +## the index 0001key2 contains unique keys +## +## open filename keyfile1,dkeyfile2,... update +## +open isamtest/0001main 0001key0,0001dup1,0001key2 1 +# pblIsamOpen( isamtest/0001main, 3, 1 ) +# ok! +## +## Get the first record according to index 0001key0, should report an error +## +## get index < NEXT | PREV | FIRST | LAST | THIS > +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Delete 100000 records, should report an error +## +## ndelete n +## +ndelete 100000 +# pblIsamDelete( 100000 records ) +# i 0, rc -1, pbl_errno 1041, errno 0 +## +## Insert one record with keys "key1", "key", "key20" and data "data1" +## +## insert ,key1,key2... data +## +insert ,key1,key,key20 data1 +# pblIsamInsert( 1, ,key1,key,key20, 15, data1, 6 ) +# rc 0 +## +## Insert one record with keys "long1", "key", "long1" and 'long' data +## Note the key "key" is a duplicate key +## +insert ,long1,key,long1 1data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +# pblIsamInsert( 1, ,long1,key,long1, 16, 1data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891, 1276 ) +# rc 0 +## +## Insert one record with keys "long2", "key", "long2" and 'long' data +## Note the key "key" is a duplicate key +## +insert ,long2,key,long2 2data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +# pblIsamInsert( 1, ,long2,key,long2, 16, 2data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891, 1276 ) +# rc 0 +## +## Insert more records with long data +## +insert ,long3,key,long3 3data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +# pblIsamInsert( 1, ,long3,key,long3, 16, 3data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891, 1276 ) +# rc 0 +insert ,long4,key,long4 4data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +# pblIsamInsert( 1, ,long4,key,long4, 16, 4data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891, 1276 ) +# rc 0 +## +## Read the datalen of the current record, 'long4' the one just inserted +## +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 1276 +## +## Read the data of the current record, 'long4' the one just inserted +## +readdata +# pblIsamReadData( currentrecord ) +# datalen 1276, data 4data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## read the datalen and the data again +## +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 1276 +readdata +# pblIsamReadData( currentrecord ) +# datalen 1276, data 4data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +## +## Read alphabetically previous record according to index 0001key0 +## changes the current record to 'long3' +## +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 5, key long3 +## +## Read datalen and data of current record, 'long3' +## +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 1276 +readdata +# pblIsamReadData( currentrecord ) +# datalen 1276, data 3data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +## +## Read alphabetically previous record according to index 0001key0 +## changes the current record to 'long2' +## +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 5, key long2 +## +## Read datalen and data of current record, 'long2' +## +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 1276 +readdata +# pblIsamReadData( currentrecord ) +# datalen 1276, data 2data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +## +## Read alphabetically previous record according to index 0001key0 +## changes the current record to 'long1' +## +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 5, key long1 +## +## Read datalen and data of current record, 'long2' +## +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 1276 +readdata +# pblIsamReadData( currentrecord ) +# datalen 1276, data 1data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +## +## Read alphabetically previous record according to index 0001key0 +## changes the current record to 'key1' +## +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key1 +## +## Read datalen and data of current record, 'key1' +## +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 6 +readdata +# pblIsamReadData( currentrecord ) +# datalen 6, data data1 +## +## Read alphabetically previous record according to index 0001key0 +## reports an error, because we are positioned on the first record +## +get 0 PREV +# pblIsamGet( 3, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Read datalen and data of current record, 'key1' +## +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 6 +readdata +# pblIsamReadData( currentrecord ) +# datalen 6, data data1 +## +## Insert a record with an empty value for index 0001key2, +## results in an error, because the index needs unique keys +## and does therefore not allow empty values +## +insert ,key8,key, data1 +# pblIsamInsert( 1, ,key8,key,, 10, data1, 6 ) +# rc -1, pbl_errno 1006, errno 0 +## +## Insert a record with an value "key20" for index 0001key2, +## this should result in an error, because the index needs unique keys +## and the value "key20" was already inserted with the very first insert +## +insert ,key2,key,key20 data1 +# pblIsamInsert( 1, ,key2,key,key20, 15, data1, 6 ) +# rc -1, pbl_errno 1002, errno 0 +## +## Flush all changes made so far +## +flush +# pblIsamFlush( 1 ) +# rc 0 +## +## Insert a record with key values "key2", "key", "key1f" +## +insert ,key2,key,key1f data1 +# pblIsamInsert( 1, ,key2,key,key1f, 15, data1, 6 ) +# rc 0 +## +## Flush all changes made so far +## +flush +# pblIsamFlush( 1 ) +# rc 0 +## +## Read alphabetically first record according to index 0001key0 +## sets the current record to 'key1' +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Delete the current record +## +## Note: This positions the current record to the record that +## was historically inserted after the 'key1' record +## i.e. the 'long1' record +## +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +## +## Get the current record according to index 0001key0 +## should be the 'long1' record, the second record ever inserted! +## +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key long1 +## +## Read alphabetically first record according to index 0001key0 +## this yields the alphabetically smallest key, 'key2' +## and sets the current record to that record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key2 +## +## Delete the current record, 'key2' +## +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +## +## Insert a record with key values "key1", "key", "key20" +## +insert ,key1,key,key20 data1 +# pblIsamInsert( 1, ,key1,key,key20, 15, data1, 6 ) +# rc 0 +## +## Insert a record with key values "key2", "key", "key1f" +## +insert ,key2,key,key1f data1 +# pblIsamInsert( 1, ,key2,key,key1f, 15, data1, 6 ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Update the index 0001key0 of the record to 'key2' instead of 'key1' +## Reports an error because the value 'key2' exists already +## +updatekey 0 key2 +# pblIsamUpdateKey( 0, key2, 4 ) +# rc -1, pbl_errno 1002, errno 0 +## +## Update the index 0001key0 of the record to key to 'key1' +## +updatekey 0 key1 +# pblIsamUpdateKey( 0, key1, 4 ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Update the data of the current record +## +updatedata da +# pblIsamUpdateData( da, 3 ) +# datalen 3 +## +## Update the data of the current record +## +updatedata deta1 +# pblIsamUpdateData( deta1, 6 ) +# datalen 6 +## +## Update the data of the current record +## +updatedata data1 +# pblIsamUpdateData( data1, 6 ) +# datalen 6 +## +## Update index 0001key0 of the current record +## +updatekey 0 key1 +# pblIsamUpdateKey( 0, key1, 4 ) +# rc 0 +## +## Update index 0001key0 of the current record +## +updatekey 0 key11 +# pblIsamUpdateKey( 0, key11, 5 ) +# rc 0 +## +## Update index 0001key0 of the current record +## +updatekey 0 key1 +# pblIsamUpdateKey( 0, key1, 4 ) +# rc 0 +## +## Update index 0001key0 of the current record +## +updatekey 0 key1 +# pblIsamUpdateKey( 0, key1, 4 ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Update the value of the index 0001dup1, allowing duplicates +## +updatekey 1 key +# pblIsamUpdateKey( 1, key, 3 ) +# rc 0 +## +## Update the value of the index 0001dup1, allowing duplicates +## +updatekey 1 key1 +# pblIsamUpdateKey( 1, key1, 4 ) +# rc 0 +## +## Update the value of the index 0001dup1, allowing duplicates +## +updatekey 1 key +# pblIsamUpdateKey( 1, key, 3 ) +# rc 0 +## +## Update the value of the index 0001dup1, allowing duplicates +## +updatekey 1 key +# pblIsamUpdateKey( 1, key, 3 ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Insert some records +## +insert ,key3,key,key1e data1 +# pblIsamInsert( 1, ,key3,key,key1e, 15, data1, 6 ) +# rc 0 +insert ,key4,keya,key1d data1 +# pblIsamInsert( 1, ,key4,keya,key1d, 16, data1, 6 ) +# rc 0 +insert ,key5,keya,key1c data1 +# pblIsamInsert( 1, ,key5,keya,key1c, 16, data1, 6 ) +# rc 0 +insert ,key6,keya,key1b data1 +# pblIsamInsert( 1, ,key6,keya,key1b, 16, data1, 6 ) +# rc 0 +insert ,key7,keya,key1a data1 +# pblIsamInsert( 1, ,key7,keya,key1a, 16, data1, 6 ) +# rc 0 +insert ,key8,keya,key10 data1 +# pblIsamInsert( 1, ,key8,keya,key10, 16, data1, 6 ) +# rc 0 +insert ,key9,key,key19 data1 +# pblIsamInsert( 1, ,key9,key,key19, 15, data1, 6 ) +# rc 0 +insert ,keya,key,key18 data1 +# pblIsamInsert( 1, ,keya,key,key18, 15, data1, 6 ) +# rc 0 +insert ,keyb,key,key17 data1 +# pblIsamInsert( 1, ,keyb,key,key17, 15, data1, 6 ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Read the alphabetically next couple of records according to index 0001key0 +## +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key2 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key3 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key4 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key5 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key6 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key7 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key8 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key9 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key keya +## +## Rollback the transaction, the inserts that happened +## after the transaction started are NOT committed +## +transaction ROLLBACK +# pblIsamCommit( ROLLBACK ) +# rc 1, pbl_errno 0, errno 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Read the alphabetically next couple of records according to index 0001key0 +## +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key2 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 5, key long1 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 5, key long2 +## +## Start another transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Repeat the inserts done during the last transaction +## +insert ,key3,key,key1e data1 +# pblIsamInsert( 1, ,key3,key,key1e, 15, data1, 6 ) +# rc 0 +insert ,key4,keya,key1d data1 +# pblIsamInsert( 1, ,key4,keya,key1d, 16, data1, 6 ) +# rc 0 +insert ,key5,keya,key1c data1 +# pblIsamInsert( 1, ,key5,keya,key1c, 16, data1, 6 ) +# rc 0 +insert ,key6,keya,key1b data1 +# pblIsamInsert( 1, ,key6,keya,key1b, 16, data1, 6 ) +# rc 0 +insert ,key7,keya,key1a data1 +# pblIsamInsert( 1, ,key7,keya,key1a, 16, data1, 6 ) +# rc 0 +insert ,key8,keya,key10 data1 +# pblIsamInsert( 1, ,key8,keya,key10, 16, data1, 6 ) +# rc 0 +insert ,key9,key,key19 data1 +# pblIsamInsert( 1, ,key9,key,key19, 15, data1, 6 ) +# rc 0 +insert ,keya,key,key18 data1 +# pblIsamInsert( 1, ,keya,key,key18, 15, data1, 6 ) +# rc 0 +insert ,keyb,key,key17 data1 +# pblIsamInsert( 1, ,keyb,key,key17, 15, data1, 6 ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Read the alphabetically next couple of records according to index 0001key0 +## +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key2 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key3 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key4 +## +## Commit the transacttion, make the inserts permanent +## +transaction COMMIT +# pblIsamCommit( COMMIT ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Read the alphabetically next couple of records according to index 0001key0 +## +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key2 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key3 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 4, key key4 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read the data of the current record +## +readdata +# pblIsamReadData( currentrecord ) +# datalen 1276, data 4data1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891 +## +## Read alphabetically previous record according to index 0001key0 +## this sets the current record +## +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 5, key long3 +## +## Read the value of the index 0001dup1 of the current record +## +get 1 THIS +# pblIsamGet( 1, 1 ) +# keylen 3, key key +## +## Find a record who's index 0001dup1 value is the biggest value +## that is alphabetically lower than 'keya' +## +find 1 keya LT +# pblIsamFind( LT, keya, 4 ) +# keylen 3, key key +## +## Read the value of the index 0001key0 of the current record +## +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key keyb +## +## Find a record who's index 0001dup1 value is alphabetically equal to 'keya' +## or who's index 0001dup1 value is the biggest value that is alphabetically +## lower than 'keya' +## +find 1 keya LE +# pblIsamFind( LE, keya, 4 ) +# keylen 4, key keya +## +## Read the value of the index 0001key0 of the current record +## +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key4 +## +## Find the first record who's index 0001dup1 value is alphabetically +## equal to 'keya' +## +find 1 keya FI +# pblIsamFind( FI, keya, 4 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key4 +## +## Find any record who's index 0001dup1 value is alphabetically +## equal to 'keya' +## +find 1 keya EQ +# pblIsamFind( EQ, keya, 4 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key4 +find 1 notfound EQ +# pblIsamFind( EQ, notfound, 8 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Find the last record who's index 0001dup1 value is alphabetically +## equal to 'keya' +## +find 1 keya LA +# pblIsamFind( LA, keya, 4 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key8 +## +## Find a record who's index 0001dup1 value is alphabetically equal to 'keya' +## or who's index 0001dup1 value is the smallest value that is alphabetically +## bigger than 'keya' +## +find 1 keya GE +# pblIsamFind( GE, keya, 4 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key8 +## +## Find a record who's index 0001dup1 value is the smallest value +## that is alphabetically bigger than 'keya' +## Reports an error because 'keya' is the biggest value in index 0001dup1 +## +find 1 keya GT +# pblIsamFind( GT, keya, 4 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## loop backward according to index 0001key0 +## +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 5, key long3 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 5, key long2 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 5, key long1 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key keyb +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key keya +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key9 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key8 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key7 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key6 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key5 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key4 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key3 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key2 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 4, key key1 +get 0 PREV +# pblIsamGet( 3, 0 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 PREV +# pblIsamGet( 3, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Loop forwards through the file according to index 0001dup1 +## Read alphabetically first record according to index 0001dup1 +## this sets the current record +## +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 3, key key +## +## Get the index 0001key0 value of the current record +## +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key long1 +## +## +## Read alphabetically next record according to index 0001dup1 +## this sets the current record +## +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +## +## Get the index 0001key0 value of the current record +## +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key long2 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key long3 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key long4 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key1 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key2 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key3 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key9 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key keya +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 3, key key +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key keyb +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key4 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key5 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key6 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key7 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 4, key keya +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key8 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key8 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key8 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 4, key key8 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Delete 1000 records, reports an error after 15 records are deleted +## +ndelete 1000 +# pblIsamDelete( 1000 records ) +# i 15, rc -1, pbl_errno 1041, errno 0 +## +## Read alphabetically last record according to index 0001key0 +## There is no such record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Read alphabetically first record according to index 0001key0 +## There is no such record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Rollback the transaction, do not commit the deletes done above +## +transaction ROLLBACK +# pblIsamCommit( ROLLBACK ) +# rc 1, pbl_errno 0, errno 0 +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 5, key long4 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 4, key key1 +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Delete all records +## +ndelete 1000 +# pblIsamDelete( 1000 records ) +# i 15, rc -1, pbl_errno 1041, errno 0 +## +## Read alphabetically last record according to index 0001key0 +## There is no such record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Read alphabetically first record according to index 0001key0 +## There is no such record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Commit the transaction, make the deletes permanent +## +transaction COMMIT +# pblIsamCommit( COMMIT ) +# rc 0 +## +## Read alphabetically last record according to index 0001key0 +## There is no such record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Read alphabetically first record according to index 0001key0 +## There is no such record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## insert 1000 records, the keys are "key10" to "key1999" for 0001key0, ... +## +ninsert 1000 key1,key2,key3 dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +# pblIsamInsert( 1, ,key10,key20,key30, 18, dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 52 ) +# inserted 1000 records, rc 0 +## +## Read Data of current record +## +readdata +# pblIsamReadData( currentrecord ) +# datalen 52, data dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +## +## Read alphabetically last record according to index 0001key0 +## this sets the current record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 7, key key1999 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 5, key key10 +## +## Rollback the transaction, do not commit the 1000 inserts done above +## +transaction ROLLBACK +# pblIsamCommit( ROLLBACK ) +# rc 1, pbl_errno 0, errno 0 +## +## Read alphabetically last record according to index 0001key0 +## There is no such record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Read alphabetically first record according to index 0001key0 +## There is no such record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Reinsert the 1000 records +## +ninsert 1000 key1,key2,key3 dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +# pblIsamInsert( 1, ,key10,key20,key30, 18, dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 52 ) +# inserted 1000 records, rc 0 +## +## Read last and first record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 7, key key1999 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 5, key key10 +## +## Commit the 1000 inserts +## +transaction COMMIT +# pblIsamCommit( COMMIT ) +# rc 0 +## +## Read last and first record +## +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 7, key key1999 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 5, key key10 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key10 +ndelete 1000 +# pblIsamDelete( 1000 records ) +# deleted 1000 records, rc 0 +## +## Delete 1000 records, +## +flush +# pblIsamFlush( 1 ) +# rc 0 +## +## Close the empty file +## +close +# pblIsamClose( 1 ) +# rc 0 +## +## Open the file again +## +open isamtest/0001main 0001key0,0001dup1,0001key2 1 +# pblIsamOpen( isamtest/0001main, 3, 1 ) +# ok! +## +## insert 10000 records +## +ninsert 10000 loooooooooooooooongkey1,loooooooooooooooongkey2,loooooooooooooooongkey3 dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +# pblIsamInsert( 1, ,loooooooooooooooongkey10,loooooooooooooooongkey20,loooooooooooooooongkey30, 75, dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 134 ) +# inserted 10000 records, rc 0 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 24, key loooooooooooooooongkey10 +readdata +# pblIsamReadData( currentrecord ) +# datalen 134, data dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +## +## Find a record with an index 0001key0 value +## lower than loooooooooooooooongkey12555 +## +find 0 loooooooooooooooongkey12555 LT +# pblIsamFind( LT, loooooooooooooooongkey12555, 27 ) +# keylen 27, key loooooooooooooooongkey12554 +## +## Find a record with an index 0001key0 value +## lower than or equal to loooooooooooooooongkey13666 +## +find 0 loooooooooooooooongkey13666 LE +# pblIsamFind( LE, loooooooooooooooongkey13666, 27 ) +# keylen 27, key loooooooooooooooongkey13666 +## +## Find the first record with an index 0001key0 value +## equal to loooooooooooooooongkey13666 +## +find 0 loooooooooooooooongkey14777 FI +# pblIsamFind( FI, loooooooooooooooongkey14777, 27 ) +# keylen 27, key loooooooooooooooongkey14777 +## +## Find any record with an index 0001key0 value +## equal to loooooooooooooooongkey15888 +## +find 0 loooooooooooooooongkey15888 EQ +# pblIsamFind( EQ, loooooooooooooooongkey15888, 27 ) +# keylen 27, key loooooooooooooooongkey15888 +## +## Find the last record with an index 0001key0 value +## equal to loooooooooooooooongkey16999 +## +find 0 loooooooooooooooongkey16999 LA +# pblIsamFind( LA, loooooooooooooooongkey16999, 27 ) +# keylen 27, key loooooooooooooooongkey16999 +## +## Find a record with an index 0001key0 value +## equal to or bigger than loooooooooooooooongkey17111 +## +find 0 loooooooooooooooongkey17111 GE +# pblIsamFind( GE, loooooooooooooooongkey17111, 27 ) +# keylen 27, key loooooooooooooooongkey17111 +## +## Find a record with an index 0001key0 value +## bigger than loooooooooooooooongkey18222 +## +find 0 loooooooooooooooongkey18222 GT +# pblIsamFind( GT, loooooooooooooooongkey18222, 27 ) +# keylen 27, key loooooooooooooooongkey18223 +## +## Get the next record according to index 0001key0 +## +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 27, key loooooooooooooooongkey18224 +## +## Do some finds on index 0001dup1 +## +find 1 loooooooooooooooongkey22555 LE +# pblIsamFind( LE, loooooooooooooooongkey22555, 27 ) +# keylen 27, key loooooooooooooooongkey22555 +find 1 loooooooooooooooongkey23666 FI +# pblIsamFind( FI, loooooooooooooooongkey23666, 27 ) +# keylen 27, key loooooooooooooooongkey23666 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 27, key loooooooooooooooongkey23667 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 27, key loooooooooooooooongkey23668 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 27, key loooooooooooooooongkey23669 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 26, key loooooooooooooooongkey2367 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 27, key loooooooooooooooongkey23670 +get 1 PREV +# pblIsamGet( 3, 1 ) +# keylen 26, key loooooooooooooooongkey2367 +## +## Do some finds on index 0001key2 +## +find 2 loooooooooooooooongkey32555 LT +# pblIsamFind( LT, loooooooooooooooongkey32555, 27 ) +# keylen 27, key loooooooooooooooongkey32554 +find 2 loooooooooooooooongkey33666 LE +# pblIsamFind( LE, loooooooooooooooongkey33666, 27 ) +# keylen 27, key loooooooooooooooongkey33666 +find 2 loooooooooooooooongkey34777 FI +# pblIsamFind( FI, loooooooooooooooongkey34777, 27 ) +# keylen 27, key loooooooooooooooongkey34777 +find 2 loooooooooooooooongkey35888 EQ +# pblIsamFind( EQ, loooooooooooooooongkey35888, 27 ) +# keylen 27, key loooooooooooooooongkey35888 +find 2 loooooooooooooooongkey36999 LA +# pblIsamFind( LA, loooooooooooooooongkey36999, 27 ) +# keylen 27, key loooooooooooooooongkey36999 +find 2 loooooooooooooooongkey37111 GE +# pblIsamFind( GE, loooooooooooooooongkey37111, 27 ) +# keylen 27, key loooooooooooooooongkey37111 +find 2 loooooooooooooooongkey38222 GT +# pblIsamFind( GT, loooooooooooooooongkey38222, 27 ) +# keylen 27, key loooooooooooooooongkey38223 +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 24, key loooooooooooooooongkey10 +## +## Delete 800 records +## +ndelete 800 +# pblIsamDelete( 800 records ) +# deleted 800 records, rc 0 +readdata +# pblIsamReadData( currentrecord ) +# datalen 134, data dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +## +## Delete 200 records +## +ndelete 200 +# pblIsamDelete( 200 records ) +# deleted 200 records, rc 0 +## +## Read alphabetically first record according to index 0001key0 +## this sets the current record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 27, key loooooooooooooooongkey11000 +## +## Rollback the transaction +## +transaction ROLLBACK +# pblIsamCommit( ROLLBACK ) +# rc 1, pbl_errno 0, errno 0 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 24, key loooooooooooooooongkey10 +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 24, key loooooooooooooooongkey10 +## +## Delete 1000 records +## +ndelete 1000 +# pblIsamDelete( 1000 records ) +# deleted 1000 records, rc 0 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 27, key loooooooooooooooongkey11000 +transaction COMMIT +# pblIsamCommit( COMMIT ) +# rc 0 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 27, key loooooooooooooooongkey11000 +## +## Delete 1000 records +## +ndelete 1000 +# pblIsamDelete( 1000 records ) +# deleted 1000 records, rc 0 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 27, key loooooooooooooooongkey12000 +## +## Delete 8000 records, i.e. all of them +## +ndelete 8000 +# pblIsamDelete( 8000 records ) +# deleted 8000 records, rc 0 +## +## Verify the file is empty now +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +get 1 FIRST +# pblIsamGet( 4, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 2 FIRST +# pblIsamGet( 4, 2 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Close the file +## +close +# pblIsamClose( 1 ) +# rc 0 +quit diff --git a/src/pbl/ISAM0002.TST b/src/pbl/ISAM0002.TST new file mode 100644 index 0000000..e150800 --- /dev/null +++ b/src/pbl/ISAM0002.TST @@ -0,0 +1,177 @@ +########################################################################### +## +## PBL - Program Base Library, Copyright 2002 Peter Graf +## +## This file is part of PBL - The Program Base Library. +## PBL is free software. +## +## 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 +## +## For more information on the Program Base Library or Peter Graf, +## please see: http://mission.base.com/. +## +## ISAM file implementation test case, this test case is set up for +## a regression test of the ISAM library, don't change it unless you +## know what you are doing! +## +## 1. Build the pbliftst executable. make all +## 2. Create the sub directory isamtest. mkdir isamtest +## 3. Clear the sub directory isamtest. rm imamtest/* +## 4. Run the test frame on this file. pbliftst ISAM0002.TST +## 5. Compare ISAM0002.TST and pbliftst.log diff ISAM0002.TST pbliftst.log +## +## There should be no differences reported, if so your build of the +## PBL library is most likely ok! +## +########################################################################### +## +## Test case 2 +## +## Create a file with 200000 records, close and reopen the file +## and then do a lot of record lookup requests +## +open isamtest/0002main 0002key0,0002dup1,0002key2 1 +# pblIsamOpen( isamtest/0002main, 3, 1 ) +# ok! +## +## read the first record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## make sure the file is empty +## +ndelete 250000 +# pblIsamDelete( 250000 records ) +# i 0, rc -1, pbl_errno 1041, errno 0 +## +## Insert a lot of records +## +ninsert 200000 key0,duplicatekey1,loooooooooooooooooooooongerkey2 dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +# pblIsamInsert( 1, ,key00,duplicatekey10,loooooooooooooooooooooongerkey20, 54, dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 61 ) +# inserted 200000 records, rc 0 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 5, key key00 +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 9, key key099999 +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 14, key duplicatekey10 +get 1 LAST +# pblIsamGet( 5, 1 ) +# keylen 18, key duplicatekey199999 +get 2 FIRST +# pblIsamGet( 4, 2 ) +# keylen 32, key loooooooooooooooooooooongerkey20 +get 2 LAST +# pblIsamGet( 5, 2 ) +# keylen 36, key loooooooooooooooooooooongerkey299999 +close +# pblIsamClose( 1 ) +# rc 0 +## +## open the file for reading +## +open isamtest/0002main 0002key0,0002dup1,0002key2 0 +# pblIsamOpen( isamtest/0002main, 3, 0 ) +# ok! +## +## do a lot of finds +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 5, key key00 +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 9, key key099999 +nfind 200000 0 key0 LT +# pblIsamFind( 1, LT, 0, key0, 4 ) +# found 200000 records, rc 0 +nfind 200000 0 key0 LE +# pblIsamFind( 1, LE, 0, key0, 4 ) +# found 200000 records, rc 0 +nfind 200000 0 key0 FI +# pblIsamFind( 1, FI, 0, key0, 4 ) +# found 200000 records, rc 0 +nfind 200000 0 key0 EQ +# pblIsamFind( 1, EQ, 0, key0, 4 ) +# found 200000 records, rc 0 +nfind 200000 0 key0 LA +# pblIsamFind( 1, LA, 0, key0, 4 ) +# found 200000 records, rc 0 +nfind 200000 0 key0 GE +# pblIsamFind( 1, GE, 0, key0, 4 ) +# found 200000 records, rc 0 +nfind 200000 0 key0 GT +# pblIsamFind( 1, GT, 0, key0, 4 ) +# found 200000 records, rc 0 +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 14, key duplicatekey10 +get 1 LAST +# pblIsamGet( 5, 1 ) +# keylen 18, key duplicatekey199999 +nfind 200000 1 duplicatekey1 LT +# pblIsamFind( 1, LT, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +nfind 200000 1 duplicatekey1 LE +# pblIsamFind( 1, LE, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +nfind 200000 1 duplicatekey1 FI +# pblIsamFind( 1, FI, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +nfind 200000 1 duplicatekey1 EQ +# pblIsamFind( 1, EQ, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +nfind 200000 1 duplicatekey1 LA +# pblIsamFind( 1, LA, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +nfind 200000 1 duplicatekey1 GE +# pblIsamFind( 1, GE, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +nfind 200000 1 duplicatekey1 GT +# pblIsamFind( 1, GT, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +get 2 FIRST +# pblIsamGet( 4, 2 ) +# keylen 32, key loooooooooooooooooooooongerkey20 +get 2 LAST +# pblIsamGet( 5, 2 ) +# keylen 36, key loooooooooooooooooooooongerkey299999 +nfind 200000 2 loooooooooooooooooooooongerkey2 LT +# pblIsamFind( 1, LT, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +nfind 200000 2 loooooooooooooooooooooongerkey2 LE +# pblIsamFind( 1, LE, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +nfind 200000 2 loooooooooooooooooooooongerkey2 FI +# pblIsamFind( 1, FI, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +nfind 200000 2 loooooooooooooooooooooongerkey2 EQ +# pblIsamFind( 1, EQ, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +nfind 200000 2 loooooooooooooooooooooongerkey2 LA +# pblIsamFind( 1, LA, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +nfind 200000 2 loooooooooooooooooooooongerkey2 GE +# pblIsamFind( 1, GE, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +nfind 200000 2 loooooooooooooooooooooongerkey2 GT +# pblIsamFind( 1, GT, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +quit diff --git a/src/pbl/ISAM0003.TST b/src/pbl/ISAM0003.TST new file mode 100644 index 0000000..0befeef --- /dev/null +++ b/src/pbl/ISAM0003.TST @@ -0,0 +1,86 @@ +########################################################################### +## +## PBL - Program Base Library, Copyright Peter Graf +## +## This file is part of PBL - The Program Base Library. +## PBL is free software. +## +## 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 +## +## For more information on the Program Base Library or Peter Graf, +## please see: http://mission.base.com/. +## +## ISAM file implementation test case +## +## Usage: +## 1. Build the pbliftst executable. make all +## 2. Create the sub directory isamtest. mkdir isamtest +## 3. Clear the sub directory isamtest. rm imamtest/* +## 4. Run the test frame on ISAM0002.TST pbliftst ISAM0002.TST +## 5. Run the test frame on this file. pbliftst ISAM0003.TST +## 6. Compare ISAM0003.TST and pbliftst.log diff ISAM0003.TST pbliftst.log +## +## There should be no differences reported, if so your build of the +## PBL library is most likely ok! +## +########################################################################### +## +## Test case 3, uses output from test case 2 +## +## Open a big file +## and then do a lot of record lookup requests +## +## open the file for reading +## +open isamtest/0002main 0002key0,0002dup1,0002key2 0 +# pblIsamOpen( isamtest/0002main, 3, 0 ) +# ok! +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 5, key key00 +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 9, key key099999 +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 14, key duplicatekey10 +get 1 LAST +# pblIsamGet( 5, 1 ) +# keylen 18, key duplicatekey199999 +get 2 FIRST +# pblIsamGet( 4, 2 ) +# keylen 32, key loooooooooooooooooooooongerkey20 +get 2 LAST +# pblIsamGet( 5, 2 ) +# keylen 36, key loooooooooooooooooooooongerkey299999 +## +## do a lot of finds +## +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 14, key duplicatekey10 +get 1 LAST +# pblIsamGet( 5, 1 ) +# keylen 18, key duplicatekey199999 +nfind 200000 0 key0 LT +# pblIsamFind( 1, LT, 0, key0, 4 ) +# found 200000 records, rc 0 +nfind 200000 1 duplicatekey1 LT +# pblIsamFind( 1, LT, 1, duplicatekey1, 13 ) +# found 200000 records, rc 0 +nfind 200000 2 loooooooooooooooooooooongerkey2 LT +# pblIsamFind( 1, LT, 2, loooooooooooooooooooooongerkey2, 31 ) +# found 200000 records, rc 0 +quit diff --git a/src/pbl/ISAM0004.TST b/src/pbl/ISAM0004.TST new file mode 100644 index 0000000..e1f0ec7 --- /dev/null +++ b/src/pbl/ISAM0004.TST @@ -0,0 +1,406 @@ +########################################################################### +## +## PBL - Program Base Library, Copyright 2002 Peter Graf +## +## This file is part of PBL - The Program Base Library. +## PBL is free software. +## +## 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 +## +## For more information on the Program Base Library or Peter Graf, +## please see: http://mission.base.com/. +## +## ISAM file implementation test case, this test case is set up for +## a regression test of the ISAM library, don't change it unless you +## know what you are doing! +## +## Usage: +## +## 1. Build the pbliftst executable. make all +## 2. Create the sub directory isamtest. mkdir isamtest +## 3. Clear the sub directory isamtest. rm imamtest/* +## 4. Run the test frame on this file. pbliftst ISAM0004.TST +## 5. Compare ISAM0004.TST and pbliftst.log diff ISAM0004.TST pbliftst.log +## +## there should be no differences reported, if so your build of the +## PBL library is most likely ok! +## +########################################################################### +## +## Test case 4, tests insert, find, get on duplicate keys +## +## Open the file isam file isamtest/0004main with three index files +## 0004key0, 0004dup1 and 0004key2 +## open the file for update, create if necessary +## the index 0004key0 contains unique keys +## the index 0004dup1 can contain duplicate keys, +## ( the test frame allows that because its name contains the string 'dup' ) +## the index 0004key2 contains unique keys +## +## open filename keyfile1,dkeyfile2,... update +## +open isamtest/0004main 0004key0,0004dup1,0004key2 1 +# pblIsamOpen( isamtest/0004main, 3, 1 ) +# ok! +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Get the first record according to index 0004key0, should report an error +## +## get index < NEXT | PREV | FIRST | LAST | THIS > +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Delete 100000 records, should report an error +## +## ndelete n +## +ndelete 100000 +# pblIsamDelete( 100000 records ) +# i 0, rc -1, pbl_errno 1041, errno 0 +ninsert 2000 key0,dup1,key2 data +# pblIsamInsert( 1, ,key00,dup10,key20, 18, data, 5 ) +# inserted 2000 records, rc 0 +## +## Read alphabetically last record according to index 0004dup1 +## Try reading and searching beyond the last record +## +get 1 LAST +# pblIsamGet( 5, 1 ) +# keylen 7, key dup1999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +find 1 dup1999 LA +# pblIsamFind( LA, dup1999, 7 ) +# keylen 7, key dup1999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +find 1 dup1999 GE +# pblIsamFind( GE, dup1999, 7 ) +# keylen 7, key dup1999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +find 1 dup1999 GT +# pblIsamFind( GT, dup1999, 7 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +## +## Read alphabetically first record according to index 0004dup1 +## Try reading and searching beyond the first record +## +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 5, key dup10 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +get 1 PREV +# pblIsamGet( 3, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +find 1 dup10 FI +# pblIsamFind( FI, dup10, 5 ) +# keylen 5, key dup10 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +find 1 dup10 LE +# pblIsamFind( LE, dup10, 5 ) +# keylen 5, key dup10 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +find 1 dup10 LT +# pblIsamFind( LT, dup10, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +## +## Find a record in the middle and read the records surounding it +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 7, key dup1200 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0200 +## +## Test all possible find operations on an inner record +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LE +# pblIsamFind( LE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 EQ +# pblIsamFind( EQ, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 LA +# pblIsamFind( LA, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 GE +# pblIsamFind( GE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 GT +# pblIsamFind( GT, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +## +## Tnsert two records with a duplicate key +## +insert ,key1insert1,dup12,key2insert1 data1 +# pblIsamInsert( 1, ,key1insert1,dup12,key2insert1, 30, data1, 6 ) +# rc 0 +insert ,key1insert2,dup12,key2insert2 data1 +# pblIsamInsert( 1, ,key1insert2,dup12,key2insert2, 30, data1, 6 ) +# rc 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +## +## Test the find operations on the records with duplicate keys +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LE +# pblIsamFind( LE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert1 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +find 1 dup12 EQ +# pblIsamFind( EQ, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 LA +# pblIsamFind( LA, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +find 1 dup12 GE +# pblIsamFind( GE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +find 1 dup12 GT +# pblIsamFind( GT, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +## +## Delete the three records with duplicate key dup150 +## +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert1 +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +## +## Test the find operations on the deleted records with duplicate keys +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LE +# pblIsamFind( LE, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 EQ +# pblIsamFind( EQ, dup12, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LA +# pblIsamFind( LA, dup12, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 GE +# pblIsamFind( GE, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +find 1 dup12 GT +# pblIsamFind( GT, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +## +## Delete 1999 records, i.e. all of them +## +ndelete 1999 +# pblIsamDelete( 1999 records ) +# deleted 1999 records, rc 0 +## +## Verify the file is empty now +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +get 1 FIRST +# pblIsamGet( 4, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 2 FIRST +# pblIsamGet( 4, 2 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Rollback the transaction, the inserts that happened +## after the transaction started are NOT committed +## +transaction ROLLBACK +# pblIsamCommit( ROLLBACK ) +# rc 1, pbl_errno 0, errno 0 +## +## Close the file +## +close +# pblIsamClose( 1 ) +# rc 0 +quit diff --git a/src/pbl/ISAM0005.TST b/src/pbl/ISAM0005.TST new file mode 100644 index 0000000..1cf21b8 --- /dev/null +++ b/src/pbl/ISAM0005.TST @@ -0,0 +1,322 @@ +########################################################################### +## +## PBL - Program Base Library, Copyright Peter Graf +## +## This file is part of PBL - The Program Base Library. +## PBL is free software. +## +## 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 +## +## For more information on the Program Base Library or Peter Graf, +## please see: http://mission.base.com/. +## +## ISAM file implementation test case, this test case is set up for +## a regression test of the ISAM library, don't change it unless you +## know what you are doing! +## +## Usage: +## +## 1. Build the pbliftst executable. make all +## 2. Create the sub directory isamtest. mkdir isamtest +## 3. Clear the sub directory isamtest. rm imamtest/* +## 4. Run the test frame on this file. pbliftst ISAM0005.TST +## 5. Compare ISAM0005.TST and pbliftst.log diff ISAM0005.TST pbliftst.log +## +## There should be no differences reported, if so your build of the +## PBL library is most likely ok! +## +########################################################################### +## +## Test case 5 +## +## Create a file with 2000000 records, +## and then do some lookup requests +## +## !!!!! NOTE !!!! Test needs 700 Megabytes of disc space +## +open isamtest/0005main 0005key0,0005dup1,0005key2 1 +# pblIsamOpen( isamtest/0005main, 3, 1 ) +# ok! +## +## read the first record +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +ndelete 2500000 +# pblIsamDelete( 2500000 records ) +# i 0, rc -1, pbl_errno 1041, errno 0 +## +## Insert a lot of records +## +ninsert 2000000 key0,duplicatekey1,loooooooooooooooooooooongerkey2 dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +# pblIsamInsert( 1, ,key00,duplicatekey10,loooooooooooooooooooooongerkey20, 54, dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 61 ) +# inserted 2000000 records, rc 0 +get -1 FIRST +# pblIsamGet( 4, -1 ) +# keylen 0, key +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 61 +readkey 0 +# pblIsamReadKey( currentrecord, 0 ) +# keylen 5, key key00 +get -1 PREV +# pblIsamGet( 3, -1 ) +# rc -1, pbl_errno 1003, errno 0 +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 61 +readkey 0 +# pblIsamReadKey( currentrecord, 0 ) +# keylen 5, key key00 +get -1 NEXT +# pblIsamGet( 2, -1 ) +# keylen 0, key +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 61 +readkey 0 +# pblIsamReadKey( currentrecord, 0 ) +# keylen 5, key key01 +get -1 THIS +# pblIsamGet( 1, -1 ) +# keylen 0, key +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 61 +readkey 0 +# pblIsamReadKey( currentrecord, 0 ) +# keylen 5, key key01 +get -1 LAST +# pblIsamGet( 5, -1 ) +# keylen 0, key +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 61 +readkey 0 +# pblIsamReadKey( currentrecord, 0 ) +# keylen 11, key key01999999 +get -1 NEXT +# pblIsamGet( 2, -1 ) +# rc -1, pbl_errno 1003, errno 0 +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 61 +readkey 0 +# pblIsamReadKey( currentrecord, 0 ) +# keylen 11, key key01999999 +get -1 PREV +# pblIsamGet( 3, -1 ) +# keylen 0, key +datalen +# pblIsamReadDatalen( currentrecord ) +# datalen 61 +readkey 0 +# pblIsamReadKey( currentrecord, 0 ) +# keylen 11, key key01999998 +get 0 FIRST +# pblIsamGet( 4, 0 ) +# keylen 5, key key00 +get 0 PREV +# pblIsamGet( 3, 0 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 5, key key01 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 6, key key010 +get 0 LAST +# pblIsamGet( 5, 0 ) +# keylen 10, key key0999999 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 10, key key0999998 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 10, key key0999997 +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 14, key duplicatekey10 +get 1 PREV +# pblIsamGet( 3, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 14, key duplicatekey11 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 15, key duplicatekey110 +get 1 LAST +# pblIsamGet( 5, 1 ) +# keylen 19, key duplicatekey1999999 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 1 PREV +# pblIsamGet( 3, 1 ) +# keylen 19, key duplicatekey1999998 +get 1 PREV +# pblIsamGet( 3, 1 ) +# keylen 19, key duplicatekey1999997 +get 2 FIRST +# pblIsamGet( 4, 2 ) +# keylen 32, key loooooooooooooooooooooongerkey20 +get 2 PREV +# pblIsamGet( 3, 2 ) +# rc -1, pbl_errno 1003, errno 0 +get 2 NEXT +# pblIsamGet( 2, 2 ) +# keylen 32, key loooooooooooooooooooooongerkey21 +get 2 NEXT +# pblIsamGet( 2, 2 ) +# keylen 33, key loooooooooooooooooooooongerkey210 +get 2 LAST +# pblIsamGet( 5, 2 ) +# keylen 37, key loooooooooooooooooooooongerkey2999999 +get 2 NEXT +# pblIsamGet( 2, 2 ) +# rc -1, pbl_errno 1003, errno 0 +get 2 PREV +# pblIsamGet( 3, 2 ) +# keylen 37, key loooooooooooooooooooooongerkey2999998 +get 2 PREV +# pblIsamGet( 3, 2 ) +# keylen 37, key loooooooooooooooooooooongerkey2999997 +## +## do some finds in the middle of the file +## +find 0 key02 LT +# pblIsamFind( LT, key02, 5 ) +# keylen 11, key key01999999 +get 0 PREV +# pblIsamGet( 3, 0 ) +# keylen 11, key key01999998 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 11, key key01999999 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 5, key key02 +get 0 NEXT +# pblIsamGet( 2, 0 ) +# keylen 6, key key020 +find 0 key02 LE +# pblIsamFind( LE, key02, 5 ) +# keylen 5, key key02 +find 0 key02 FI +# pblIsamFind( FI, key02, 5 ) +# keylen 5, key key02 +find 0 key02 EQ +# pblIsamFind( EQ, key02, 5 ) +# keylen 5, key key02 +find 0 key02 LA +# pblIsamFind( LA, key02, 5 ) +# keylen 5, key key02 +find 0 key02 GE +# pblIsamFind( GE, key02, 5 ) +# keylen 5, key key02 +find 0 key02 GT +# pblIsamFind( GT, key02, 5 ) +# keylen 6, key key020 +find 1 duplicatekey12 LT +# pblIsamFind( LT, duplicatekey12, 14 ) +# keylen 20, key duplicatekey11999999 +get 1 PREV +# pblIsamGet( 3, 1 ) +# keylen 20, key duplicatekey11999998 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 20, key duplicatekey11999999 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 14, key duplicatekey12 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 15, key duplicatekey120 +find 1 duplicatekey12 LE +# pblIsamFind( LE, duplicatekey12, 14 ) +# keylen 14, key duplicatekey12 +find 1 duplicatekey12 FI +# pblIsamFind( FI, duplicatekey12, 14 ) +# keylen 14, key duplicatekey12 +find 1 duplicatekey12 EQ +# pblIsamFind( EQ, duplicatekey12, 14 ) +# keylen 14, key duplicatekey12 +find 1 duplicatekey12 LA +# pblIsamFind( LA, duplicatekey12, 14 ) +# keylen 14, key duplicatekey12 +find 1 duplicatekey12 GE +# pblIsamFind( GE, duplicatekey12, 14 ) +# keylen 14, key duplicatekey12 +find 1 duplicatekey12 GT +# pblIsamFind( GT, duplicatekey12, 14 ) +# keylen 15, key duplicatekey120 +find 2 loooooooooooooooooooooongerkey22 LT +# pblIsamFind( LT, loooooooooooooooooooooongerkey22, 32 ) +# keylen 38, key loooooooooooooooooooooongerkey21999999 +get 2 PREV +# pblIsamGet( 3, 2 ) +# keylen 38, key loooooooooooooooooooooongerkey21999998 +get 2 NEXT +# pblIsamGet( 2, 2 ) +# keylen 38, key loooooooooooooooooooooongerkey21999999 +get 2 NEXT +# pblIsamGet( 2, 2 ) +# keylen 32, key loooooooooooooooooooooongerkey22 +get 2 NEXT +# pblIsamGet( 2, 2 ) +# keylen 33, key loooooooooooooooooooooongerkey220 +find 2 loooooooooooooooooooooongerkey22 LE +# pblIsamFind( LE, loooooooooooooooooooooongerkey22, 32 ) +# keylen 32, key loooooooooooooooooooooongerkey22 +find 2 loooooooooooooooooooooongerkey22 FI +# pblIsamFind( FI, loooooooooooooooooooooongerkey22, 32 ) +# keylen 32, key loooooooooooooooooooooongerkey22 +find 2 loooooooooooooooooooooongerkey22 EQ +# pblIsamFind( EQ, loooooooooooooooooooooongerkey22, 32 ) +# keylen 32, key loooooooooooooooooooooongerkey22 +find 2 loooooooooooooooooooooongerkey22 LA +# pblIsamFind( LA, loooooooooooooooooooooongerkey22, 32 ) +# keylen 32, key loooooooooooooooooooooongerkey22 +find 2 loooooooooooooooooooooongerkey22 GE +# pblIsamFind( GE, loooooooooooooooooooooongerkey22, 32 ) +# keylen 32, key loooooooooooooooooooooongerkey22 +find 2 loooooooooooooooooooooongerkey22 GT +# pblIsamFind( GT, loooooooooooooooooooooongerkey22, 32 ) +# keylen 33, key loooooooooooooooooooooongerkey220 +## +## More finds at the start of the file +## +find 0 key00 LT +# pblIsamFind( LT, key00, 5 ) +# rc -1, pbl_errno 1003, errno 0 +find 0 key00 LE +# pblIsamFind( LE, key00, 5 ) +# keylen 5, key key00 +find 0 key00 FI +# pblIsamFind( FI, key00, 5 ) +# keylen 5, key key00 +get 0 PREV +# pblIsamGet( 3, 0 ) +# rc -1, pbl_errno 1003, errno 0 +close +# pblIsamClose( 1 ) +# rc 0 +quit diff --git a/src/pbl/Makefile.am b/src/pbl/Makefile.am new file mode 100644 index 0000000..a4dcc65 --- /dev/null +++ b/src/pbl/Makefile.am @@ -0,0 +1,4 @@ +# TODO: Doesn't build the pbl tests.. +lib_LIBRARIES=libpbl.a +libpbl_a_SOURCES=pbl.c pblhash.c pblkf.c pblisam.c jbhash.c +AM_CFLAGS= -g -Wall -pedantic -std=gnu99 diff --git a/src/pbl/README.DOC b/src/pbl/README.DOC new file mode 100644 index 0000000..5b30dc0 --- /dev/null +++ b/src/pbl/README.DOC @@ -0,0 +1,7 @@ + +The documentation for PBL was created with docpp. +The command to create it is: + +docxx -H --dir doc pbl.dxx + + diff --git a/src/pbl/classFooter.inc b/src/pbl/classFooter.inc new file mode 100644 index 0000000..9ed7fff --- /dev/null +++ b/src/pbl/classFooter.inc @@ -0,0 +1,3 @@ +
+Copyright(C) 2003 Peter Graf, this software is distributed under the +GNU Lesser General Public License diff --git a/src/pbl/classHeader.inc b/src/pbl/classHeader.inc new file mode 100644 index 0000000..27819e0 --- /dev/null +++ b/src/pbl/classHeader.inc @@ -0,0 +1,3 @@ +
+

Program Base Library Functions

+
diff --git a/src/pbl/doc/AIntroduction.html b/src/pbl/doc/AIntroduction.html new file mode 100755 index 0000000..8dc7b57 --- /dev/null +++ b/src/pbl/doc/AIntroduction.html @@ -0,0 +1,90 @@ + + + + + #define A: Introduction + + +
+

Program Base Library Functions

+
+ +

#define A: Introduction

+
+PBL is a C library of functions that can be used in a C or C++ project. +PBL is highly portable and compiles warning free on Linux gcc, Windows +Cygwin gcc and Windows Microsoft Visual C++, V 6.0. + +

+

VERSIONS:

+
    +Version 1.00, Thu Sep 5 2002 - initial version +

    +Version 1.01, Fri Nov 1 2002 - improved memory management, see pblkf.c Revision 1.2, 1.3 +

    +Version 1.02, Mit Feb 19 2003 - fixed a bug reported by Csaba Pálos, see pblisam.c Revision 1.2 +

+ +

+

CODE:

+
    +The code of the PBL library includes: +

    +PBL BASE - some base functions, +see pbl_* functions, +

    +PBL HASH - an open source memory hash table implementation, +see pblHt* functions, +

      +Features +
        +
      • random access lookups +
      • sequential access +
      • regression test frame +
      +
    +PBL KEYFILE - an open source key file implementation, +see pblKf* functions, +
      +Features +
        +
      • ultra fast B* tree implementation for random lookups +
      • transaction handling +
      • sequential access methods +
      • embedable small footprint, < 35 Kb +
      • arbitrary size files, up to 4 terrabytes +
      • arbitrary number of records per file, up to 2 ^^ 48 records +
      • duplicate keys +
      • advanced key compression for minimal size B trees +
      • keylength up to 255 bytes +
      • regression test frame +
      +
    +PBL ISAM - an open source ISAM file implementation, +see pblIsam* functions +
      +Features +
        +
      • ultra fast B* tree implementation for random lookups +
      • transaction handling +
      • sequential access methods +
      • embedable small footprint, < 75 Kb +
      • arbitrary size files, up to 4 terrabytes +
      • arbitrary number of records per file, up to 2 ^^ 48 records +
      • duplicate keys and unique keys +
      • advanced key compression for minimal size index files +
      • keylength up to 255 bytes per index +
      • keylength up to 1024 per record +
      • regression test frame +
      +
    +
+
+


+Copyright(C) 2002 Peter Graf, this software is distributed under the +GNU Lesser General Public License +
+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/BFiles.html b/src/pbl/doc/BFiles.html new file mode 100755 index 0000000..c0b0f82 --- /dev/null +++ b/src/pbl/doc/BFiles.html @@ -0,0 +1,53 @@ + + + + + #define B: Files + + +
+

Program Base Library Functions

+
+ +

#define B: Files

+
list of files of component +

+FILES +

    +
  • pbl.h - the include file of the library +
  • pbl.c - source for the base functions +
  • pblhash.c - source file for the +hash functions +
  • pblhttst.c - source file for the +hash function test frame +
  • pblkf.c - source file for the key +file functions +
  • pblkftst.c - source file for the +key file handling test frame +
  • pblisam.c - source file for the isam +file functions +
  • pbliftst.c - source file for the +isam file handling test frame +
  • makefile - a Unix makefile for the +component +
  • pblhttstdeb.dsp - a Microsoft Visual +Studio 6.0 project file for +hash table debug +
  • pblkftstdeb.dsp - a Microsoft +Visual Studio 6.0 project file +for key file debug +
  • pbliftstdeb.dsp - a Microsoft Visual +Studio 6.0 project file for +isam file debug +
  • ISAM0001.LOG - a test case for the +isam file handling test frame +
  • pbl.dxx - the source for this document +
+


+Copyright(C) 2002 Peter Graf, this software is distributed under the +GNU Lesser General Public License +
+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/CErrorcodes.html b/src/pbl/doc/CErrorcodes.html new file mode 100755 index 0000000..1fac71f --- /dev/null +++ b/src/pbl/doc/CErrorcodes.html @@ -0,0 +1,41 @@ + + + + + #define C: Error codes + + +
+

Program Base Library Functions

+
+ +

#define C: Error codes

+
error codes of the pbl library + +

+
Fields:
PBL_ERROR_OUT_OF_MEMORY - out of memory +
PBL_ERROR_EXISTS - record already exists +
PBL_ERROR_NOT_FOUND - record not found +
PBL_ERROR_BAD_FILE - file structure damaged +
PBL_ERROR_PARAM_MODE - parameter mode is not valid +
PBL_ERROR_PARAM_KEY - parameter key is not valid +
PBL_ERROR_PARAM_KEYLEN - parameter keylen is not valid +
PBL_ERROR_PARAM_DATA - parameter data is not valid +
PBL_ERROR_PARAM_DATALEN - parameter datalen is not valid +
PBL_ERROR_PARAM_INDEX - parameter index is not valid +
PBL_ERROR_CREATE - file system create error, see errno +
PBL_ERROR_OPEN - file system open error, see errno +
PBL_ERROR_SEEK - file system seek error, see errno +
PBL_ERROR_READ - file system read error, see errno +
PBL_ERROR_WRITE - file system write error, see errno +
PBL_ERROR_PROGRAM - an internal error in the code, debug it!! +
PBL_ERROR_NOFIT - internal error forcing a block split +
PBL_ERROR_NOT_ALLOWED - file not open for update, operation not allowed +
PBL_ERROR_POSITION - current record is not positioned


+Copyright(C) 2002 Peter Graf, this software is distributed under the +GNU Lesser General Public License +
+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/DDefinitionsforKeyFileParameters.html b/src/pbl/doc/DDefinitionsforKeyFileParameters.html new file mode 100755 index 0000000..f5deb8d --- /dev/null +++ b/src/pbl/doc/DDefinitionsforKeyFileParameters.html @@ -0,0 +1,28 @@ + + + + + #define D: Definitions for Key File Parameters + + +
+

Program Base Library Functions

+
+ +

#define D: Definitions for Key File Parameters

+
DEFINES FOR PARAMETER mode OF pblKfFind() +
+
Fields:
PBLEQ - any record that is equal +
PBLFI - first record that is equal +
PBLLA - last record that is equal +
PBLGE - last equal or first that is greater +
PBLGT - first that is greater +
PBLLE - first equal or last that is smaller +
PBLLT - last that is smaller


+Copyright(C) 2002 Peter Graf, this software is distributed under the +GNU Lesser General Public License +
+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/EDefinitionsforISAMParameters.html b/src/pbl/doc/EDefinitionsforISAMParameters.html new file mode 100755 index 0000000..5f288b4 --- /dev/null +++ b/src/pbl/doc/EDefinitionsforISAMParameters.html @@ -0,0 +1,26 @@ + + + + + #define E: Definitions for ISAM Parameters + + +
+

Program Base Library Functions

+
+ +

#define E: Definitions for ISAM Parameters

+
DEFINES FOR PARAMETER which OF pblIsamGet() +
+
Fields:
PBLTHIS - get key and keylen of current record +
PBLNEXT - get key and keylen of next record +
PBLPREV - get key and keylen of previous record +
PBLFIRST - get key and keylen of first record +
PBLLAST - get key and keylen of last record


+Copyright(C) 2002 Peter Graf, this software is distributed under the +GNU Lesser General Public License +
+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/General.html b/src/pbl/doc/General.html new file mode 100755 index 0000000..d565151 --- /dev/null +++ b/src/pbl/doc/General.html @@ -0,0 +1,19 @@ + + + + + General Bits + + + + +
+
+
+Copyright(C) 2002 Peter Graf, this software is distributed under the +GNU Lesser General Public License +
+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/PBLDATALENGTH.html b/src/pbl/doc/PBLDATALENGTH.html new file mode 100755 index 0000000..d8ba1fd --- /dev/null +++ b/src/pbl/doc/PBLDATALENGTH.html @@ -0,0 +1,25 @@ + + + + + #define PBLDATALENGTH + + +
+

Program Base Library Functions

+
+ +

#define PBLDATALENGTH

maximum data length of data being stored on index blocks of key files,
+ + +
+

Documentation

+
+maximum data length of data being stored on index blocks of key files, +maximum length of data stored with an item on the level 0 block, 1024 +data that is longer is stored on data blocks.
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/PBLKEYLENGTH.html b/src/pbl/doc/PBLKEYLENGTH.html new file mode 100755 index 0000000..26e91f4 --- /dev/null +++ b/src/pbl/doc/PBLKEYLENGTH.html @@ -0,0 +1,24 @@ + + + + + #define PBLKEYLENGTH + + +
+

Program Base Library Functions

+
+ +

#define PBLKEYLENGTH

the maximum length of a key of the key file component,
+ + +
+

Documentation

+
+the maximum length of a key of the key file component, +maximum length of a key, 255 for now
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/PBL_FREE.html b/src/pbl/doc/PBL_FREE.html new file mode 100755 index 0000000..b30b540 --- /dev/null +++ b/src/pbl/doc/PBL_FREE.html @@ -0,0 +1,24 @@ + + + + + #define PBL_FREE + + +
+

Program Base Library Functions

+
+ +

#define PBL_FREE

( ptr )

make free save against NULL pointers,
+ + +
+

Documentation

+
+make free save against NULL pointers, +also the parameter ptr is set to NULL
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/PBL_LIST_.html b/src/pbl/doc/PBL_LIST_.html new file mode 100755 index 0000000..c91a5c4 --- /dev/null +++ b/src/pbl/doc/PBL_LIST_.html @@ -0,0 +1,23 @@ + + + + + #define PBL_LIST_ + + +
+

Program Base Library Functions

+
+ +

#define PBL_LIST_

( Parameters )

macros for linear list handling,
+ + +
+

Documentation

+
+macros for linear list handling,
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/PBL_LIST_APPEND.html b/src/pbl/doc/PBL_LIST_APPEND.html new file mode 100755 index 0000000..7f26e99 --- /dev/null +++ b/src/pbl/doc/PBL_LIST_APPEND.html @@ -0,0 +1,23 @@ + + + + + #define PBL_LIST_APPEND + + +
+

Program Base Library Functions

+
+ +

#define PBL_LIST_APPEND

( HEAD, TAIL, ITEM, NEXT, PREV )

append an element to the end of a linear list
+ + +
+

Documentation

+
+append an element to the end of a linear list
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/PBL_LIST_PUSH.html b/src/pbl/doc/PBL_LIST_PUSH.html new file mode 100755 index 0000000..03705f0 --- /dev/null +++ b/src/pbl/doc/PBL_LIST_PUSH.html @@ -0,0 +1,23 @@ + + + + + #define PBL_LIST_PUSH + + +
+

Program Base Library Functions

+
+ +

#define PBL_LIST_PUSH

( HEAD, TAIL, ITEM, NEXT, PREV )

push an element to the beginning of a linear list
+ + +
+

Documentation

+
+push an element to the beginning of a linear list
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/PBL_LIST_UNLINK.html b/src/pbl/doc/PBL_LIST_UNLINK.html new file mode 100755 index 0000000..d310644 --- /dev/null +++ b/src/pbl/doc/PBL_LIST_UNLINK.html @@ -0,0 +1,23 @@ + + + + + #define PBL_LIST_UNLINK + + +
+

Program Base Library Functions

+
+ +

#define PBL_LIST_UNLINK

( HEAD, TAIL, ITEM, NEXT, PREV )

remove an element from a linear list
+ + +
+

Documentation

+
+remove an element from a linear list
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/gifs.db b/src/pbl/doc/gifs.db new file mode 100755 index 0000000..e69de29 diff --git a/src/pbl/doc/icon1.gif b/src/pbl/doc/icon1.gif new file mode 100755 index 0000000000000000000000000000000000000000..f78f30eb981225beb16035974453af044eaaed3d GIT binary patch literal 326 zcmZ?wbhEHbSJz>XZiWhW+$CxX1K<{@Q;PzA3MW)Hil!>)yLQv z&I+YZWR4Dq0Qrf5 zE!m-=z(Yr>|42iEfdETiOVhyu2Ne$2qlXS;Sjcg9G-()EC{6Ng4B9Bb&hGxWX`zGB ztnbe@Mi#u2t#oD*5s{NGS5Q=P;Sv=Pl~k5hQB-wRQ&*Q#oU7r^r6eV#G~HwQ3KvHP FYXI`hOxged literal 0 HcmV?d00001 diff --git a/src/pbl/doc/icon2.gif b/src/pbl/doc/icon2.gif new file mode 100755 index 0000000000000000000000000000000000000000..6cbe01a831d9c27158ef1ade66cc25446fac9018 GIT binary patch literal 326 zcmZ?wbhEHbvUV_sg0vVRlep zUT#ibUH$CLjP97|8hg8t^_%zaId~E%=;f7aZRKxk>swYjH7c^q#Kc`$*&sZ;+`~Ol zL*3NdE7jE{7APVst6^&DtgCA)C##W~TG-k;MN7*vC@7wR8bI+U3nR!J9S{NX69Zea zLqmawj#U4Vh6DovmcEvzg9Q#M9Ii(X9muedZ+!$E~PkE!<|b>N=j+E$MO{}jttfS DX0}r~ literal 0 HcmV?d00001 diff --git a/src/pbl/doc/index.html b/src/pbl/doc/index.html new file mode 100755 index 0000000..158af71 --- /dev/null +++ b/src/pbl/doc/index.html @@ -0,0 +1,108 @@ +
+

Documentation for PBL

+The Program Base Library +
+ +

Table of Contents

+

General stuff

+ +

Functions

+ +

Variables

+
    +
  • pbl_errno integer value used for returning error codes +
  • pbl_errstr character buffer used for returning error strings +
+

Macros

+
    +
  • PBLDATALENGTH maximum data length of data being stored on index blocks of key files, +
  • PBLKEYLENGTH the maximum length of a key of the key file component, +
  • PBL_FREE make free save against NULL pointers, +
  • PBL_LIST_ macros for linear list handling, +
  • PBL_LIST_APPEND append an element to the end of a linear list +
  • PBL_LIST_PUSH push an element to the beginning of a linear list +
  • PBL_LIST_UNLINK remove an element from a linear list +
  • pblKfFirst set the current record to the first record of the file +
  • pblKfLast set the current record to the last record of the file +
  • pblKfNext set the current record to the next record of the file +
  • pblKfPrev set the current record to the previous record of the file +
  • pblKfThis return the datalen of the current record +
+

Typedefs

+
    +
  • pblHashTable_t the hash table type the pblHt* functions are dealing with, +
  • pblIsamFile_t the ISAM file type the pblIsam* functions are dealing with, +
  • pblKeyFile_t the key file type the pblKf* functions are dealing with, +
+
+Copyright(C) 2002 Peter Graf, this software is distributed under the +GNU Lesser General Public License +
+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHashTable_t.html b/src/pbl/doc/pblHashTable_t.html new file mode 100755 index 0000000..ab1087b --- /dev/null +++ b/src/pbl/doc/pblHashTable_t.html @@ -0,0 +1,24 @@ + + + + + typedef struct pblHashTable_s pblHashTable_t + + +
+

Program Base Library Functions

+
+ +

typedef struct pblHashTable_s pblHashTable_t

the hash table type the pblHt* functions are dealing with,
+ + +
+

Documentation

+
+the hash table type the pblHt* functions are dealing with, +the details of the structure are hidden from the user
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtCreate.html b/src/pbl/doc/pblHtCreate.html new file mode 100755 index 0000000..9c5c0f6 --- /dev/null +++ b/src/pbl/doc/pblHtCreate.html @@ -0,0 +1,26 @@ + + + + + pblHashTable_t* pblHtCreate + + +
+

Program Base Library Functions

+
+ +

pblHashTable_t* pblHtCreate

( void )

create a new hash table
+ + +
+

Documentation

+
+create a new hash table + +

+
Returns:
pblHashTable_t * retptr != NULL: pointer to new hash table +
pblHashTable_t * retptr == NULL: OUT OF MEMORY

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtCurrent.html b/src/pbl/doc/pblHtCurrent.html new file mode 100755 index 0000000..e4d66e4 --- /dev/null +++ b/src/pbl/doc/pblHtCurrent.html @@ -0,0 +1,28 @@ + + + + + void* pblHtCurrent + + +
+

Program Base Library Functions

+
+ +

void* pblHtCurrent

( pblHashTable_t* h )

get data of current key in hash table
+ + +
+

Documentation

+
+get data of current key in hash table + +

+
Parameters:
h - hash table to look in
Returns:
void * retptr != NULL: pointer to data of current item +
void * retptr == NULL: there is no current item in the hash table +
PBL_ERROR_NOT_FOUND: +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtDelete.html b/src/pbl/doc/pblHtDelete.html new file mode 100755 index 0000000..78493ab --- /dev/null +++ b/src/pbl/doc/pblHtDelete.html @@ -0,0 +1,30 @@ + + + + + int pblHtDelete + + +
+

Program Base Library Functions

+
+ +

int pblHtDelete

( pblHashTable_t* h )

delete a hash table
+ + +
+

Documentation

+
+delete a hash table + +

the hash table has to be empty! + +

+
Parameters:
h - hash table to delete
Returns:
int ret == 0: ok +
int ret == -1: an error, see pbl_errno: +
PBL_ERROR_EXISTS: the hash table is not empty +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtFirst.html b/src/pbl/doc/pblHtFirst.html new file mode 100755 index 0000000..d966324 --- /dev/null +++ b/src/pbl/doc/pblHtFirst.html @@ -0,0 +1,40 @@ + + + + + void* pblHtFirst + + +
+

Program Base Library Functions

+
+ +

void* pblHtFirst

( pblHashTable_t* h )

get data of first key in hash table
+ + +
+

Documentation

+
+get data of first key in hash table + +

This call and pblHtNext can be used in order to loop through all items +stored in a hash table. + +

+   Example:
+
+

for( data = pblHtFirst( h ); data; data = pblHtNext( h )) + { + do something with the data pointer + } +

+ +

+
Parameters:
h - hash table to look in
Returns:
void * retptr != NULL: pointer to data of first item +
void * retptr == NULL: the hash table is empty +
PBL_ERROR_NOT_FOUND: +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtInsert.html b/src/pbl/doc/pblHtInsert.html new file mode 100755 index 0000000..6d6e355 --- /dev/null +++ b/src/pbl/doc/pblHtInsert.html @@ -0,0 +1,35 @@ + + + + + int pblHtInsert + + +
+

Program Base Library Functions

+
+ +

int pblHtInsert

( pblHashTable_t* h, void* key, size_t keylen,
  void* dataptr )

insert a key / data pair into a hash table
+ + +
+

Documentation

+
+insert a key / data pair into a hash table + +

only the pointer to the data is stored in the hash table +no space is malloced for the data! + +

+
Parameters:
h - hash table to insert to +
key - key to insert +
keylen - length of that key +
dataptr - dataptr to insert
Returns:
int ret == 0: ok +
int ret == -1: an error, see pbl_errno: +
PBL_ERROR_EXISTS: an item with the same key already exists +
PBL_ERROR_OUT_OF_MEMORY: out of memory +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtLookup.html b/src/pbl/doc/pblHtLookup.html new file mode 100755 index 0000000..545de82 --- /dev/null +++ b/src/pbl/doc/pblHtLookup.html @@ -0,0 +1,30 @@ + + + + + void* pblHtLookup + + +
+

Program Base Library Functions

+
+ +

void* pblHtLookup

( pblHashTable_t* h, void* key,
  size_t keylen )

search for a key in a hash table
+ + +
+

Documentation

+
+search for a key in a hash table + +

+
Parameters:
h - hash table to search in +
key - key to search +
keylen - length of that key
Returns:
void * retptr != NULL: pointer to data of item found +
void * retptr == NULL: no item found with the given key +
PBL_ERROR_NOT_FOUND: +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtNext.html b/src/pbl/doc/pblHtNext.html new file mode 100755 index 0000000..72ee27c --- /dev/null +++ b/src/pbl/doc/pblHtNext.html @@ -0,0 +1,40 @@ + + + + + void* pblHtNext + + +
+

Program Base Library Functions

+
+ +

void* pblHtNext

( pblHashTable_t* h )

get data of next key in hash table
+ + +
+

Documentation

+
+get data of next key in hash table + +

This call and pblHtFirst can be used in order to loop through all items +stored in a hash table. + +

+   Example:
+
+

for( data = pblHtFirst( h ); data; data = pblHtNext( h )) + { + do something with the data pointer + } +

+ +

+
Parameters:
h - hash table to look in
Returns:
void * retptr != NULL: pointer to data of next item +
void * retptr == NULL: there is no next item in the hash table +
PBL_ERROR_NOT_FOUND: +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblHtRemove.html b/src/pbl/doc/pblHtRemove.html new file mode 100755 index 0000000..f0b04c1 --- /dev/null +++ b/src/pbl/doc/pblHtRemove.html @@ -0,0 +1,61 @@ + + + + + int pblHtRemove + + +
+

Program Base Library Functions

+
+ +

int pblHtRemove

( pblHashTable_t* h, void* key,
  size_t keylen )

remove an item from the hash table
+ + +
+

Documentation

+
+remove an item from the hash table + +

parameters key and keylen are optional, if they are not given +the current record is deleted + +

if the current record is removed the pointer to the current record +is moved to the next record. + +

+   Example:
+
+

for( data = pblHtFirst( h ); data; data = pblHtRemove( h, 0, 0 )) + { + this loop removes all items from a hash table + } +

+ +

if the current record is moved by this function the next call to +pblHtNext will return the data of the then current record. +Therefore the following code does what is expected: +It visits all items of the hash table and removes the expired ones. + +

+   for( data = pblHtFirst( h ); data; data = pblHtNext( h ))
+   {
+       if( needs to be deleted( data ))
+       {
+           pblHtRemove( h, 0, 0 );
+       }
+   }
+   
+ +

+
Parameters:
h - hash table to remove from +
key - OPT: key to remove +
keylen - OPT: length of that key
Returns:
int ret == 0: ok +
int ret == -1: an error, see pbl_errno: +
PBL_ERROR_NOT_FOUND: the current item is not positioned +
or there is no item with the given key +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblISAMFILE_TestFrame.html b/src/pbl/doc/pblISAMFILE_TestFrame.html new file mode 100755 index 0000000..d219d41 --- /dev/null +++ b/src/pbl/doc/pblISAMFILE_TestFrame.html @@ -0,0 +1,74 @@ + + + + + int pblISAMFILE_TestFrame + + +
+

Program Base Library Functions

+
+ +

int pblISAMFILE_TestFrame

( int argc, char* argv[] )

test frame for the ISAM file library
+ + +
+

Documentation

+
+test frame for the ISAM file library + +

This test frame calls the PBL ISAM file library, +it is an interactive test frame capable of regression tests. + +

Interactive mode: +

    +Call the program pbliftst from a UNIX or DOS shell. +
    +The following commands to test the PBL ISAM File Library are supplied: +
      +
      + q       FOR QUIT
      + open filename keyfile1,dupfile2,... update
      + transaction < START | COMMIT | ROLLBACK >
      + close
      + flush
      + insert ,key1,key2... data
      + ninsert n key1,key2,... data
      + find index key < LT | LE | FI | EQ | LA | GE | GT >
      + nfind n index key < LT | LE | FI | EQ | LA | GE | GT >
      + get index < NEXT | PREV | FIRST | LAST | THIS >
      + datalen
      + readdata
      + readkey index
      + updatedata data
      + updatekey index key
      + ndelete n
      + 
      +
    +See pblKEYFILE_TestFrame for an example to interactively use the +test frame. +
+Regression mode: +
    +Five regression test cases are supplied with the PBL ISAM library. + +

    ISAM0001.TST, ISAM0002.TST, ISAM0003.TST, ISAM0004.TST and ISAM0005.TST. + +

    ISAM0001.TST and ISAM0004.TST are run when the "make test" +is done. Do the following if you want to run the test cases per hand +

    +   1. Build the pbliftst executable.          make all
    +   2. Create the sub directory isamtest.      mkdir isamtest
    +   3. Clear the sub directory isamtest.       rm imamtest/0*
    +   4. Run the test frame on this file.        pbliftst ISAM0001.TST
    +   5. Compare ISAM0001.TST and pbliftst.log   diff ISAM0001.TST pbliftst.log
    + 
    +There should be no differences reported, if so your build of the +PBL library is most likely ok! + +

+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamClose.html b/src/pbl/doc/pblIsamClose.html new file mode 100755 index 0000000..8fdc7e7 --- /dev/null +++ b/src/pbl/doc/pblIsamClose.html @@ -0,0 +1,30 @@ + + + + + int pblIsamClose + + +
+

Program Base Library Functions

+
+ +

int pblIsamClose

( pblIsamFile_t* isamfile )

close an ISAM file
+ + +
+

Documentation

+
+close an ISAM file + +

all changes are flushed to disk before, +all memory allocated for the file is released. + +

+
Parameters:
isamfile - ISAM file to close
Returns:
int rc == 0: call went ok, file is closed +
int rc != 0: some error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamCommit.html b/src/pbl/doc/pblIsamCommit.html new file mode 100755 index 0000000..93d097f --- /dev/null +++ b/src/pbl/doc/pblIsamCommit.html @@ -0,0 +1,40 @@ + + + + + int pblIsamCommit + + +
+

Program Base Library Functions

+
+ +

int pblIsamCommit

( int nfiles, pblIsamFile_t** isamfiles,
  int rollback )

commit or rollback changes done during a transaction
+ + +
+

Documentation

+
+commit or rollback changes done during a transaction + +

transactions can be nested, if so the commit +only happens when the outermost transaction +calls a commit. + +

the commit only happens to process space buffer cache, +call pblIsamFlush() after pblIsamCommit() if you want to +flush to kernel space buffer cache. + +

+
Parameters:
nfiles - number of files in ISAM file list +
isamfiles - ISAM file list to commit changes of +
rollback - != 0: roll back the changes, == 0: commit the changes
Returns:
int rc == 0: the commit went ok +
int rc > 0: a rollback happened, either because the caller +requested it or because an inner transaction resulted +in a rollback +
int rc < 0: some error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamDelete.html b/src/pbl/doc/pblIsamDelete.html new file mode 100755 index 0000000..56cfda5 --- /dev/null +++ b/src/pbl/doc/pblIsamDelete.html @@ -0,0 +1,37 @@ + + + + + int pblIsamDelete + + +
+

Program Base Library Functions

+
+ +

int pblIsamDelete

( pblIsamFile_t* isamfile )

delete the current record of the ISAM file.
+ + +
+

Documentation

+
+delete the current record of the ISAM file. + +

the current record of the file is set to the next record or +if the last record is deleted, to the previous record, + +

if there are no more records in the file after the delete +the current record is of course unpositioned + +

+RESTRICTIONS: +
- the file must be open for update, + +

+
Parameters:
isamfile - ISAM file to delete from
Returns:
int rc == 0: call went ok +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamFile_t.html b/src/pbl/doc/pblIsamFile_t.html new file mode 100755 index 0000000..13dad43 --- /dev/null +++ b/src/pbl/doc/pblIsamFile_t.html @@ -0,0 +1,24 @@ + + + + + typedef struct pblIsamFile_s pblIsamFile_t + + +
+

Program Base Library Functions

+
+ +

typedef struct pblIsamFile_s pblIsamFile_t

the ISAM file type the pblIsam* functions are dealing with,
+ + +
+

Documentation

+
+the ISAM file type the pblIsam* functions are dealing with, +the details of the structure are hidden from the user
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamFind.html b/src/pbl/doc/pblIsamFind.html new file mode 100755 index 0000000..030b15f --- /dev/null +++ b/src/pbl/doc/pblIsamFind.html @@ -0,0 +1,66 @@ + + + + + int pblIsamFind + + +
+

Program Base Library Functions

+
+ +

int pblIsamFind

( pblIsamFile_t* isamfile, int which,
  int index, unsigned char* skey, int skeylen,
  unsigned char* okey )

find a record in an ISAM file, set the current record
+ + +
+

Documentation

+
+find a record in an ISAM file, set the current record + +

parameter which specifies which record to find relative +to the search key specified by skey and skeylen. +the following values for which are possible + +


PBLEQ - find a record whose key is equal to skey +
PBLFI - find the first record that is equal +
PBLLA - find the last record that is equal +
PBLGE - find the last record that is equal or the smallest +record that is greater +
PBLGT - find the smallest record that is greater +
PBLLE - find the first record that is equal or the biggest +record that is smaller +
PBLLT - find the biggest record that is smaller + +

parameter index specifies which of the keys to use + +

+RESTRICTIONS: +
- the out parameter okey must point to a memory area that is +big enough to hold any possible key, i.e 255 bytes + +

+
Parameters:
isamfile - ISAM file to search in +
which - mode to use for search +
index - index of key to use for search +
skey - key to use for search +
skeylen - length of search key +
okey - buffer for result key
Returns:
int rc >= 0: +
    +
  • call went ok, +the value returned is the length +of the key of the record found, +
  • the key of the record is copied to okey, +
  • the current record of the file is set to the +record found +
+
int rc < 0: +
    +
  • some error occured, see pbl_errno +especially PBL_ERROR_NOT_FOUND, if there is no +matching record +
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamFlush.html b/src/pbl/doc/pblIsamFlush.html new file mode 100755 index 0000000..376b106 --- /dev/null +++ b/src/pbl/doc/pblIsamFlush.html @@ -0,0 +1,29 @@ + + + + + int pblIsamFlush + + +
+

Program Base Library Functions

+
+ +

int pblIsamFlush

( pblIsamFile_t* isamfile )

flush an ISAM file
+ + +
+

Documentation

+
+flush an ISAM file + +

all changes are flushed to disk, + +

+
Parameters:
isamfile - ISAM file to flush
Returns:
int rc == 0: call went ok +
int rc != 0: some error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamGet.html b/src/pbl/doc/pblIsamGet.html new file mode 100755 index 0000000..c51d5c9 --- /dev/null +++ b/src/pbl/doc/pblIsamGet.html @@ -0,0 +1,62 @@ + + + + + int pblIsamGet + + +
+

Program Base Library Functions

+
+ +

int pblIsamGet

( pblIsamFile_t* isamfile, int which, int index,
  unsigned char* okey )

get the key and keylen of a record
+ + +
+

Documentation

+
+get the key and keylen of a record + +

parameter which specifies which record to get relative +to the search key specified by index. +the following values for which are possible + +


PBLTHIS - get key and keylen of current record +
PBLNEXT - get key and keylen of next record +
PBLPREV - get key and keylen of previous record +
PBLFIRST - get key and keylen of first record +
PBLLAST - get key and keylen of last record + +

parameter index specifies which of the keys to get, +the pseudo index value -1 can be used in order to access the file +sequentially in the order the records were inserted. +okey is not set in this case, a keylength of 0 is returned in case +the call went ok. + +

+RESTRICTIONS: +
- the out parameter okey must point to a memory area that is +big enough to hold any possible key, i.e 255 bytes + +

+
Parameters:
isamfile - ISAM file to read in +
which - mode to use for read +
index - index of key to use for read +
okey - buffer for result key
Returns:
int rc >= 0: +
    +
  • call went ok, +the value returned is the length +of the key of the record found, +
  • the key of the record is copied to okey, +
  • the current record of the file is set to the +record found +
+
int rc < 0: +
    +
  • some error occured, see pbl_errno +
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamInsert.html b/src/pbl/doc/pblIsamInsert.html new file mode 100755 index 0000000..db94e90 --- /dev/null +++ b/src/pbl/doc/pblIsamInsert.html @@ -0,0 +1,52 @@ + + + + + int pblIsamInsert + + +
+

Program Base Library Functions

+
+ +

int pblIsamInsert

( pblIsamFile_t* isamfile,
  unsigned char* allkeys, int allkeyslen,
  unsigned char* data, long datalen )

insert a new record with the given keys and data into the isam file,
+ + +
+

Documentation

+
+insert a new record with the given keys and data into the isam file, + +

the current record of the file will be set to the new record + +

+RESTRICTIONS: +
- the file must be open for update, +
- allkeys must point to the keys to be inserted, +
- allkeyslen must be bigger than 0 and smaller than 1024, +
- data must point to the data be inserted, +
- datalen must not be negative, +
- if datalen == 0, the pointer data is not evaluated at all + +

Parameter allkeys must contain all values for all keys +of the record. The values have to be prepended by one byte giving +the length of the following value. All values have to be concatenated +into one string. + +

Example: +

 4isam4file3key 
+with the numbers as binary values and the letters ascii, +specifies three keys with the values "isam", "file" and "key". + +

+
Parameters:
isamfile - ISAM file to insert to +
allkeys - pointers to all keys to insert +
allkeyslen - total length of all keys to insert +
data - data to insert +
datalen - length of the data
Returns:
int rc == 0: call went ok +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamOpen.html b/src/pbl/doc/pblIsamOpen.html new file mode 100755 index 0000000..9f17828 --- /dev/null +++ b/src/pbl/doc/pblIsamOpen.html @@ -0,0 +1,40 @@ + + + + + pblIsamFile_t* pblIsamOpen + + +
+

Program Base Library Functions

+
+ +

pblIsamFile_t* pblIsamOpen

( char* path,
  int update,
  void* filesettag,
  int nkeys,
  char** keyfilenames,
  int* keydup )

open an ISAM file, creates the file if necessary
+ + +
+

Documentation

+
+open an ISAM file, creates the file if necessary + +

if update is 0, the ISAM file is opened for read access only, +if update is not 0 the ISAM file is opened for reading and writing + +

a file set tag can be attached to the ISAM file, +if a file having a non NULL file set tag is flushed +to disk all files having the same file set tag attached +are flushed as well. + +

+
Parameters:
path - path of file to create +
update - flag: should file be opened for update? +
filesettag - filesettag, for flushing multiple files consistently +
nkeys - number of key files to create +
keyfilenames - list of names of key index files to create +
keydup - flaglist: is the i'th index key a duplicate key?
Returns:
pblIsamFile_t * retptr == NULL: an error occured, see pbl_errno +
pblIsamFile_t * retptr != NULL: a pointer to an ISAM file descriptor +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamReadData.html b/src/pbl/doc/pblIsamReadData.html new file mode 100755 index 0000000..ab37ed5 --- /dev/null +++ b/src/pbl/doc/pblIsamReadData.html @@ -0,0 +1,32 @@ + + + + + long pblIsamReadData + + +
+

Program Base Library Functions

+
+ +

long pblIsamReadData

( pblIsamFile_t* isamfile,
  unsigned char* buffer,
  long bufferlen )

read the data of the current record
+ + +
+

Documentation

+
+read the data of the current record + +

parameter bufferlen specifies how many bytes to read + +

+
Parameters:
isamfile - ISAM file to read from +
buffer - buffer to read to +
bufferlen - length of that buffer
Returns:
long rc >= 0: call went ok, the value returned is the length +of the data copied +
long rc < 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamReadDatalen.html b/src/pbl/doc/pblIsamReadDatalen.html new file mode 100755 index 0000000..3bcf7d5 --- /dev/null +++ b/src/pbl/doc/pblIsamReadDatalen.html @@ -0,0 +1,28 @@ + + + + + long pblIsamReadDatalen + + +
+

Program Base Library Functions

+
+ +

long pblIsamReadDatalen

( pblIsamFile_t* isamfile )

read the datalen of the current record
+ + +
+

Documentation

+
+read the datalen of the current record + +

+
Parameters:
isamfile - ISAM file to read length of data from
Returns:
long rc >= 0: call went ok, the value returned is the length +of the data of the record, +
long rc < 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamReadKey.html b/src/pbl/doc/pblIsamReadKey.html new file mode 100755 index 0000000..ee50063 --- /dev/null +++ b/src/pbl/doc/pblIsamReadKey.html @@ -0,0 +1,46 @@ + + + + + int pblIsamReadKey + + +
+

Program Base Library Functions

+
+ +

int pblIsamReadKey

( pblIsamFile_t* isamfile, int index,
  unsigned char* okey )

read the key and keylen of the current record
+ + +
+

Documentation

+
+read the key and keylen of the current record + +

parameter index specifies which of the keys to read + +

+RESTRICTIONS: +
- the out parameter okey must point to a memory area that is +big enough to hold any possible key, i.e 255 bytes + +

+
Parameters:
isamfile - ISAM file to read in +
index - index of key read +
okey - buffer for result key
Returns:
int rc >= 0: +
    +
  • call went ok, +the value returned is the length of the key +
  • the key of the record is copied to okey, +
  • the current record of the file is not affected +by this function +
+
int rc < 0: +
    +
  • some error occured, see pbl_errno +
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamSetCompareFunction.html b/src/pbl/doc/pblIsamSetCompareFunction.html new file mode 100755 index 0000000..c166b0a --- /dev/null +++ b/src/pbl/doc/pblIsamSetCompareFunction.html @@ -0,0 +1,43 @@ + + + + + int pblIsamSetCompareFunction + + +
+

Program Base Library Functions

+
+ +

int pblIsamSetCompareFunction

( pblIsamFile_t* isamfile,
  int index,
  int (* keycompare ) ( void* left,
  size_t llen, void* right,
  size_t rlen ) )

set an application specific compare function for a key of an ISAM file
+ + +
+

Documentation

+
+set an application specific compare function for a key of an ISAM file + +

parameter index specifies which of the indices to set +the compare function for + +

an application specific compare function can be used in order to +implement special orderings of the values of an index, e.g. +because of the use of european "umlauts" in names + +

the default compare function is the c-library memcmp function +the keycompare function should behave like memcmp + +

+
Parameters:
isamfile - ISAM file to set function for +
index - index of key to set function for +
keycompare - compare function to set +
left - "left" buffer for compare +
llen - length of that buffer +
right - "right" buffer for compare +
rlen - length of that buffer
Returns:
int rc == 0: call went ok +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamStartTransaction.html b/src/pbl/doc/pblIsamStartTransaction.html new file mode 100755 index 0000000..91ad2f7 --- /dev/null +++ b/src/pbl/doc/pblIsamStartTransaction.html @@ -0,0 +1,32 @@ + + + + + int pblIsamStartTransaction + + +
+

Program Base Library Functions

+
+ +

int pblIsamStartTransaction

( int nfiles,
  pblIsamFile_t** isamfiles )

start a transaction on a set of ISAM files
+ + +
+

Documentation

+
+start a transaction on a set of ISAM files + +

transactions can be nested + +

+
Parameters:
nfiles - number of files in ISAM file list +
isamfiles - ISAM file list to start transaction on
Returns:
int rc == 0: the transaction was started successfully +
int rc > 0: the transaction was started +but another transaction has resulted in +a rollback request on the file already +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamUpdateData.html b/src/pbl/doc/pblIsamUpdateData.html new file mode 100755 index 0000000..03e442b --- /dev/null +++ b/src/pbl/doc/pblIsamUpdateData.html @@ -0,0 +1,34 @@ + + + + + long pblIsamUpdateData + + +
+

Program Base Library Functions

+
+ +

long pblIsamUpdateData

( pblIsamFile_t* isamfile,
  unsigned char* data, long datalen )

update the data of the current record
+ + +
+

Documentation

+
+update the data of the current record + +

parameter datalen specifies how many bytes to write + +

the file must be open for update + +

+
Parameters:
isamfile - ISAM file to update +
data - data to write +
datalen - length of that data
Returns:
long rc >= 0: call went ok, the value returned is the length +of the data copied +
long rc < 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblIsamUpdateKey.html b/src/pbl/doc/pblIsamUpdateKey.html new file mode 100755 index 0000000..819f122 --- /dev/null +++ b/src/pbl/doc/pblIsamUpdateKey.html @@ -0,0 +1,34 @@ + + + + + int pblIsamUpdateKey + + +
+

Program Base Library Functions

+
+ +

int pblIsamUpdateKey

( pblIsamFile_t* isamfile, int index,
  unsigned char* ukey, int ukeylen )

update a key of the current record of the ISAM file
+ + +
+

Documentation

+
+update a key of the current record of the ISAM file + +

parameter index specifies which of the keys to update + +

the file must be open for update + +

+
Parameters:
isamfile - ISAM file to update key for +
index - index of key to update +
ukey - new value for the key to update +
ukeylen - length of that value
Returns:
int rc == 0: call went ok +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKEYFILE_TestFrame.html b/src/pbl/doc/pblKEYFILE_TestFrame.html new file mode 100755 index 0000000..37a72fd --- /dev/null +++ b/src/pbl/doc/pblKEYFILE_TestFrame.html @@ -0,0 +1,142 @@ + + + + + int pblKEYFILE_TestFrame + + +
+

Program Base Library Functions

+
+ +

int pblKEYFILE_TestFrame

( int argc, char* argv[] )

test frame for the key file library
+ + +
+

Documentation

+
+test frame for the key file library + +

This test frame calls the key file library, +it is an interactive test frame capable of regression tests. + +

Interactive mode: +

    +Call the program pblkftst from a UNIX or DOS shell. +
    +The following commands to test the PBL Key File Library are supplied: +
      +
      + q       FOR QUIT
      + create  
      + open     
      + close | flush | delete
      + insert   
      + ninsert   
      + find     < LT | LE | FI | EQ | LA | GE | GT >
      + update  
      + ndelete 
      + first | last | next | prev | this | read
      + list    
      + 
      +
    +
+Interactive mode example: +
    +The following short examples demonstrates how to use the interactive +test frame. Lines starting with a # are printed by the program +lines starting with other characters are user input. +
      +
      +pblkftst
      +
      +

      ##command: +create /tmp/keytest +# create filename +# pblKfCreate( /tmp/keytest ) +# ok! + +

      ##command: +insert testkey testdata +# insert key, data +# pblKfInsert( 1, testkey, 8, testdata, 9 ) +# rc 0, pbl_errno 0, errno 0 + +

      ##command: +first +# pblKfFirst( 1 ) +# datalen 9, key testkey, keylen 8 + +

      ##command: +close +# pblKfClose( 1 ) +# rc 0, pbl_errno 0, errno 0 + +

      ##command: +quit +

      +
    +
+ +

Regression mode: +

    +Put a sequence of test commands into a test batch file. +

    +Example: +

      +Open a new file KEY0001.TST and add the following lines +
      +create /tmp/keytest2
      +insert testkey testdata
      +first
      +close
      +quit
      +
      +
    +Then run pblkftst KEY0001.TST + +

    The program creates a log file called pblkftst.log when run. +This log file can be used as regression input file for further +tests. +

      +
      +##command:
      +create # create filename
      +/tmp/key0001
      +# pblKfCreate( /tmp/key0001 )
      +# ok!
      +
      +

      ##command: +insert # insert key, data +testkey testdata +# pblKfInsert( 1, testkey, 8, testdata, 9 ) +# rc 0, pbl_errno 0, errno 0 + +

      ##command: +first +# pblKfFirst( 1 ) +# datalen 9, key testkey, keylen 8 + +

      ##command: +close +# pblKfClose( 1 ) +# rc 0, pbl_errno 0, errno 0 + +

      ##command: +quit +

      +
    +Keep the contents of this file and diff it with the outout of +the KEY0001.TST testcase you created whenever you change +the code of the library. + +

    See pblISAMFILE_TestFrame for an example of regression +tests with a test frame. The regression test cases given with +pblISAMFILE_TestFrame of course also test the PBL Key File +library. +

+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKeyFile_t.html b/src/pbl/doc/pblKeyFile_t.html new file mode 100755 index 0000000..489e29c --- /dev/null +++ b/src/pbl/doc/pblKeyFile_t.html @@ -0,0 +1,24 @@ + + + + + typedef struct pblKeyFile_s pblKeyFile_t + + +
+

Program Base Library Functions

+
+ +

typedef struct pblKeyFile_s pblKeyFile_t

the key file type the pblKf* functions are dealing with,
+ + +
+

Documentation

+
+the key file type the pblKf* functions are dealing with, +the details of the structure are hidden from the user
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfClose.html b/src/pbl/doc/pblKfClose.html new file mode 100755 index 0000000..72765f6 --- /dev/null +++ b/src/pbl/doc/pblKfClose.html @@ -0,0 +1,30 @@ + + + + + int pblKfClose + + +
+

Program Base Library Functions

+
+ +

int pblKfClose

( pblKeyFile_t* k )

close a key file
+ + +
+

Documentation

+
+close a key file + +

all changes are flushed to disk before, +all memory allocated for the file is released. + +

+
Parameters:
k - key file to close
Returns:
int rc == 0: call went ok, file is closed +
int rc != 0: some error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfCommit.html b/src/pbl/doc/pblKfCommit.html new file mode 100755 index 0000000..6e768ef --- /dev/null +++ b/src/pbl/doc/pblKfCommit.html @@ -0,0 +1,39 @@ + + + + + int pblKfCommit + + +
+

Program Base Library Functions

+
+ +

int pblKfCommit

( pblKeyFile_t* k, int rollback )

commit or rollback changes done during a transaction.
+ + +
+

Documentation

+
+commit or rollback changes done during a transaction. + +

transactions can be nested, if so the commit +only happens when the outermost transaction +calls a commit. + +

the commit only happens to process space buffer cache, +call pblKfFlush() after pblKfCommit() if you want to +flush to kernel space buffer cache. + +

+
Parameters:
k - key file to commit +
rollback - != 0: roll back the changes, == 0: commit the changes
Returns:
int rc == 0: the commit went ok +
int rc > 0: a rollback happened, either because the caller +requested it or because an inner transaction resulted +in a rollback +
int rc < 0: some error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfCreate.html b/src/pbl/doc/pblKfCreate.html new file mode 100755 index 0000000..2329648 --- /dev/null +++ b/src/pbl/doc/pblKfCreate.html @@ -0,0 +1,38 @@ + + + + + pblKeyFile_t* pblKfCreate + + +
+

Program Base Library Functions

+
+ +

pblKeyFile_t* pblKfCreate

( char* path,
  void* filesettag )

create a key file with the name specified by path.
+ + +
+

Documentation

+
+create a key file with the name specified by path. + +

a file set tag can be attached to the file, +if a file having a non NULL file set tag is flushed +to disk all files having the same file set tag attached +are flushed as well. + +

+RESTRICTIONS: +
- the file to create must not exists. +
- the current record of the file will not be set + +

+
Parameters:
path - path of file to create +
filesettag - file set tag, for flushing multiple files consistently
Returns:
pblKeyFile_t * retptr == NULL: an error occured, see pbl_errno +
pblKeyFile_t * retptr != NULL: a pointer to a key file descriptor +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfDelete.html b/src/pbl/doc/pblKfDelete.html new file mode 100755 index 0000000..72245ce --- /dev/null +++ b/src/pbl/doc/pblKfDelete.html @@ -0,0 +1,40 @@ + + + + + int pblKfDelete + + +
+

Program Base Library Functions

+
+ +

int pblKfDelete

( pblKeyFile_t* k )

delete the current record of the key file.
+ + +
+

Documentation

+
+delete the current record of the key file. + +

the current record of the file is set to the next record or +if the last record is deleted, to the previous record, + +

if there are no more records in the file after the delete +the current record is of course unpositioned + +

+RESTRICTIONS: +
- the file must be open for update, +
- no space will be given back to the file system, +
- if an index block and its successor or its predeccessor +together use less than half of a block the two blocks are merged + +

+
Parameters:
k - key file to delete record from
Returns:
int rc == 0: call went ok +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfFind.html b/src/pbl/doc/pblKfFind.html new file mode 100755 index 0000000..24a2a85 --- /dev/null +++ b/src/pbl/doc/pblKfFind.html @@ -0,0 +1,68 @@ + + + + + long pblKfFind + + +
+

Program Base Library Functions

+
+ +

long pblKfFind

( pblKeyFile_t* k, int mode,
  unsigned char* skey, int skeylen,
  unsigned char* okey, int* okeylen )

find a record in a key file, set the current record
+ + +
+

Documentation

+
+find a record in a key file, set the current record + +

parameter mode specifies which record to find relative +to the search key specified by skey and skeylen. +the following values for mode are possible + +


PBLEQ - find a record whose key is equal to skey +
PBLFI - find the first record that is equal +
PBLLA - find the last record that is equal +
PBLGE - find the last record that is equal or the smallest +record that is greater +
PBLGT - find the smallest record that is greater +
PBLLE - find the first record that is equal or the biggest +record that is smaller +
PBLLT - find the biggest record that is smaller + +

keep in mind that PBL allows multiple records with the same key. + +

+RESTRICTIONS: +
- the out parameter okey must point to a memory area that is +big enough to hold any possible key, i.e 255 bytes + +

+
Parameters:
k - key file to search in +
mode - mode to use for search +
skey - key to use for search +
skeylen - length of search key +
okey - buffer for result key +
okeylen - length of the result key after return
Returns:
long rc >= 0: +
    +
  • call went ok, +the value returned is the length +of the data of the record found, +
  • the length of the key of the record is set in +the out parameter okeylen, +
  • the key of the record is copied to okey, +
  • the current record of the file is set to the +record found +
+
long rc < 0: +
    +
  • some error occured, see pbl_errno +especially PBL_ERROR_NOT_FOUND, if there is no +matching record +
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfFirst.html b/src/pbl/doc/pblKfFirst.html new file mode 100755 index 0000000..a04140f --- /dev/null +++ b/src/pbl/doc/pblKfFirst.html @@ -0,0 +1,23 @@ + + + + + #define pblKfFirst + + +
+

Program Base Library Functions

+
+ +

#define pblKfFirst

( KF, K, L )

set the current record to the first record of the file
+ + +
+

Documentation

+
+set the current record to the first record of the file
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfFlush.html b/src/pbl/doc/pblKfFlush.html new file mode 100755 index 0000000..51ddc4d --- /dev/null +++ b/src/pbl/doc/pblKfFlush.html @@ -0,0 +1,29 @@ + + + + + int pblKfFlush + + +
+

Program Base Library Functions

+
+ +

int pblKfFlush

( pblKeyFile_t* k )

flush a key file
+ + +
+

Documentation

+
+flush a key file + +

all changes are flushed to disk, + +

+
Parameters:
k - key file to flush
Returns:
int rc == 0: call went ok +
int rc != 0: some error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfGetAbs.html b/src/pbl/doc/pblKfGetAbs.html new file mode 100755 index 0000000..c45f651 --- /dev/null +++ b/src/pbl/doc/pblKfGetAbs.html @@ -0,0 +1,48 @@ + + + + + long pblKfGetAbs + + +
+

Program Base Library Functions

+
+ +

long pblKfGetAbs

( pblKeyFile_t* k, long absindex, char* okey,
  int* okeylen )

set current record to a record with an absolute position index
+ + +
+

Documentation

+
+set current record to a record with an absolute position index + +

this function is only to be used through the macro functions: + +


pblKfFirst( k, okey, okeylen ) read key of first record +
pblKfLast( k, okey, okeylen ) read key of last record + +

+
Parameters:
k - key file to position in +
absindex - index of record to positon to +
okey - buffer for result key +
okeylen - length of the result key after return
Returns:
long rc >= 0: +
    +
  • call went ok, +the value returned is the length +of the data of the record found, +
  • the length of the key of the record is set in +the out parameter okeylen, +
  • the key of the record is copied to okey, +
  • the current record of the file is set to the +record found +
+
long rc < 0: +
    +
  • some error occured, see pbl_errno +
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfGetRel.html b/src/pbl/doc/pblKfGetRel.html new file mode 100755 index 0000000..52bb876 --- /dev/null +++ b/src/pbl/doc/pblKfGetRel.html @@ -0,0 +1,49 @@ + + + + + long pblKfGetRel + + +
+

Program Base Library Functions

+
+ +

long pblKfGetRel

( pblKeyFile_t* k, long relindex, char* okey,
  int* okeylen )

set current record to a record with a relative position index
+ + +
+

Documentation

+
+set current record to a record with a relative position index + +

this function is only to be used through the macro functions: + +


pblKfThis( k, okey, okeylen ) read key of current record +
pblKfNext( k, okey, okeylen ) read key of next record +
pblKfPrev( k, okey, okeylen ) read key of previous record + +

+
Parameters:
k - key file to position in +
relindex - index relative to current record +
okey - buffer for result key +
okeylen - length of the result key after return
Returns:
long rc >= 0: +
    +
  • call went ok, +the value returned is the length +of the data of the record found, +
  • the length of the key of the record is set in +the out parameter okeylen, +
  • the key of the record is copied to okey, +
  • the current record of the file is set to the +record found +
+
long rc < 0: +
    +
  • some error occured, see pbl_errno +
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfInit.html b/src/pbl/doc/pblKfInit.html new file mode 100755 index 0000000..c4163eb --- /dev/null +++ b/src/pbl/doc/pblKfInit.html @@ -0,0 +1,28 @@ + + + + + int pblKfInit + + +
+

Program Base Library Functions

+
+ +

int pblKfInit

( int nblocks )

change the number of cache blocks used per open key file
+ + +
+

Documentation

+
+change the number of cache blocks used per open key file + +

the default number is 64, a memory block uses about 4096 bytes of heap memory + +

+
Returns:
int rc: the number of blocks used after the call +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfInsert.html b/src/pbl/doc/pblKfInsert.html new file mode 100755 index 0000000..6381d02 --- /dev/null +++ b/src/pbl/doc/pblKfInsert.html @@ -0,0 +1,46 @@ + + + + + int pblKfInsert + + +
+

Program Base Library Functions

+
+ +

int pblKfInsert

( pblKeyFile_t* k, unsigned char* key,
  int keylen, unsigned char* data,
  long datalen )

insert a new record with the given key and data into a key file,
+ + +
+

Documentation

+
+insert a new record with the given key and data into a key file, + +

multiple records with the same key are allowed, +if there are already records with the same key the new +record will be inserted behind all records with the same key, + +

the current record of the file will be set to the new record + +

+RESTRICTIONS: +
- the file must be open for update, +
- key must point to the key to be inserted, +
- keylen must be bigger than 0 and smaller than 256, +
- data must point to the data be inserted, +
- datalen must not be negative, +
- if datalen == 0, the pointer data is not evaluated at all + +

+
Parameters:
k - key file to insert to +
key - key to insert +
keylen - length of the key +
data - data to insert +
datalen - length of the data
Returns:
int rc == 0: call went ok +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfLast.html b/src/pbl/doc/pblKfLast.html new file mode 100755 index 0000000..8d9f9f6 --- /dev/null +++ b/src/pbl/doc/pblKfLast.html @@ -0,0 +1,23 @@ + + + + + #define pblKfLast + + +
+

Program Base Library Functions

+
+ +

#define pblKfLast

( KF, K, L )

set the current record to the last record of the file
+ + +
+

Documentation

+
+set the current record to the last record of the file
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfNext.html b/src/pbl/doc/pblKfNext.html new file mode 100755 index 0000000..40d8c14 --- /dev/null +++ b/src/pbl/doc/pblKfNext.html @@ -0,0 +1,23 @@ + + + + + #define pblKfNext + + +
+

Program Base Library Functions

+
+ +

#define pblKfNext

( KF, K, L )

set the current record to the next record of the file
+ + +
+

Documentation

+
+set the current record to the next record of the file
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfOpen.html b/src/pbl/doc/pblKfOpen.html new file mode 100755 index 0000000..73b484a --- /dev/null +++ b/src/pbl/doc/pblKfOpen.html @@ -0,0 +1,42 @@ + + + + + pblKeyFile_t* pblKfOpen + + +
+

Program Base Library Functions

+
+ +

pblKeyFile_t* pblKfOpen

( char* path,
  int update,
  void* filesettag )

open an existing key file
+ + +
+

Documentation

+
+open an existing key file + +

if update is 0, the file is opened for read access only, +if update is not 0 the file is opened for reading and writing + +

a file set tag can be attached to the file, +if a file having a non NULL file set tag is flushed +to disk all files having the same file set tag attached +are flushed as well. + +

+RESTRICTIONS: +
- the file must exist already +
- the current record of the file will not be set + +

+
Parameters:
path - path of file to create +
update - flag: should file be opened for update? +
filesettag - file set tag, for flushing multiple files consistently
Returns:
pblKeyFile_t * retptr == NULL: an error occured, see pbl_errno +
pblKeyFile_t * retptr != NULL: a pointer to a key file descriptor +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfPrev.html b/src/pbl/doc/pblKfPrev.html new file mode 100755 index 0000000..d82b292 --- /dev/null +++ b/src/pbl/doc/pblKfPrev.html @@ -0,0 +1,23 @@ + + + + + #define pblKfPrev + + +
+

Program Base Library Functions

+
+ +

#define pblKfPrev

( KF, K, L )

set the current record to the previous record of the file
+ + +
+

Documentation

+
+set the current record to the previous record of the file
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfRead.html b/src/pbl/doc/pblKfRead.html new file mode 100755 index 0000000..47470f3 --- /dev/null +++ b/src/pbl/doc/pblKfRead.html @@ -0,0 +1,39 @@ + + + + + long pblKfRead + + +
+

Program Base Library Functions

+
+ +

long pblKfRead

( pblKeyFile_t* k, unsigned char* data,
  long datalen )

read the data of the current record of the file
+ + +
+

Documentation

+
+read the data of the current record of the file + +

the caller can restrict the number of bytes read by +specifying the maximum number of bytes to read by parameter +datalen, if datalen is 0, all bytes stored for the +current record are copied to the buffer pointed to by data. +

+RESTRICTIONS: +
- data must point to an area of memory being big enough to hold +the bytes copied +
- datalen must not be negative, it is ignored otherwise + +

+
Parameters:
k - key file to read from +
data - data to insert +
datalen - length of the data
Returns:
int rc == 0: call went ok, rc is the number of bytes copied +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfRestorePosition.html b/src/pbl/doc/pblKfRestorePosition.html new file mode 100755 index 0000000..7e6d1d2 --- /dev/null +++ b/src/pbl/doc/pblKfRestorePosition.html @@ -0,0 +1,28 @@ + + + + + int pblKfRestorePosition + + +
+

Program Base Library Functions

+
+ +

int pblKfRestorePosition

( pblKeyFile_t* k )

restore the position of the current record saved by the last previous call to pblKfSavePosition().
+ + +
+

Documentation

+
+restore the position of the current record saved by the +last previous call to pblKfSavePosition(). + +

+
Parameters:
k - key file to restore position for
Returns:
int rc == 0: the position was restored +
int rc < 0: an error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfSavePosition.html b/src/pbl/doc/pblKfSavePosition.html new file mode 100755 index 0000000..4a8146d --- /dev/null +++ b/src/pbl/doc/pblKfSavePosition.html @@ -0,0 +1,27 @@ + + + + + int pblKfSavePosition + + +
+

Program Base Library Functions

+
+ +

int pblKfSavePosition

( pblKeyFile_t* k )

save the position of the current record for later restore
+ + +
+

Documentation

+
+save the position of the current record for later restore + +

+
Parameters:
k - key file to save position for
Returns:
int rc == 0: the position was saved +
int rc < 0: an error, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfSetCompareFunction.html b/src/pbl/doc/pblKfSetCompareFunction.html new file mode 100755 index 0000000..0be5963 --- /dev/null +++ b/src/pbl/doc/pblKfSetCompareFunction.html @@ -0,0 +1,38 @@ + + + + + void pblKfSetCompareFunction + + +
+

Program Base Library Functions

+
+ +

void pblKfSetCompareFunction

( pblKeyFile_t* k,
  int (* keycompare ) ( void* left,
  size_t llen, void* right,
  size_t rlen ) )

set an application specific compare function for the keys of a key file
+ + +
+

Documentation

+
+set an application specific compare function for the keys of a key file + +

an application specific compare function can be used in order to +implement special orderings of the values of an index, e.g. +because of the use of european "umlauts" in names + +

the default compare function is the c-library memcmp function +the keycompare function should behave like memcmp + +

+
Parameters:
k - key file to set compare function for +
keycompare - compare function to set +
left - "left" buffer for compare +
llen - length of that buffer +
right - "right" buffer for compare +
rlen - length of that buffer
Returns:
void +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfStartTransaction.html b/src/pbl/doc/pblKfStartTransaction.html new file mode 100755 index 0000000..aa8f3b1 --- /dev/null +++ b/src/pbl/doc/pblKfStartTransaction.html @@ -0,0 +1,31 @@ + + + + + int pblKfStartTransaction + + +
+

Program Base Library Functions

+
+ +

int pblKfStartTransaction

( pblKeyFile_t* k )

start a transaction on a key file
+ + +
+

Documentation

+
+start a transaction on a key file + +

transactions can be nested + +

+
Parameters:
k - key file to start transaction on
Returns:
int rc == 0: the transaction was started successfully +
int rc > 0: the transaction was started +but another transaction has resulted in +a rollback request on the file already +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfThis.html b/src/pbl/doc/pblKfThis.html new file mode 100755 index 0000000..79f7c50 --- /dev/null +++ b/src/pbl/doc/pblKfThis.html @@ -0,0 +1,23 @@ + + + + + #define pblKfThis + + +
+

Program Base Library Functions

+
+ +

#define pblKfThis

( KF, K, L )

return the datalen of the current record
+ + +
+

Documentation

+
+return the datalen of the current record
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pblKfUpdate.html b/src/pbl/doc/pblKfUpdate.html new file mode 100755 index 0000000..5f50edd --- /dev/null +++ b/src/pbl/doc/pblKfUpdate.html @@ -0,0 +1,43 @@ + + + + + int pblKfUpdate + + +
+

Program Base Library Functions

+
+ +

int pblKfUpdate

( pblKeyFile_t* k, unsigned char* data,
  long datalen )

update the data of the current record
+ + +
+

Documentation

+
+update the data of the current record + +

the current record of the file is updated with the new data given + +

+

+RESTRICTIONS: +
- the file must be open for update, +
- if the new datalen of the record is not bigger than the old datalen, +the data will be updated in place, otherwise the new data of the +record will be appended to the file, the space previously used for +the data of the record will not be reused in this case, +
- data must point to the new data be inserted, +
- datalen must not be negative, +
- if datalen == 0, the pointer data is not evaluated at all + +

+
Parameters:
k - key file to delete record from +
data - new data to update with +
datalen - length of the new data
Returns:
int rc == 0: call went ok +
int rc != 0: some error occured, see pbl_errno +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_BufToLong.html b/src/pbl/doc/pbl_BufToLong.html new file mode 100755 index 0000000..dc7d4db --- /dev/null +++ b/src/pbl/doc/pbl_BufToLong.html @@ -0,0 +1,26 @@ + + + + + long pbl_BufToLong + + +
+

Program Base Library Functions

+
+ +

long pbl_BufToLong

( unsigned char* buf )

read a four byte long from a four byte buffer
+ + +
+

Documentation

+
+read a four byte long from a four byte buffer + +

+
Parameters:
buf - the buffer to read from
Returns:
long ret: the long value read +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_BufToShort.html b/src/pbl/doc/pbl_BufToShort.html new file mode 100755 index 0000000..9008469 --- /dev/null +++ b/src/pbl/doc/pbl_BufToShort.html @@ -0,0 +1,26 @@ + + + + + int pbl_BufToShort + + +
+

Program Base Library Functions

+
+ +

int pbl_BufToShort

( unsigned char* buf )

read a two byte short from a two byte buffer
+ + +
+

Documentation

+
+read a two byte short from a two byte buffer + +

+
Parameters:
buf - buffer to read from
Returns:
int rc: the short value read +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_LongSize.html b/src/pbl/doc/pbl_LongSize.html new file mode 100755 index 0000000..5a82e8e --- /dev/null +++ b/src/pbl/doc/pbl_LongSize.html @@ -0,0 +1,26 @@ + + + + + int pbl_LongSize + + +
+

Program Base Library Functions

+
+ +

int pbl_LongSize

( unsigned long value )

find out how many bytes a four byte long would use in a buffer
+ + +
+

Documentation

+
+find out how many bytes a four byte long would use in a buffer + +

+
Parameters:
value - value to check
Returns:
int rc: number of bytes used in buffer +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_LongToBuf.html b/src/pbl/doc/pbl_LongToBuf.html new file mode 100755 index 0000000..0b35395 --- /dev/null +++ b/src/pbl/doc/pbl_LongToBuf.html @@ -0,0 +1,25 @@ + + + + + void pbl_LongToBuf + + +
+

Program Base Library Functions

+
+ +

void pbl_LongToBuf

( unsigned char* buf, long l )

copy a four byte long to a four byte buffer
+ + +
+

Documentation

+
+copy a four byte long to a four byte buffer +
+
Parameters:
buf - buffer to copy to +
l - long value to copy

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_LongToVarBuf.html b/src/pbl/doc/pbl_LongToVarBuf.html new file mode 100755 index 0000000..ed8fe54 --- /dev/null +++ b/src/pbl/doc/pbl_LongToVarBuf.html @@ -0,0 +1,25 @@ + + + + + int pbl_LongToVarBuf + + +
+

Program Base Library Functions

+
+ +

int pbl_LongToVarBuf

( unsigned char* buffer,
  unsigned long value )

copy a four byte long to a variable length buffer
+ + +
+

Documentation

+
+copy a four byte long to a variable length buffer + +

+
Returns:
int rc: the number of bytes used in the buffer

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_ShortToBuf.html b/src/pbl/doc/pbl_ShortToBuf.html new file mode 100755 index 0000000..8029184 --- /dev/null +++ b/src/pbl/doc/pbl_ShortToBuf.html @@ -0,0 +1,25 @@ + + + + + void pbl_ShortToBuf + + +
+

Program Base Library Functions

+
+ +

void pbl_ShortToBuf

( unsigned char* buf, int s )

copy a two byte short to a two byte buffer
+ + +
+

Documentation

+
+copy a two byte short to a two byte buffer +
+
Parameters:
buf - buffer to copy to +
s - short value to copy

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_VarBufSize.html b/src/pbl/doc/pbl_VarBufSize.html new file mode 100755 index 0000000..9321130 --- /dev/null +++ b/src/pbl/doc/pbl_VarBufSize.html @@ -0,0 +1,26 @@ + + + + + int pbl_VarBufSize + + +
+

Program Base Library Functions

+
+ +

int pbl_VarBufSize

( unsigned char* buffer )

find out how many bytes a four byte long uses in a buffer
+ + +
+

Documentation

+
+find out how many bytes a four byte long uses in a buffer + +

+
Parameters:
buffer - buffer to check
Returns:
int rc: number of bytes used in buffer +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_VarBufToLong.html b/src/pbl/doc/pbl_VarBufToLong.html new file mode 100755 index 0000000..b6050d6 --- /dev/null +++ b/src/pbl/doc/pbl_VarBufToLong.html @@ -0,0 +1,27 @@ + + + + + int pbl_VarBufToLong + + +
+

Program Base Library Functions

+
+ +

int pbl_VarBufToLong

( unsigned char* buffer, long* value )

read a four byte long from a variable length buffer
+ + +
+

Documentation

+
+read a four byte long from a variable length buffer + +

+
Parameters:
buffer - buffer to read from +
value - long to read to
Returns:
int rc: the number of bytes used in the buffer +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_errno.html b/src/pbl/doc/pbl_errno.html new file mode 100755 index 0000000..47a45e8 --- /dev/null +++ b/src/pbl/doc/pbl_errno.html @@ -0,0 +1,23 @@ + + + + + extern int pbl_errno + + +
+

Program Base Library Functions

+
+ +

extern int pbl_errno

integer value used for returning error codes
+ + +
+

Documentation

+
+integer value used for returning error codes
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_errstr.html b/src/pbl/doc/pbl_errstr.html new file mode 100755 index 0000000..c4847ce --- /dev/null +++ b/src/pbl/doc/pbl_errstr.html @@ -0,0 +1,23 @@ + + + + + extern char* pbl_errstr + + +
+

Program Base Library Functions

+
+ +

extern char* pbl_errstr

character buffer used for returning error strings
+ + +
+

Documentation

+
+character buffer used for returning error strings
+

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_malloc.html b/src/pbl/doc/pbl_malloc.html new file mode 100755 index 0000000..40b4671 --- /dev/null +++ b/src/pbl/doc/pbl_malloc.html @@ -0,0 +1,28 @@ + + + + + void* pbl_malloc + + +
+

Program Base Library Functions

+
+ +

void* pbl_malloc

( char* tag, size_t size )

replacement for malloc
+ + +
+

Documentation

+
+replacement for malloc + +

+
Parameters:
tag - tag used for memory leak detection +
size - number of bytes to allocate
Returns:
void * retptr == NULL: OUT OF MEMORY +
void * retptr != NULL: pointer to buffer allocated +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_malloc0.html b/src/pbl/doc/pbl_malloc0.html new file mode 100755 index 0000000..18157fa --- /dev/null +++ b/src/pbl/doc/pbl_malloc0.html @@ -0,0 +1,28 @@ + + + + + void* pbl_malloc0 + + +
+

Program Base Library Functions

+
+ +

void* pbl_malloc0

( char* tag, size_t size )

replacement for malloc, initializes the memory to 0
+ + +
+

Documentation

+
+replacement for malloc, initializes the memory to 0 + +

+
Parameters:
tag - tag used for memory leak detection +
size - number of bytes to allocate
Returns:
void * retptr == NULL: OUT OF MEMORY +
void * retptr != NULL: pointer to buffer allocated +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_mem2dup.html b/src/pbl/doc/pbl_mem2dup.html new file mode 100755 index 0000000..a4f40dd --- /dev/null +++ b/src/pbl/doc/pbl_mem2dup.html @@ -0,0 +1,31 @@ + + + + + void* pbl_mem2dup + + +
+

Program Base Library Functions

+
+ +

void* pbl_mem2dup

( char* tag, void* mem1, size_t len1,
  void* mem2, size_t len2 )

duplicate and concatenate two memory buffers
+ + +
+

Documentation

+
+duplicate and concatenate two memory buffers + +

+
Parameters:
tag - tag used for memory leak detection +
mem1 - first buffer to duplicate +
len1 - length of first buffer +
mem2 - second buffer to duplicate +
len2 - length of second buffer
Returns:
void * retptr == NULL: OUT OF MEMORY +
void * retptr != NULL: pointer to new buffer allocated +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_memcmp.html b/src/pbl/doc/pbl_memcmp.html new file mode 100755 index 0000000..08b5bbc --- /dev/null +++ b/src/pbl/doc/pbl_memcmp.html @@ -0,0 +1,31 @@ + + + + + int pbl_memcmp + + +
+

Program Base Library Functions

+
+ +

int pbl_memcmp

( void* left, size_t llen, void* right,
  size_t rlen )

compare two memory buffers, similar to memcmp
+ + +
+

Documentation

+
+compare two memory buffers, similar to memcmp + +

+
Parameters:
left - first buffer for compare +
llen - length of that buffer +
right - second buffer for compare +
rlen - length of that buffer
Returns:
int rc < 0: left is smaller than right +
int rc == 0: left and right are equal +
int rc > 0: left is bigger than right +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_memcmplen.html b/src/pbl/doc/pbl_memcmplen.html new file mode 100755 index 0000000..31377bd --- /dev/null +++ b/src/pbl/doc/pbl_memcmplen.html @@ -0,0 +1,29 @@ + + + + + int pbl_memcmplen + + +
+

Program Base Library Functions

+
+ +

int pbl_memcmplen

( void* left, size_t llen, void* right,
  size_t rlen )

find out how many starting bytes of two buffers are equal
+ + +
+

Documentation

+
+find out how many starting bytes of two buffers are equal + +

+
Parameters:
left - first buffer for compare +
llen - length of that buffer +
right - second buffer for compare +
rlen - length of that buffer
Returns:
int rc: number of equal bytes +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_memdup.html b/src/pbl/doc/pbl_memdup.html new file mode 100755 index 0000000..257490a --- /dev/null +++ b/src/pbl/doc/pbl_memdup.html @@ -0,0 +1,29 @@ + + + + + void* pbl_memdup + + +
+

Program Base Library Functions

+
+ +

void* pbl_memdup

( char* tag, void* data, size_t size )

duplicate a buffer, similar to strdup
+ + +
+

Documentation

+
+duplicate a buffer, similar to strdup + +

+
Parameters:
tag - tag used for memory leak detection +
data - buffer to duplicate +
size - size of that buffer
Returns:
void * retptr == NULL: OUT OF MEMORY +
void * retptr != NULL: pointer to buffer allocated +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/doc/pbl_memlcpy.html b/src/pbl/doc/pbl_memlcpy.html new file mode 100755 index 0000000..5d7e1cf --- /dev/null +++ b/src/pbl/doc/pbl_memlcpy.html @@ -0,0 +1,29 @@ + + + + + size_t pbl_memlcpy + + +
+

Program Base Library Functions

+
+ +

size_t pbl_memlcpy

( void* to, size_t tolen, void* from,
  size_t n )

memcpy with target length check
+ + +
+

Documentation

+
+memcpy with target length check + +

+
Parameters:
to - target buffer to copy to +
tolen - number of bytes in the target buffer +
from - source to copy from +
n - length of source
Returns:
size_t rc: number of bytes copied +

Alphabetic index


+
+This page was generated with the help of DOC++. + + diff --git a/src/pbl/gpl2.txt b/src/pbl/gpl2.txt new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/src/pbl/gpl2.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/pbl/hierFooter.inc b/src/pbl/hierFooter.inc new file mode 100644 index 0000000..9ed7fff --- /dev/null +++ b/src/pbl/hierFooter.inc @@ -0,0 +1,3 @@ +
+Copyright(C) 2003 Peter Graf, this software is distributed under the +GNU Lesser General Public License diff --git a/src/pbl/hierHeader.inc b/src/pbl/hierHeader.inc new file mode 100644 index 0000000..d41e93c --- /dev/null +++ b/src/pbl/hierHeader.inc @@ -0,0 +1,4 @@ +
+

Documentation for PBL

+The Program Base Library +
diff --git a/src/pbl/indexFooter.inc b/src/pbl/indexFooter.inc new file mode 100644 index 0000000..9ed7fff --- /dev/null +++ b/src/pbl/indexFooter.inc @@ -0,0 +1,3 @@ +
+Copyright(C) 2003 Peter Graf, this software is distributed under the +GNU Lesser General Public License diff --git a/src/pbl/indexHeader.inc b/src/pbl/indexHeader.inc new file mode 100644 index 0000000..d41e93c --- /dev/null +++ b/src/pbl/indexHeader.inc @@ -0,0 +1,4 @@ +
+

Documentation for PBL

+The Program Base Library +
diff --git a/src/pbl/jbhash.c b/src/pbl/jbhash.c new file mode 100644 index 0000000..dcc7b58 --- /dev/null +++ b/src/pbl/jbhash.c @@ -0,0 +1,295 @@ +/* + * A durable, recoverable hashtable + * Based on Peter Graf's pblhash, + * Jim Blomo + * $Id$ + */ + +#include +#include +#include +#include + +#include +#include + +const recordid ZERO_RECORDID = {0,0,0}; + +jbHashTable_t* jbHtCreate(int xid, int size) { + + jbHashTable_t *ht; + ht = (jbHashTable_t*)malloc(sizeof(jbHashTable_t)); + + if( ht ) { + recordid * hm = malloc(sizeof(recordid) * size); + if(hm) { + memset(hm, 0, sizeof(recordid)*size); + + ht->size = size; + ht->store = Talloc(xid, sizeof(jbHashTable_t)); + ht->hashmap_record = Talloc(xid, sizeof(recordid) * size); + ht->hashmap = NULL; /* Always should be NULL in the store, so that we know if we need to read it in */ + Tset(xid, ht->store, ht); + ht->hashmap = hm; + Tset(xid, ht->hashmap_record, ht->hashmap); + ht->iterIndex = 0; + ht->iterData = NULL; + + return ht; + } else { + free(ht); + return NULL; + } + } + + return NULL; +} + +int jbHtValid(int xid, jbHashTable_t *ht) { + + int ret; + jbHashTable_t *test = (jbHashTable_t*)malloc(sizeof(jbHashTable_t)); + Tread(xid, ht->store, test); + ret = ( test->store.size == ht->store.size + && test->store.slot == ht->store.slot + && test->store.page == ht->store.page ); + /* TODO: Check hashmap_record? */ + free(test); + + return ret; +} + +/** + * Hash function generator, taken directly from pblhash + */ +static int hash( const unsigned char * key, size_t keylen, int size ) { + int ret = 104729; + + for( ; keylen-- > 0; key++ ) + { + if( *key ) + { + ret *= *key + keylen; + ret %= size; + } + } + + return( ret % size ); +} + +/** Should be called the first time ht->hashmap is accessed by a library function. + Checks to see if the hashmap record has been read in, reads it if necessary, and then + returns a pointer to it. */ +static recordid* _getHashMap(int xid, jbHashTable_t *ht) { + if(! ht->hashmap) { + ht->hashmap = malloc(sizeof(recordid) * ht->size); + Tread(xid, ht->hashmap_record, ht->hashmap); + } + return ht->hashmap; +} + +int jbHtInsert(int xid, jbHashTable_t *ht, const byte *key, size_t keylen, const byte *dat, size_t datlen) { + + int index = hash( key, keylen, ht->size); + recordid rid = _getHashMap(xid, ht)[index]; + byte *newd; + jbHashItem_t newi; + + if( rid.size == 0 ) { /* nothing with this hash has been inserted */ + + newi.store = Talloc(xid, sizeof(jbHashItem_t)+keylen+datlen); + newd = malloc(sizeof(jbHashItem_t)+keylen+datlen); + newi.keylen = keylen; + newi.datlen = datlen; + newi.next = ZERO_RECORDID; + memcpy(newd, &newi, sizeof(jbHashItem_t)); + memcpy(newd+sizeof(jbHashItem_t), key, keylen); + memcpy(newd+sizeof(jbHashItem_t)+keylen, dat, datlen); + Tset(xid, newi.store, newd); + + ht->hashmap[index] = newi.store; + /* Tset(xid, ht->store, ht); */ + Tset(xid, ht->hashmap_record, ht->hashmap); + + free(newd); + + } else { + + byte *item = NULL; + + do { + + free(item); /* NULL ignored by free */ + item = malloc(rid.size); + Tread(xid, rid, item); + if( ((jbHashItem_t*)item)->keylen == keylen && !memcmp(key, item+sizeof(jbHashItem_t), keylen)) { + memcpy(item+sizeof(jbHashItem_t)+keylen, dat, ((jbHashItem_t*)item)->datlen); + Tset(xid, ((jbHashItem_t*)item)->store, item); + free(item); + return 0; + } + rid = ((jbHashItem_t*)item)->next; /* could go off end of list */ + } while( ((jbHashItem_t*)item)->next.size != 0 ); + /* now item is the tail */ + + newi.store = Talloc(xid, sizeof(jbHashItem_t)+keylen+datlen); + newd = malloc(sizeof(jbHashItem_t)+keylen+datlen); + newi.keylen = keylen; + newi.datlen = datlen; + newi.next = ZERO_RECORDID; + memcpy(newd, &newi, sizeof(jbHashItem_t)); + memcpy(newd+sizeof(jbHashItem_t), key, keylen); + memcpy(newd+sizeof(jbHashItem_t)+keylen, dat, datlen); + Tset(xid, newi.store, newd); + + ((jbHashItem_t*)item)->next = newi.store; + Tset(xid, ((jbHashItem_t*)item)->store, item); + free(item); + free(newd); + } + + return 0; +} + +int jbHtLookup( int xid, jbHashTable_t *ht, const byte *key, size_t keylen, byte *buf ) { + + int index = hash(key, keylen, ht->size); + recordid rid = _getHashMap(xid, ht)[index]; + if( rid.size == 0 ) { /* nothing inserted with this hash */ + return -1; + } else { + byte *item = NULL; + item = malloc(rid.size); + Tread(xid, rid, item); + + for( ; !(((jbHashItem_t*)item)->keylen == keylen && !memcmp(key, item+sizeof(jbHashItem_t), keylen)); + rid = ((jbHashItem_t*)item)->next ) { + if( rid.size == 0) { /* at the end of the list and not found */ + return -1; + } + free(item); + item = malloc(rid.size); + Tread(xid, rid, item); + } + /* rid is what we want */ + + memcpy(buf, item+sizeof(jbHashItem_t)+((jbHashItem_t*)item)->keylen, ((jbHashItem_t*)item)->datlen); + free(item); + return 0; + } + + return 0; +} + +int jbHtRemove( int xid, jbHashTable_t *ht, const byte *key, size_t keylen, byte *buf ) { + + int index = hash(key, keylen, ht->size); + recordid rid = _getHashMap(xid, ht)[index]; + if( rid.size == 0) { /* nothing inserted with this hash */ + return -1; + } else { + byte *del = malloc(rid.size); + Tread(xid, rid, del); + if( ((jbHashItem_t*)del)->keylen == keylen && !memcmp(key, del+sizeof(jbHashItem_t), keylen) ) { + /* the head is the entry to be removed */ + if( buf ) { + memcpy( buf, del+sizeof(jbHashItem_t*)+keylen, ((jbHashItem_t*)del)->datlen); + } + ht->hashmap[index] = ((jbHashItem_t*)del)->next; + /* Tset(xid, ht->store, ht); */ + Tset(xid, ht->hashmap_record, ht->hashmap); + /* TODO: dealloc rid */ + free(del); + return 0; + } else { + byte * prevd = NULL; + while( ((jbHashItem_t*)del)->next.size ) { + free(prevd); /* free will ignore NULL args */ + prevd = del; + rid = ((jbHashItem_t*)del)->next; + del = malloc(rid.size); + Tread(xid, rid, del); + if( ((jbHashItem_t*)del)->keylen == keylen && !memcmp(key, del+sizeof(jbHashItem_t), keylen) ) { + if( buf ) { + memcpy( buf, del+sizeof(jbHashItem_t)+keylen, ((jbHashItem_t*)del)->datlen); + } + ((jbHashItem_t*)prevd)->next = ((jbHashItem_t*)del)->next; + Tset(xid, ((jbHashItem_t*)prevd)->store, prevd); + /* TODO: dealloc rid */ + free(prevd); + free(del); + return 0; + } + } + /* could not find exact key */ + + free(prevd); + free(del); + return -1; + } + } + + assert( 0 ); /* should not get here */ + return -1; +} + +int jbHtFirst( int xid, jbHashTable_t *ht, byte *buf ) { + + ht->iterIndex = 0; + ht->iterData = NULL; + return jbHtNext( xid, ht, buf); +} + +int jbHtNext( int xid, jbHashTable_t *ht, byte *buf ) { + _getHashMap(xid, ht); + if( ht->iterData && (((jbHashItem_t*)(ht->iterData))->next.size != 0) ) { + recordid next = ((jbHashItem_t*)(ht->iterData))->next; + free( ht->iterData ); + ht->iterData = malloc(next.size); + Tread(xid, next, ht->iterData); + } else { + while(ht->iterIndex < ht->size) { + if( ht->hashmap[ht->iterIndex].size ) + break; + else + ht->iterIndex++; + } + if( ht->iterIndex == ht->size) /* went through and found no data */ + return -1; + + free( ht->iterData ); + ht->iterData = malloc(ht->hashmap[ht->iterIndex].size); /* to account for the last post incr */ + Tread(xid, ht->hashmap[ht->iterIndex++], ht->iterData); /* increment for next round */ + } + + return jbHtCurrent(xid, ht, buf); +} + +int jbHtCurrent(int xid, jbHashTable_t *ht, byte *buf) { + + if( ht->iterData ) { + memcpy(buf, ht->iterData + sizeof(jbHashItem_t) + ((jbHashItem_t*)(ht->iterData))->keylen, ((jbHashItem_t*)(ht->iterData))->datlen); + return 0; + } + return -1; +} + + +int jbHtCurrentKey(int xid, jbHashTable_t *ht, byte *buf) { + + if( ht->iterData ) { + memcpy(buf, ht->iterData + sizeof(jbHashItem_t), ((jbHashItem_t*)(ht->iterData))->keylen); + return 0; + } + return -1; +} + +int jbHtDelete(int xid, jbHashTable_t *ht) { + + /* deralloc ht->store */ + + if(ht->hashmap) { free(ht->hashmap); } + free(ht); + + return 0; +} diff --git a/src/pbl/lgpl2_1.txt b/src/pbl/lgpl2_1.txt new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/src/pbl/lgpl2_1.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/src/pbl/license.txt b/src/pbl/license.txt new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/src/pbl/license.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/src/pbl/makefile-old b/src/pbl/makefile-old new file mode 100644 index 0000000..8039c79 --- /dev/null +++ b/src/pbl/makefile-old @@ -0,0 +1,64 @@ +# +# simple makefile to make the pbl library and the test frame +# +AR= /usr/bin/ar +RANLIB= /usr/bin/ar ts +IPATH= -I. +CFLAGS= -g -Wall -O3 ${IPATH} ${CFLAGS_USR} +CC= gcc + +INCLIB = + +LIB_OBJS = pbl.o pblhash.o pblkf.o pblisam.o jbhash.o +THELIB = libpbl.a + +EXE_OBJS1 = pblhttst.o +THEEXE1 = pblhttst + +EXE_OBJS2 = pblkftst.o +THEEXE2 = pblkftst + +EXE_OBJS3 = pbliftst.o +THEEXE3 = pbliftst + +EXE_OBJS4 = pblkfblockprint.o +THEEXE4 = pblkfblockprint + +all: $(THELIB) $(THEEXE1) $(THEEXE2) $(THEEXE3) $(THEEXE4) + +$(THELIB): $(LIB_OBJS) + $(AR) rc $(THELIB) $? + $(RANLIB) $(THELIB) + +$(THEEXE1): $(EXE_OBJS1) $(THELIB) + $(CC) -O2 -o $(THEEXE1) $(EXE_OBJS1) $(THELIB) $(INCLIB) + +$(THEEXE2): $(EXE_OBJS2) $(THELIB) + $(CC) -O2 -o $(THEEXE2) $(EXE_OBJS2) $(THELIB) $(INCLIB) + +$(THEEXE3): $(EXE_OBJS3) $(THELIB) + $(CC) -O2 -o $(THEEXE3) $(EXE_OBJS3) $(THELIB) $(INCLIB) + +$(THEEXE4): $(EXE_OBJS4) $(THELIB) + $(CC) -O2 -o $(THEEXE4) $(EXE_OBJS4) $(THELIB) $(INCLIB) + +test: $(THEEXE3) + mkdir -p isamtest/ + rm -f isamtest/* + $(THEEXE3) ISAM0001.TST > /dev/null + diff ISAM0001.TST pbliftst.log || ( echo test case 1 failed; exit 1 ) + echo passed test case 1 + $(THEEXE3) ISAM0004.TST > /dev/null + diff ISAM0004.TST pbliftst.log || ( echo test case 4 failed; exit 1 ) + echo passed test case 1 + rm -f isamtest/* + echo !!! all tests passed !!! + +clean: + rm -f ${THELIB} ${LIB_OBJS} core + rm -f ${THEEXE1} ${EXE_OBJS1} + rm -f ${THEEXE2} ${EXE_OBJS2} + rm -f ${THEEXE3} ${EXE_OBJS3} + rm -f ${THEEXE4} ${EXE_OBJS4} + rm -f isamtest/* + diff --git a/src/pbl/pbl.c b/src/pbl/pbl.c new file mode 100644 index 0000000..5548b51 --- /dev/null +++ b/src/pbl/pbl.c @@ -0,0 +1,723 @@ +/* + pbl.c - basic library functions + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + $Log$ + Revision 1.1 2004/06/24 21:11:34 sears + Initial revision + + Revision 1.3 2004/05/26 09:55:31 sears + Misc bugfixes / optimizations. + + Revision 1.2 2003/12/11 09:21:20 jim + update includes + + Revision 1.1 2003/12/11 09:10:48 jim + pbl + + Revision 1.2 2002/09/12 20:47:13 peter + added the isam file handling to the library + + +*/ +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char* _PBL_id = "$Id$"; +static int _PBL_fct() { return( _PBL_id ? 0 : _PBL_fct() ); } + +#include +#include +#include +#include +#include + +#include + +/*****************************************************************************/ +/* #defines */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* typedefs */ +/*****************************************************************************/ + +/* + * the type is only needed if we keep a heap memory trace + */ +typedef struct pbl_memtrace_s +{ + char * tag; /* tag used by calling function */ + time_t time; /* time when the chunk of memory was requested */ + void * data; /* pointer to data that was allocated */ + size_t size; /* number of bytes allocated */ + + struct pbl_memtrace_s * next; /* memory chunks are kept in a linear */ + struct pbl_memtrace_s * prev; /* list */ + +} pbl_memtrace_t; + +/*****************************************************************************/ +/* globals */ +/*****************************************************************************/ + +#ifdef PBL_MEMTRACE + +/* + * head and tail of known memory chunks + */ +static pbl_memtrace_t * pbl_memtrace_head; +static pbl_memtrace_t * pbl_memtrace_tail; + +/* + * number of memory chunks known + */ +static long pbl_nmem_chunks = 0; + +/* + * total size of all chunks known + */ +static long pbl_nmem_size = 0; + +#endif + +static char pbl_errbuf[ PBL_ERRSTR_LEN + 1 ]; + +int pbl_errno; +char * pbl_errstr = pbl_errbuf; + +/*****************************************************************************/ +/* functions */ +/*****************************************************************************/ + +#ifdef PBL_MEMTRACE + +/* + * log a line for all memory chunks that are allocated for more than + * 3 minutes, or if call at the end of the program, log all chunks known + */ +void pbl_memtrace_out( int checktime ) +{ + static int first = 1; + pbl_memtrace_t * memtrace; + pbl_memtrace_t * tmp; + + char * outpath = "pblmemtrace.log"; + FILE * outfile = NULL; + time_t now = time( 0 ); + char * nowstr = NULL; + char * timestr = NULL; + + if( !pbl_memtrace_head ) + { + return; + } + + memtrace = pbl_memtrace_head; + while( memtrace ) + { + if( checktime && ( now - memtrace->time < 180 )) + { + break; + } + + if( !outfile ) + { + if( first ) + { + first = 0; + outfile = fopen( outpath, "w" ); + if( outfile ) + { + fprintf( outfile, ">>memtrace at %s", ctime( &now )); + } + } + else + { + outfile = fopen( outpath, "a" ); + } + + if( !outfile ) + { + break; + } + } + + tmp = memtrace; + memtrace = memtrace->next; + + if( !nowstr ) + { + nowstr = strdup( ctime( &now )); + } + timestr = ctime( &(tmp->time)); + + fprintf( outfile, "%s %.*s: %.*s %06ld %x %ld %ld \"%s\"\n", + checktime ? ">" : "e", + 8, nowstr ? nowstr + 11 : "unknown", + 8, timestr ? timestr + 11 : "unknown", + (long)tmp->size, + tmp->data - NULL, + pbl_nmem_chunks, pbl_nmem_size, tmp->tag + ); + + PBL_LIST_UNLINK( pbl_memtrace_head, pbl_memtrace_tail, + tmp, next, prev ); + free( tmp ); + } + + if( nowstr ) + { + free( nowstr ); + } + + if( outfile ) + { + fclose( outfile ); + } +} + +/* + * remember a memory chunk that was allocated by some function + */ +void pbl_memtrace_create( +char * tag, +void * data, +size_t size +) +{ + pbl_memtrace_t * memtrace; + + memtrace = malloc( sizeof( pbl_memtrace_t )); + if( !memtrace ) + { + return; + } + + memtrace->tag = tag; + memtrace->time = time( 0 ); + memtrace->data = data; + memtrace->size = size; + + PBL_LIST_APPEND( pbl_memtrace_head, pbl_memtrace_tail, + memtrace, next, prev ); + + pbl_nmem_chunks++; + pbl_nmem_size += size; + + pbl_memtrace_out( 1 ); +} + +/* + * remove a memory from the chunk list, the caller freed the memory + */ +void pbl_memtrace_delete( +void * data +) +{ + pbl_memtrace_t * memtrace; + + for( memtrace = pbl_memtrace_head; memtrace; memtrace = memtrace->next ) + { + if( memtrace->data == data ) + { + pbl_nmem_chunks--; + pbl_nmem_size -= memtrace->size; + + PBL_LIST_UNLINK( pbl_memtrace_head, pbl_memtrace_tail, + memtrace, next, prev ); + free( memtrace ); + break; + } + } +} + +#endif /* PBL_MEMTRACE */ + +/** + * replacement for malloc + * + * @return void * retptr == NULL: OUT OF MEMORY + * @return void * retptr != NULL: pointer to buffer allocated + */ +void * pbl_malloc( +char * tag, /** tag used for memory leak detection */ +size_t size /** number of bytes to allocate */ +) +{ + void * ptr; + + if( !tag ) + { + tag = "pbl_malloc"; + } + + ptr = malloc( size ); + if( !ptr ) + { + snprintf( pbl_errstr, PBL_ERRSTR_LEN, + "%s: failed to malloc %d bytes\n", tag, size ); + pbl_errno = PBL_ERROR_OUT_OF_MEMORY; + return( 0 ); + } + +#ifdef PBL_MEMTRACE + pbl_memtrace_create( tag, ptr, size ); +#endif + + return( ptr ); +} + +/** + * replacement for malloc, initializes the memory to 0 + * + * @return void * retptr == NULL: OUT OF MEMORY + * @return void * retptr != NULL: pointer to buffer allocated + */ +void * pbl_malloc0( +char * tag, /** tag used for memory leak detection */ +size_t size /** number of bytes to allocate */ +) +{ + void * ptr = malloc( size ); + if( !ptr ) + { + snprintf( pbl_errstr, PBL_ERRSTR_LEN, + "failed to malloc %d bytes\n", size ); + pbl_errno = PBL_ERROR_OUT_OF_MEMORY; + return( 0 ); + } + + memset( ptr, 0, size ); + +#ifdef PBL_MEMTRACE + assert(0); + pbl_memtrace_create( tag, ptr, size ); +#endif + + return( ptr ); +} + + +/** + * duplicate a buffer, similar to strdup + * + * @return void * retptr == NULL: OUT OF MEMORY + * @return void * retptr != NULL: pointer to buffer allocated + */ +void * pbl_memdup( +char * tag, /** tag used for memory leak detection */ +void * data, /** buffer to duplicate */ +size_t size /** size of that buffer */ +) +{ + void * ptr = malloc( size ); + if( !ptr ) + { + snprintf( pbl_errstr, PBL_ERRSTR_LEN, + "failed to malloc %d bytes\n", size ); + pbl_errno = PBL_ERROR_OUT_OF_MEMORY; + return( 0 ); + } + + memcpy( ptr, data, size ); + +#ifdef PBL_MEMTRACE + pbl_memtrace_create( tag, ptr, size ); +#endif + + return( ptr ); +} + +/** + * duplicate and concatenate two memory buffers + * + * @return void * retptr == NULL: OUT OF MEMORY + * @return void * retptr != NULL: pointer to new buffer allocated + */ + +void * pbl_mem2dup( +char * tag, /** tag used for memory leak detection */ +void * mem1, /** first buffer to duplicate */ +size_t len1, /** length of first buffer */ +void * mem2, /** second buffer to duplicate */ +size_t len2 /** length of second buffer */ +) +{ + void * ret; + + if( !tag ) + { + tag = "pbl_mem2dup"; + } + + ret = pbl_malloc( tag, len1 + len2 ); + if( !ret ) + { + return( 0 ); + } + + if( len1 ) + { + memcpy( ret, mem1, len1 ); + } + + if( len2 ) + { + memcpy( ((char*)ret) + len1, mem2, len2 ); + } + + return( ret ); +} + +/** + * memcpy with target length check + * + * @return size_t rc: number of bytes copied + */ +size_t pbl_memlcpy( +void * to, /** target buffer to copy to */ +size_t tolen, /** number of bytes in the target buffer */ +void * from, /** source to copy from */ +size_t n /** length of source */ +) +{ + size_t l = n > tolen ? tolen : n; + + memcpy( to, from, l ); + return( l ); +} + +/** + * find out how many starting bytes of two buffers are equal + * + * @return int rc: number of equal bytes + */ + +int pbl_memcmplen( +void * left, /** first buffer for compare */ +size_t llen, /** length of that buffer */ +void * right, /** second buffer for compare */ +size_t rlen /** length of that buffer */ +) +{ + unsigned int i; + unsigned char * l = ( unsigned char * )left; + unsigned char * r = ( unsigned char * )right; + + if( llen > rlen ) + { + llen = rlen; + } + + for( i = 0; i < llen; i++ ) + { + if( *l++ != *r++ ) + { + break; + } + } + + return( i ); +} + +/** + * compare two memory buffers, similar to memcmp + * + * @return int rc < 0: left is smaller than right + * @return int rc == 0: left and right are equal + * @return int rc > 0: left is bigger than right + */ + +int pbl_memcmp( +void * left, /** first buffer for compare */ +size_t llen, /** length of that buffer */ +void * right, /** second buffer for compare */ +size_t rlen /** length of that buffer */ +) +{ + size_t len; + int rc; + + /* + * a buffer with a length 0 is logically smaller than any other buffer + */ + if( !llen ) + { + if( !rlen ) + { + return( 0 ); + } + return( -1 ); + } + if( !rlen ) + { + return( 1 ); + } + + /* + * use the shorter of the two buffer lengths for the memcmp + */ + if( llen <= rlen ) + { + len = llen; + } + else + { + len = rlen; + } + + /* + * memcmp is used, therefore the ordering is ascii + */ + rc = memcmp( left, right, len ); + if( rc ) + { + return( rc ); + } + + /* + * if the two buffers are equal in the first len bytes, but don't have + * the same lengths, the longer one is logically bigger + */ + return( (int) ( ((int)llen) - ((int)rlen) )); +} + +/** + * copy a two byte short to a two byte buffer + */ +void pbl_ShortToBuf( +unsigned char * buf, /** buffer to copy to */ +int s /** short value to copy */ +) +{ + *buf++ = ( unsigned char ) ( s >> 8 ); + *buf = ( unsigned char ) ( s ); +} + +/** + * read a two byte short from a two byte buffer + * + * @return int rc: the short value read + */ +int pbl_BufToShort( +unsigned char * buf /** buffer to read from */ +) +{ + unsigned int s = (( unsigned int ) ( *buf++ )) << 8; + + s |= *buf; + return( s ); +} + +/** + * copy a four byte long to a four byte buffer + */ +void pbl_LongToBuf( +unsigned char * buf, /** buffer to copy to */ +long l /** long value to copy */ +) +{ + + *buf++ = (unsigned char ) ( ( l >> 24 )); + *buf++ = (unsigned char ) ( ( l >> 16 )); + *buf++ = (unsigned char ) ( ( l >> 8 )); + *buf = (unsigned char ) ( l ); +} + +/** + * read a four byte long from a four byte buffer + * + * @return long ret: the long value read + */ +long pbl_BufToLong( +unsigned char * buf /** the buffer to read from */ +) +{ + unsigned long l = ((( unsigned long ) ( *buf++ ) )) << 24; + + l |= ((( unsigned long ) ( *buf++ ) ) ) << 16; + l |= ((( unsigned long ) ( *buf++ ) ) ) << 8; + l |= *buf; + + return( l ); +} + +/** + * copy a four byte long to a variable length buffer + * + * @return int rc: the number of bytes used in the buffer + */ +int pbl_LongToVarBuf( unsigned char * buffer, unsigned long value ) +{ + if( value <= 0x7f ) + { + *buffer = (unsigned char)value; + return( 1 ); + } + + if( value <= 0x3fff ) + { + *buffer++ = (unsigned char)( value / 0x100 ) | 0x80; + *buffer = (unsigned char)value & 0xff; + return( 2 ); + } + + if( value <= 0x1fffff ) + { + *buffer++ = (unsigned char)( value / 0x10000 ) | 0x80 | 0x40; + *buffer++ = (unsigned char)( value / 0x100 ); + *buffer = (unsigned char)value & 0xff; + return( 3 ); + } + + if( value <= 0x0fffffff ) + { + *buffer++ = (unsigned char)( value / 0x1000000 ) | 0x80 | 0x40 | 0x20; + *buffer++ = (unsigned char)( value / 0x10000 ); + *buffer++ = (unsigned char)( value / 0x100 ); + *buffer = (unsigned char)value & 0xff; + return( 4 ); + } + + *buffer++ = (unsigned char)0xf0; + pbl_LongToBuf( buffer, value ); + + return( 5 ); +} + + +/** + * read a four byte long from a variable length buffer + * + * @return int rc: the number of bytes used in the buffer + */ +int pbl_VarBufToLong( +unsigned char * buffer, /** buffer to read from */ +long * value /** long to read to */ +) +{ + int c = 0xff & *buffer++; + int val; + + if( !( c & 0x80 )) + { + *value = c; + return( 1 ); + } + + if( !( c & 0x40 )) + { + *value = ( c & 0x3f ) * 0x100 + ( *buffer & 0xff ); + return( 2 ); + } + if( !( c & 0x20 )) + { + val = ( c & 0x1f ) * 0x10000; + val += (( *buffer++ ) & 0xff ) * 0x100; + *value = val + (( *buffer ) & 0xff ); + return( 3 ); + } + + if( !( c & 0x10 )) + { + val = ( c & 0x0f ) * 0x1000000; + val += (( *buffer++ ) & 0xff ) * 0x10000; + val += (( *buffer++ ) & 0xff ) * 0x100; + *value = val + (( *buffer ) & 0xff ); + return( 4 ); + } + + *value = pbl_BufToLong( buffer ); + return( 5 ); +} + +/** + * find out how many bytes a four byte long would use in a buffer + * + * @return int rc: number of bytes used in buffer + */ + +int pbl_LongSize( +unsigned long value /** value to check */ +) +{ + if( value <= 0x7f ) + { + return( 1 ); + } + + if( value <= 0x3fff ) + { + return( 2 ); + } + + if( value <= 0x1fffff ) + { + return( 3 ); + } + + if( value <= 0x0fffffff ) + { + return( 4 ); + } + + return( 5 ); +} + +/** + * find out how many bytes a four byte long uses in a buffer + * + * @return int rc: number of bytes used in buffer + */ + +int pbl_VarBufSize( +unsigned char * buffer /** buffer to check */ +) +{ + int c = 0xff & *buffer; + + if( !( c & 0x80 )) + { + return( 1 ); + } + + if( !( c & 0x40 )) + { + return( 2 ); + } + + if( !( c & 0x20 )) + { + return( 3 ); + } + + if( !( c & 0x10 )) + { + return( 4 ); + } + + return( 5 ); +} + diff --git a/src/pbl/pbl.dxx b/src/pbl/pbl.dxx new file mode 100644 index 0000000..6bcc7a9 --- /dev/null +++ b/src/pbl/pbl.dxx @@ -0,0 +1,81 @@ +/** @name A: Introduction + +PBL is a C library of functions that can be used in a C or C++ project. +PBL is highly portable and compiles warning free on Linux gcc, Windows +Cygwin gcc and Windows Microsoft Visual C++, V 6.0. + +

+

VERSIONS:

+
    +Version 1.00, Thu Sep 5 2002 - initial version +

    +Version 1.01, Fri Nov 1 2002 - improved memory management, see pblkf.c Revision 1.2, 1.3 +

    +Version 1.02, Mit Feb 19 2003 - fixed a bug reported by Csaba Pálos, see pblisam.c Revision 1.2 +

+ +

+

CODE:

+
    +The code of the PBL library includes: +

    +PBL BASE - some base functions, +see pbl_* functions, +

    +PBL HASH - an open source memory hash table implementation, +see pblHt* functions, +

      +Features +
        +
      • random access lookups +
      • sequential access +
      • regression test frame +
      +
    +PBL KEYFILE - an open source key file implementation, +see pblKf* functions, +
      +Features +
        +
      • ultra fast B* tree implementation for random lookups +
      • transaction handling +
      • sequential access methods +
      • embedable small footprint, < 35 Kb +
      • arbitrary size files, up to 4 terrabytes +
      • arbitrary number of records per file, up to 2 ^^ 48 records +
      • duplicate keys +
      • advanced key compression for minimal size B trees +
      • keylength up to 255 bytes +
      • regression test frame +
      +
    +PBL ISAM - an open source ISAM file implementation, +see pblIsam* functions +
      +Features +
        +
      • ultra fast B* tree implementation for random lookups +
      • transaction handling +
      • sequential access methods +
      • embedable small footprint, < 75 Kb +
      • arbitrary size files, up to 4 terrabytes +
      • arbitrary number of records per file, up to 2 ^^ 48 records +
      • duplicate keys and unique keys +
      • advanced key compression for minimal size index files +
      • keylength up to 255 bytes per index +
      • keylength up to 1024 per record +
      • regression test frame +
      +
    +
+ +*/ +//@Include: pbl.h +//@Include: pbl.c +//@Include: pblhash.c +//@Include: pblhttst.c +//@Include: pblkf.c +//@Include: pblkftst.c +//@Include: pblisam.c +//@Include: pbliftst.c + diff --git a/src/pbl/pblhash.c b/src/pbl/pblhash.c new file mode 100644 index 0000000..c88e93a --- /dev/null +++ b/src/pbl/pblhash.c @@ -0,0 +1,532 @@ +/* + pblhash.c - hash table implementation + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + $Log$ + Revision 1.1 2004/06/24 21:11:54 sears + Initial revision + + Revision 1.4 2004/05/26 09:55:31 sears + Misc bugfixes / optimizations. + + Revision 1.3 2003/12/11 10:48:16 jim + compiles, not link. added quasi-pincount, shadow pages + + Revision 1.2 2003/12/11 09:21:20 jim + update includes + + Revision 1.1 2003/12/11 09:10:48 jim + pbl + + Revision 1.2 2002/09/12 20:46:30 peter + added the isam file handling to the library + + Revision 1.1 2002/09/05 13:45:01 peter + Initial revision + + +*/ + +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char* rcsid = "$Id$"; +static int rcsid_fct() { return( rcsid ? 0 : rcsid_fct() ); } + +#include +#include +#include + +#include + +/*****************************************************************************/ +/* #defines */ +/*****************************************************************************/ +/*#define PBL_HASHTABLE_SIZE 1019*/ +#define PBL_HASHTABLE_SIZE 100003 + +/*****************************************************************************/ +/* typedefs */ +/*****************************************************************************/ + +typedef struct pbl_hashitem_s +{ + void * key; + size_t keylen; + + void * data; + + struct pbl_hashitem_s * next; + struct pbl_hashitem_s * prev; + + struct pbl_hashitem_s * bucketnext; + struct pbl_hashitem_s * bucketprev; + +} pbl_hashitem_t; + +typedef struct pbl_hashbucket_s +{ + pbl_hashitem_t * head; + pbl_hashitem_t * tail; + +} pbl_hashbucket_t; + +struct pbl_hashtable_s +{ + char * magic; + int currentdeleted; + pbl_hashitem_t * head; + pbl_hashitem_t * tail; + pbl_hashitem_t * current; + pbl_hashbucket_t * buckets; + +}; +typedef struct pbl_hashtable_s pbl_hashtable_t; + +/*****************************************************************************/ +/* globals */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* functions */ +/*****************************************************************************/ + +static int hash( const unsigned char * key, size_t keylen ) +{ + int ret = 104729; + + for( ; keylen-- > 0; key++ ) + { + if( *key ) + { + ret *= *key + keylen; + ret %= PBL_HASHTABLE_SIZE; + } + } + + return( ret % PBL_HASHTABLE_SIZE ); +} + +/** + * create a new hash table + * + * @return pblHashTable_t * retptr != NULL: pointer to new hash table + * @return pblHashTable_t * retptr == NULL: OUT OF MEMORY + */ +pblHashTable_t * pblHtCreate( void ) +{ + pbl_hashtable_t * ht; + + ht = pbl_malloc0( "pblHtCreate hashtable", sizeof( pbl_hashtable_t ) ); + if( !ht ) + { + return( 0 ); + } + + ht->buckets = pbl_malloc0( "pblHtCreate buckets", + sizeof( pbl_hashbucket_t ) * PBL_HASHTABLE_SIZE); + if( !ht->buckets ) + { + PBL_FREE( ht ); + return( 0 ); + } + + /* + * set the magic marker of the hashtable + */ + ht->magic = rcsid; + + return( ( pblHashTable_t * )ht ); +} + +/** + * insert a key / data pair into a hash table + * + * only the pointer to the data is stored in the hash table + * no space is malloced for the data! + * + * @return int ret == 0: ok + * @return int ret == -1: an error, see pbl_errno: + * @return PBL_ERROR_EXISTS: an item with the same key already exists + * @return PBL_ERROR_OUT_OF_MEMORY: out of memory + */ + +int pblHtInsert( +pblHashTable_t * h, /** hash table to insert to */ +void * key, /** key to insert */ +size_t keylen, /** length of that key */ +void * dataptr /** dataptr to insert */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + pbl_hashbucket_t * bucket = 0; + pbl_hashitem_t * item = 0; + + int hashval = hash( key, keylen ); + + bucket = ht->buckets + hashval; + + if( keylen < (size_t)1 ) + { + /* + * the length of the key can not be smaller than 1 + */ + pbl_errno = PBL_ERROR_EXISTS; + return( -1 ); + } + + for( item = bucket->head; item; item = item->bucketnext ) + { + if(( item->keylen == keylen ) && !memcmp( item->key, key, keylen )) + { + snprintf( pbl_errstr, PBL_ERRSTR_LEN, + "insert of duplicate item in hashtable\n" ); + pbl_errno = PBL_ERROR_EXISTS; + return( -1 ); + } + } + + item = pbl_malloc0( "pblHtInsert hashitem", sizeof( pbl_hashitem_t ) ); + if( !item ) + { + return( -1 ); + } + + item->key = pbl_memdup( "pblHtInsert item->key", key, keylen ); + if( !item->key ) + { + PBL_FREE( item ); + return( -1 ); + } + item->keylen = keylen; + item->data = dataptr; + + /* + * link the item + */ + PBL_LIST_APPEND( bucket->head, bucket->tail, item, bucketnext, bucketprev ); + PBL_LIST_APPEND( ht->head, ht->tail, item, next, prev ); + + ht->current = item; + return( 0 ); +} + +/** + * search for a key in a hash table + * + * @return void * retptr != NULL: pointer to data of item found + * @return void * retptr == NULL: no item found with the given key + * @return PBL_ERROR_NOT_FOUND: + */ + +void * pblHtLookup( +pblHashTable_t * h, /** hash table to search in */ +void * key, /** key to search */ +size_t keylen /** length of that key */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + pbl_hashbucket_t * bucket = 0; + pbl_hashitem_t * item = 0; + + int hashval = hash( key, keylen ); + + bucket = ht->buckets + hashval; + + for( item = bucket->head; item; item = item->bucketnext ) + { + if(( item->keylen == keylen ) && !memcmp( item->key, key, keylen )) + { + ht->current = item; + ht->currentdeleted = 0; + return( item->data ); + } + } + + pbl_errno = PBL_ERROR_NOT_FOUND; + + return( 0 ); +} + +/** + * get data of first key in hash table + * + * This call and \Ref{pblHtNext} can be used in order to loop through all items + * stored in a hash table. + * + *
+   Example:
+
+   for( data = pblHtFirst( h ); data; data = pblHtNext( h ))
+   {
+       do something with the data pointer
+   }
+   
+ + * @return void * retptr != NULL: pointer to data of first item + * @return void * retptr == NULL: the hash table is empty + * @return PBL_ERROR_NOT_FOUND: + */ + +void * pblHtFirst( +pblHashTable_t * h /** hash table to look in */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + pbl_hashitem_t * item = 0; + + item = ht->head; + if( item ) + { + ht->current = item; + ht->currentdeleted = 0; + return( item->data ); + } + + pbl_errno = PBL_ERROR_NOT_FOUND; + return( 0 ); +} + +/** + * get data of next key in hash table + * + * This call and \Ref{pblHtFirst} can be used in order to loop through all items + * stored in a hash table. + * + *
+   Example:
+
+   for( data = pblHtFirst( h ); data; data = pblHtNext( h ))
+   {
+       do something with the data pointer
+   }
+   
+ + * @return void * retptr != NULL: pointer to data of next item + * @return void * retptr == NULL: there is no next item in the hash table + * @return PBL_ERROR_NOT_FOUND: + */ + +void * pblHtNext( +pblHashTable_t * h /** hash table to look in */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + pbl_hashitem_t * item = 0; + + if( ht->current ) + { + if( ht->currentdeleted ) + { + item = ht->current; + } + else + { + item = ht->current->next; + } + ht->currentdeleted = 0; + } + if( item ) + { + ht->current = item; + return( item->data ); + } + + pbl_errno = PBL_ERROR_NOT_FOUND; + return( 0 ); +} + +/** + * get data of current key in hash table + * + * @return void * retptr != NULL: pointer to data of current item + * @return void * retptr == NULL: there is no current item in the hash table + * @return PBL_ERROR_NOT_FOUND: + */ + +void * pblHtCurrent( +pblHashTable_t * h /** hash table to look in */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + + if( ht->current ) + { + return( ht->current->data ); + } + + pbl_errno = PBL_ERROR_NOT_FOUND; + return( 0 ); +} + +/** + * get key of current key in hash table + * + * @return void * retptr != NULL: pointer to data of current item + * @return void * retptr == NULL: there is no current item in the hash table + * @return PBL_ERROR_NOT_FOUND: + */ + +void * pblHtCurrentKey( +pblHashTable_t * h /** hash table to look in */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + + if( ht->current ) + { + return( ht->current->key ); + } + + pbl_errno = PBL_ERROR_NOT_FOUND; + return( 0 ); +} + +/** + * remove an item from the hash table + * + * parameters key and keylen are optional, if they are not given + * the current record is deleted + * + * if the current record is removed the pointer to the current record + * is moved to the next record. + * + *
+   Example:
+
+   for( data = pblHtFirst( h ); data; data = pblHtRemove( h, 0, 0 ))
+   {
+       this loop removes all items from a hash table
+   }
+   
+ * + * if the current record is moved by this function the next call to + * \Ref{pblHtNext} will return the data of the then current record. + * Therefore the following code does what is expected: + * It visits all items of the hash table and removes the expired ones. + * + *
+   for( data = pblHtFirst( h ); data; data = pblHtNext( h ))
+   {
+       if( needs to be deleted( data ))
+       {
+           pblHtRemove( h, 0, 0 );
+       }
+   }
+   
+ + * @return int ret == 0: ok + * @return int ret == -1: an error, see pbl_errno: + * @return PBL_ERROR_NOT_FOUND: the current item is not positioned + * @return or there is no item with the given key + */ + +int pblHtRemove( +pblHashTable_t * h, /** hash table to remove from */ +void * key, /** OPT: key to remove */ +size_t keylen /** OPT: length of that key */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + pbl_hashbucket_t * bucket = 0; + pbl_hashitem_t * item = 0; + + int hashval = 0; + + if( keylen && key ) + { + hashval = hash( key, keylen ); + bucket = ht->buckets + hashval; + + for( item = bucket->head; item; item = item->bucketnext ) + { + if(( item->keylen == keylen ) && !memcmp( item->key, key, keylen )) + { + break; + } + } + } + else + { + item = ht->current; + + if( item ) + { + hashval = hash( item->key, item->keylen ); + bucket = ht->buckets + hashval; + } + } + + if( item ) + { + if( item == ht->current ) + { + ht->currentdeleted = 1; + ht->current = item->next; + } + + /* + * unlink the item + */ + PBL_LIST_UNLINK( bucket->head, bucket->tail, item, + bucketnext, bucketprev ); + PBL_LIST_UNLINK( ht->head, ht->tail, item, next, prev ); + + PBL_FREE( item->key ); + PBL_FREE( item ); + return( 0 ); + } + + pbl_errno = PBL_ERROR_NOT_FOUND; + return( -1 ); +} + +/** + * delete a hash table + * + * the hash table has to be empty! + * + * @return int ret == 0: ok + * @return int ret == -1: an error, see pbl_errno: + * @return PBL_ERROR_EXISTS: the hash table is not empty + */ + +int pblHtDelete( +pblHashTable_t * h /** hash table to delete */ +) +{ + pbl_hashtable_t * ht = ( pbl_hashtable_t * )h; + + if( ht->head ) + { + pbl_errno = PBL_ERROR_EXISTS; + return( -1 ); + } + + PBL_FREE( ht->buckets ); + PBL_FREE( ht ); + + return( 0 ); +} + diff --git a/src/pbl/pblhttst b/src/pbl/pblhttst new file mode 100755 index 0000000000000000000000000000000000000000..16ab92b19a8e0cad023a70e36c7db4f9618c7ef9 GIT binary patch literal 45923 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 literal 0 HcmV?d00001 diff --git a/src/pbl/pblhttst.c b/src/pbl/pblhttst.c new file mode 100644 index 0000000..c44d37a --- /dev/null +++ b/src/pbl/pblhttst.c @@ -0,0 +1,174 @@ +/* + pblhttst.c - hash table test frame + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + 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 + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + $Log$ + Revision 1.1 2004/06/24 21:11:54 sears + Initial revision + + Revision 1.2 2003/12/11 09:21:20 jim + update includes + + Revision 1.1 2003/12/11 09:10:48 jim + pbl + + Revision 1.2 2002/09/12 20:47:01 peter + added the isam file handling to the library + + Revision 1.1 2002/09/05 13:45:02 peter + Initial revision + +*/ + +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char* _PBL_id = "$Id$"; +static int _PBL_fct() { return( _PBL_id ? 0 : _PBL_fct() ); } + +#include +#include +#include + +#include "pbl.h" + +/*****************************************************************************/ +/* #defines */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* typedefs */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* globals */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* functions */ +/*****************************************************************************/ + +/* + * test frame for the hash table library + * + * this test frame calls the hash table library, + * it does not have any parameters, it is meant for + * debugging the hash table library + */ +int pblHASHTABLE_TestFrame( int argc, char * argv[ ] ) +{ + pblHashTable_t * ht; + int rc; + + char * data; + + ht = pblHtCreate(); + fprintf( stdout, "pblHtCreate() ht = %p\n", ht ); + + rc = pblHtInsert( ht, "123", 4, "123" ); + fprintf( stdout, "pblHtInsert( ht, 123, 4, 123 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "124", 4, "124" ); + fprintf( stdout, "pblHtInsert( ht, 124, 4, 124 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "125", 4, "125" ); + fprintf( stdout, "pblHtInsert( ht, 125, 4, 125 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "123", 4, "123" ); + fprintf( stdout, "pblHtInsert( ht, 123, 4, 123 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "123", 3, "123" ); + fprintf( stdout, "pblHtInsert( ht, 123, 3, 123 ) rc = %d\n", rc ); + + data = pblHtLookup( ht, "123", 4 ); + fprintf( stdout, "pblHtLookup( ht, 123, 4 ) data = %s\n", + data ? data : "NULL" ); + + data = pblHtLookup( ht, "123", 3 ); + fprintf( stdout, "pblHtLookup( ht, 123, 3 ) data = %s\n", + data ? data : "NULL" ); + + data = pblHtLookup( ht, "124", 4 ); + fprintf( stdout, "pblHtLookup( ht, 124, 4 ) data = %s\n", + data ? data : "NULL" ); + + data = pblHtLookup( ht, "125", 4 ); + fprintf( stdout, "pblHtLookup( ht, 125, 4 ) data = %s\n", + data ? data : "NULL" ); + + data = pblHtLookup( ht, "126", 4 ); + fprintf( stdout, "pblHtLookup( ht, 126, 4 ) data = %s\n", + data ? data : "NULL" ); + + + for( data = pblHtFirst( ht ); data; data = pblHtNext( ht )) + { + data = pblHtCurrent( ht ); + fprintf( stdout, "pblHtCurrent( ht ) data = %s\n", + data ? data : "NULL" ); + } + + rc = pblHtRemove( ht, "125", 4 ); + fprintf( stdout, "pblHtRemove( ht, 125, 4 ) rc = %d\n", rc ); + + data = pblHtFirst( ht ); + fprintf( stdout, "pblHtFirst( ht ) data = %s\n", data ? data : "NULL" ); + + rc = pblHtDelete( ht ); + fprintf( stdout, "pblHtDelete( ht, 125, 4 ) rc = %d\n", rc ); + + while( !pblHtRemove( ht, 0, 0 )); + + rc = pblHtInsert( ht, "123", 4, "123" ); + fprintf( stdout, "pblHtInsert( ht, 123, 4, 123 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "124", 4, "124" ); + fprintf( stdout, "pblHtInsert( ht, 124, 4, 124 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "125", 4, "125" ); + fprintf( stdout, "pblHtInsert( ht, 125, 4, 125 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "123", 4, "123" ); + fprintf( stdout, "pblHtInsert( ht, 123, 4, 123 ) rc = %d\n", rc ); + + rc = pblHtInsert( ht, "123", 3, "123" ); + fprintf( stdout, "pblHtInsert( ht, 123, 3, 123 ) rc = %d\n", rc ); + + + for( data = pblHtFirst( ht ); data; data = pblHtNext( ht )) + { + pblHtRemove( ht, 0, 0 ); + } + + rc = pblHtDelete( ht ); + fprintf( stdout, "pblHtDelete( ht ) rc = %d\n", rc ); + + return( rc ); +} + +int main( int argc, char * argv[] ) +{ + return( pblHASHTABLE_TestFrame( argc, argv )); +} + diff --git a/src/pbl/pblhttstdeb.dsp b/src/pbl/pblhttstdeb.dsp new file mode 100644 index 0000000..6e06311 --- /dev/null +++ b/src/pbl/pblhttstdeb.dsp @@ -0,0 +1,89 @@ +# Microsoft Developer Studio Project File - Name="pblhttst" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=pblhttst - Win32 Debug mt 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 "pblhttstdeb.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 "pblhttstdeb.mak" CFG="pblhttst - Win32 Debug mt static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pblhttst - Win32 Debug mt static" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "pblhttst" +# PROP BASE Intermediate_Dir "pblhttst" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "winbuild\debugbin" +# PROP Intermediate_Dir "winbuild\debugtmp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /D "DEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT CPP /YX +# 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 wsock32.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 /machine:I386 +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 wsock32.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 /debug /machine:I386 /out:"winbuild\debugbin\pblhttst.exe" +# Begin Target + +# Name "pblhttst - Win32 Debug mt static" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\pbl.c +# End Source File +# Begin Source File + +SOURCE=.\pblhash.c +# End Source File +# Begin Source File + +SOURCE=.\pblhttst.c +# End Source File +# Begin Source File + +SOURCE=.\pblkf.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\pbl.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/src/pbl/pblhttstdeb.dsw b/src/pbl/pblhttstdeb.dsw new file mode 100755 index 0000000..5f30c8a --- /dev/null +++ b/src/pbl/pblhttstdeb.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "pblhttst"=.\pblhttstdeb.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/pbl/pbliftst b/src/pbl/pbliftst new file mode 100755 index 0000000000000000000000000000000000000000..887179d96c85d3325ba07bcb2c494e53041035ae GIT binary patch literal 165295 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

)3xipytg=JLG28;el~V|X&O zX3WpwGm*HaIWDQ;2x#4i?>Q*dUn*~i;|p>9T|Bm0D<^Am-@M`n``lvgwzCr7u$Lu2 zTrs9r4ieUUT#R8EuV&#*-+fhWV3^tVZXX9e)mDUqg4N&TZo?B!pR1IGtkd7g>mX6Va?vd&(z5EYBWo zG~Xs%cazYIluwgAnDVg)S$ON?fp>V5ywC8|xy*-E`}jDKd)W{)4)u!uw-gzD^RH5( z>Z>;&!sCE!cH*qn#Xt-92b_!Ho7^luS26g`J!-5Y>bv(4uW#vAWPyv5i2*5z(e-Wg zK0dNFOlqYZeZsFtsw3hsC9$M9!uzybk4Nz-=1d5~H;Z1Vj%mD2kJS@?HdsIeTpl+K z)j1Fae=eRS#N1imrAp))STh%o+-xCWzPrCPDIU$lS1E^JLcn{kxWTc|U)8#1VB8u( z>+cHhZmyBmbcloh35`VmzM@mI2o1v29*mOM07)(*s{c1zrf;h(=zUA4}D|F0- zitzJZLwg+IQn!*`99P%3#y-K0SCMeK6h~|0Bfcyud4wAPa>1a-Ln^m^w?&Sn%E48s z2W&^ypG&3YAMNj3n!%Qy?+>Hl^{{tpZ{XooT&&2(dOdVx-v(aucPy)*)!@!-dCHaU zu@;5x{X&(0(2}1Vi~jNKF%(%o1yFknnQ##q>i~8Y(O$R+LrkAPF|8_C{~{twdKuO3 zzLff`kS5? z2w#Q1JO3avs~K~kCjSF8ecZ?KLG5`5alVU8myz~Bp2bx4x1-J9^-#yDZ#N=VsTtz(|+Ju^lSYVN^BA-`!PMX{4g|ae1F23dLh{LL{IG%s- z(EA{R5XuA}@s)_p5gJllXG?MUTlI!5@wUTzBJBa**RM_vs8a;E>Y6VzRZXcai04Sh zlh1YI9XNe}L)tu{y~v?IFDMvs!l$oKQDAIug9$h+lpSuopSdWW!}*`Vqjqcp&Q)VD zUWLfveaZ?3gTuE)*sJ037uY{N2K?H2B9^9^E5VxK|B{F)Ho(4*n|F#O#GeClbK z)7Tm9C!^i!z0#UJSU2CFwl|s&D|O=>z4um3LVHkKMo`fZJki*g@|t9xAD;zQlx%tXUz_AOQJdI077bTd!RMGUI%tM$c2a)z^ZQMl={ zxz?|(K&vb;)X7$PHb&u=22qlT)4zu|srBI{N2aTnU^w^SEtvB*qx#hPdPU&Gah7#~ z8d253^(0tGYDdc6=A-5CCuYwF0$8A&7o2;gmp-c=VxSpV>wDE1&6;=9aPV{liirKy;i}WF2YOv!nNaaw z7+=Y^56Gv~-NmYa{M7G$Sh{`ip5}FrqS^;9IqXna6(1?ibqRTR+EmM%$ds(p_APln z9;7v2)n|{!7t@}VMF@4q-rEXBXWGkkwR}M0=N(RaK~|Bp7nYm~h*o2enu&AP%cAd8sUUkB% z_G@*^sY~7fjK1kj(zn&!%%X?Kx_S>J1!9f#g}RkQwzI}27JEW3h;8?T$3-`)C*a$_ z^3Vd!Z=r6&1_$N%=024EA18K+zsdV0_V+^MePVmZW6zT9uHJGg=dym-TEL(Oqvj3Y zQZ6Fa-bUu!@pu5mU2>@(!@^yxr+ioK_*BAIAQpa}g9SAP7F75IjZuI2LfAa&*wZ+5 z(Ilp1xj!>}HcXw_DX`D%$ZLT1xj9+pdkRhVc#W*Efsa~fe6L0>L$gZ6)k$p=)Wxa8f zS7R{{GKtV=M88M`duiIY>|YX7D-gbA8xh0t7~DWXh}!nJj%}kxj>h0UOQg2rcT>=6 zwAwAw$X5!&Qxe8?#>eX?+=~q54ij|*m8v4Y&0OZfiJIMm ziZF;sOc{L3CLkFM>YiEk1&Z)t{TF;EC}PdO50?1Vg1=zYJ#z=}!fXC~DuDHo(U`e! z8MMry2^QCt0jQNXU+{HZJZ3#}E^-W?D&VDGgHY)aqTv|?kFUIJs6%a?NQqb6?*q;W z_HV6-URO6A?CNe>MW%S%tgDj}L|B6*-?5-ooz+!8oa%A!{f?uWLw<=wb)y?@d;{tSp3g5+Z#7f)L;d@qVd(v_4cmt;zP^q8;8EetA!MTA? zW{U}^V~Mdvu&fIHp;-WdCH6!ZjW~}l8n@5m7nTF_4HEO&Jig{8;?{^d50!)&Y;4M) zP8g_-pL!n|EI`@n;(FBl6|b$l-nfi=1JarnicQ^Pmne@4X(&+=WA?`sd`sIRR`VUt zpL|!>?UWi3;1E9vF6&VZ&%@|<*xco(sLsbrfJgP$ubvoRH?f`X$pYi*!Kb3f*N(=l z=3DwSDu9+YW_swjKBEkIjdj7oE-+{#!8*#so~XXP_sdw%!bU=avRDz6Ic>U706%Sq zzK=r*>$G;hOReYQ4TSUtGd&fPenRcoxZYUAszC>XHFzFY24pej(2axfL}M?^&~ArB zTywaUJC$O)W3_yYH;jEHz_9NN{D%ghDThBQF82Ggr{1b-*Z|ICGeC1Y&pQ--W$1IE zg3CN7^f%v=QA@W~rTCuQtG|Q?`I@8OeNlrKoDXjQ5i5BIZcQ6=pf>+N`L;Dz=^DN$ z@zS87Ft}gdOh(}S-RHpFxBVyYt!eu({g=N_wAxGJ(mt$9_zt^h=N<7a)u4>p>Laxs zvAELa=N0H~y^9U|w8Vrs7<8Y(L>N34CIXImsO73XcuH=VgQ{jA{amEuO)S(VZ8;A7 z^~I>CnkW=&Qh3%!CMYhNDk^RmwzOr3IUXm_$D{Qgp|L*Ru(x<+slR5BA1Bbq!=grt zw`M%v9tuDG68U`B;g4$<9;xYccspx(T0wXx`n}q&yGDye=ea(@N2{xWjwGu~gd0I$+u{GWt8#F0ZE zViY~0Jv=RIjX2aGZ))SiHE8}7Xjt`+O=PdYS~4!g0PJdZnfUHr)n#sCqP!v>TkGk| zTR8UPV2AyQKeXPz3=$Q7wxY@S;Qhnn!x0%D>M=glN2`0c z{J0Dw$7&P)jY7ozEcQ;mzxN=cD#31Fa(Nf5HrW^oKfs{B;r>qPZ`JRjYt{}z@ATWt z4u}8RWWGlESfvBGfa1gQK6V-GgZ1Y_Tuy5qlzqy&sG=2vMVmfj;ihNwP^s1 zQA}_rhP*}EM8Ly`s87j{^wG!+-(+Mi;UXOV;)MPbiEq?uzd%PitG@bYSzP#DPUTeR z$i)kC*P^TsypIu|-$V<)$iR-V8?f-J_3u8-0Y`OH(d6NMP38yrDu=gzHG0t%&&T0z zvHCa8KtsIY12)GcbklZh|IyL=oyvrocbm4)<2OFe^n%{UD!vZaPh@`=`DI!hDBPb! zbLJDYVym)9+q?aH$Fgm>G_2ZRKLKd9cqj)BAK7gFHAhFH_kVf#0Fs^$%Wi+q2@{*K z#b1i!d35-uRNKb&@Fj!H1w-NF zk7jfLoWX<*E(!DtvknI4PMSHivUFAf=u-p9Q!)d|mH0LIfiylJ{pw#ZP#%Gt8K{^X zNS+B|aGh9IQ89atq=rMkWEBj|nOinHFtvPU+3eC;Wt5-c+{`Inh zSu;`u1638Jvnxv{SC!A1jgl9a3@BpZ2aOsrVkiSeqlOP3IAGAQ#v(W20{xZGt}Lsl zf(DUeZYCU+B{D44v>-%-djFVmky9`*t*pu>?;9AIKb|rb7UhqHS1`1wSSo6OcqK!I z7XL!Z;Qy@ACdEVkcKsHWl}Uh zaRNOx2nNzan)0W9g?kg-vM2p!CJp?<_4B_}jP0|8_%o|_rS%0`nbpITK}l?52b6OUG*HHB&yPtrWW;N&^8W|hvKa#}zm z3oW86YZcHZ`l6D97^)2)pbgH~hL^DG&Z$PG-R(;lU1lBeAcD0X0I@qiHpLx<;+h;y|7QUC03&A}>91TvEoXwmiNmR6K$(~@&~ z&Adb$P5b6q!*%o-^$Q?87eB)KKWDhcZ8co$cNng1_~mamT!WuCTyNu-veR%irzPY! z5Q>>GtZaT|{v~tK%>!lPm9bw}YBS3&Dw_$liLC%U)v9MtB8?s96jfeUDM(W*%E}OE zv>=jmx=Q;@MtjZ-a3p~NKz8hm4ZS3S-JGdYD=`;Kdxy%Kkx$iJQ{$yE!xO40Opgv{ zw}$_c(B=bryDjAWLHel^Icok2ac)*lPM{EjWJRblFfdR8^|8pqrVhd=RaFM#L$#-2 zQ>8UYl#Yxy1BZ`-#Uz>%8mY*_igJwgf;e)_@ZlQuEb47g<&e_K>B>$B2#2Elf`&Ax zXS`t+@YC z*oF87Ml1gSVB75Q>LLZ3i2Hr|Bl7@$2XJzU_y}?vQ+|B?^vItK7au^54vBX0?BkFt z3|BPcOAQxK(l5SJrH=s--g?ro53jYskAGZXPC~w1V&;d2d3GFUKs3A+p&h)+a520S zKE9(MGPH(I0kG&k=SIM>OErhG9ED$iID-GvALx1RK@0l~55a~Jeg3t(+Hj@gcN%_Y z;dc&x7vgs*e%Ii48-DBXdm6u&@OuxxPx1Q^KTnO}YKLDsey8Dg7Jld8cOib4;&%;x zx8b)Azo+qg3BUL7`xL()@$*~*di<0mwmW#xpwj}WgGY`@3v|uGe;_X>r)zFrPLDw9 z+={Xatca9WmZb$!&n%l%UOGDsClXJZ;5T^vUy}4c>)K!C`nx@jbeiTkWFd*6$&(3TACBb)S zSNVcqb62XO(~x}vAVKsieTjm5)0c6I@^gI zH$GF_%SRJS$||c0DzMF>X`M7}R%!WcA>vn|9U3*TzrCjY9Rmf3!fO*+B?c6Um(7|y zYp&L+t%?qxGkaReoUx@91FNTMFWEp9Et$hajbG?&WTZV6j+V{ha@08Nk=blz4J=B@ zI&oInteKPN&e!g2j3ZkvwR%u#q$r*~2kU%unD1B{gmB3mfoqr8ASEA>Zi_?`$v%j{ zDK5XXOiM($$y&)Tpp`aAwyv}_jj_tA3ej3G(Hh%@H(%4bD6NH8=d>e@aar!vCZQc5 z3nHked#zKj0irf9v=JCoY#eUKX#>+6;#fY>vN9T?MObt`Q>}ApF{n73Dh$@X#>-ze zY>aGt5LtV(=Lt}(&1tE98-ORSplX*jrVWyXSIvpf2ZTkGW%9a40COkDH0&iI$<%J8Y^byIN^?*i;rnTdtHkY$_CAR5nvv-o>Uxe88ki z?M}QyCwVn4jcHGy_u2WES81<@W2*ko&$APoQOQ%`v;tA78>5Tx;mTOyoXT?UZE8hf zXc2nxoQlSTPf7%Rb_L|F)PAsI7jv<#QnbAqu0!JpGzy(+yK0%?MJ8>F>fb|9%vp0T z!h*2s%R{Qv8j^N293MVs&J1+iYg9iTQdLl1QCX#Z5{`~6yQE6%p?Wol)efU}`3V5F zk3C_ST`v^!YLSs4IX@$#ei26UtgP(H`IS@3=2m8xckR_9yKLsv>`E^5XBBJN)91`8 z%brp(=i=-sWs|y0zNj*L_S~wO+0$m0Pnz5%4|8~4)|ATJ>`B$-GpBUHZf99!QugG^ zY7Mh}U_fyoFDtiOR_~mwoUERjzIYYJR)^S2hCUAxaYo_q4zya%Fz3V99l02s9dG9# z9(7X`#CAH`!HeoVkdTkz=q|@Sz=;Z?Mzp9m;W(U*7($Xr<=Dz#GBb!;p%`2djd1D` zLU;mNHyy(;QADMYrDGF=>8qJI3h0h##|Gw?LGF(4NtyW!f(908H6z;LWMUV|Xebl& z-Xmoxpsr}gKxW(GMG0;cx$Xu{)J-DS2;$x>!i*&J7Qy|B z!Bqk+C)uq6y@t$gXNHbV4BjEoR@B0s0zE?LY6*TxzH20y$>3VS-3>va9+cp%H4t(j(u^-tQB_xfW562tb(cA;} z(Ftq|s8w?TSVwmtFTuYU_|Y9pi2oNj{^+2>Pn3d(@jEMgm*(JwHqpVQK=u3p$1qc3 z=7OUZQw<69n4ekHm|~Vari60FyaqQqrY&4EW*mzZvktB+W;<})nkR;3H+#j@z}I7f z(5pjpjDcqkITawc(Fv}vh^Z{GpCNxw(E6XIvyINnbl#;SD0Dzbt;P~F2s!(jXP7zg z&FZyIrH5oBn-~3y83qlL&wu76N~bQfl=)xE>U9LYW-rRVK*ju~hnNc~wj&s4&H#UN z(cj=Yg7IcM^1M7scqW*=$z^ep!~*6l#+Iral1v(a<}wvaHP4`ASE*R0`A_EeCl$*v ze`f3&73*fMB$sQK3C~_ABwJZ5HPITsB(uMHC0X6@h6tpYM;N~d*|`lB zP6otrCbECTUhNS2$1T&+%nbV=8=sbeRl1!qz zl8#KQ5rWj+D@fTy@_rAQqPw|~pgC@Y6WyJh93k+J?zx&!{Iuv^(%$bSyWTR5-vge} zr*Swwa{TYc4v3Tyv-Ah;Y-f(Lp#ptKY=ou`rwlaE#9UX5) zV-?Fiz!u|ND~+57>CX$R3pB_5h#UP_JKhMR*BfEn8HZgk54&>Ef^qL+2 zL;ND(`%Pu^noW#ev$Mjtjb1a@1*pDz;TX;ozZkuKF?#)C^!ml<^^4K#7o*oNMz3Ft zUjI52&gEA|uWyqu>4ldtF%fX3__=UoyzESR*yn0avr78>%3?MT1(jIbv7}2olT5hXA`5>xsYOq zjb7)XtB`lt=yhJMY(-`CIv2kxY0BtzHZgjgO^jY=6QkGJ#OQT4F?yZXsuoG3_Y)S9 znh>Mcsf=Fd4VOx$%IJ08sA9_Kbv7}2olT5hXA`5>dG8oel`?vrYg7|ZMz8b!L6R1L z2&@9PF^4h?g!m0UHz_-ASrH1tDQ30wtNv4cm=g3Wh^$fA7xyDLYMz3?! zenI#UZrrCt5Ejblb&mf=5`TglOC2>*t0qI3YBJ3<9<7ZsdY$L>;SgdBfE!!Zz@?E^ z+8hhnijFdRouzYy=pquaQK_sMYIQpuHcv36N!6O2+HKr}pxclJNTb&|R6C7cXW55LI!@bAf4-#C#!r7ifbheWzf%H@&pE-WiVwbgM6FP3dxGqE(TMN36uzF zyx88c9(8GD-2i}N4xxGJgiauCKR1J)ph(uBP7H2BO=M)B`uLap+PbXPI z^>kzmU08G8fdFL`bEcE#_zZDRr)nmD0VgJf2%h)h6tW$7FE+~%_Ff_d#~9EK4c|LI z+zvcOjHZVBik{#ABo2>(ZTQTTK_7b?r&!B@VN|fM6%B>|D%oNRQ1@F~j_p+_EnbZZ2~Vtmx5ritVb>;?2&)?51Xk1T&ZUbyt`H&9Rh;Jw9X>(G2!wTZ-NW0dr!9n5R;J zL3fD&n%RMwoXNstFgIsVoC0EUf$=mF53Z6}s^;8_K*NyOUUQUEOG7RPH2O<8M(ika z9O=W>u;y4nxkkND1{0ZU5!-C^I6sE-*oo%tWPgq-k!H50AQM!~FmEOLxnZ#u5c52h z<~7GN-}6-g{F>t^6*JKVrqT1^7_n2$SBYO{bJiTEliAcsNOauGlnW*0Izm^m6SR+w z#nvOZCU~CJt;c}kc}^z`tJB9?hX1 zr@YqHD1k?}qcKP=)jSTz5os`f&AAv%h$`I&yZS${B>NrL0_--fhZ}o89FeXSL*gLm zVT3z$bhOg6b;#bUw~99xBG9Ux48rLA?53^St7kmJ?7>(-$>cI=1+_|)5i97y+96_{ z$;uH#VOk;3(1LIi_h`h8)|34kz+Urz3`V+tH>%U&{~UydzYQR!|82M~e+)J4--NK& zzXc_U(K?+uv`A~c_*^h)`xm6@?Jr007E;EYu3KjSHLjoiR12!LNQleVCjqDZ18^=z zx)C?TMjYCR$nFzYsMiwl4LD~bHzTgtMl5MW+(5($`V+tj9K}wi-W6Hs->CXdJWP?k zW>ZT{Cj4unbiNzR^l!gqP*(K5li+CLelNi_(1rd3$vVHp;ExilLRITOF&M0vtm!{< zYzp!yg#I4^&c#s#{TS_xq>0Q-)1BDhOGc~sVtZ)t#ZwjqCMfCO#G zKLAPMa~#$cIjAHZq|hoHN_q_yga{4qqz|A0ged}YR5i(SUWw^6}?zRXz6}IVa zi=ewLO!syJ-G&G{6}IU%M9^&r(|NFGuH@VmL8rnt-L43_U17TX2DDs0pF9F4W_bJ(@- z#_0ehS*(D5U9thhl=jsnA_o<=bLbM0Lzi$4m7q&Olg}1FO1Y-z{7y~}HsmxWA}1BL za~czo)0l8hJ3yCuqcqJ&;ihetR+;=`1G|a{b}DSMtB7D%5oTA0lM$*rR0$~Q-zliT zY6rUm3v`h{S)hwm2%YE>2_=sP>92H>&@Uy_lJ8_zqT4MIBC4=0;+6;zw@5DNZ*Moy zy%9mD!ZzI-5p-{a>5h|5+T%U}{d%qU#F(cfi;8M&S1N4h5Ea$fuA-vsc2!C`$st-m zzn;Ub4LJ;o$U%ke90o$G5rcc z`s%WWZ>OIo>6xh*aXqK$oOCj~gTT{Ab?`2CfsX6Y`Uc&Rg_&VJ#n7^OLhyBt()Xy$ zn6#QnL77|b6|5Yd7W^CJ=f=&g_ZlvJOzszmI##-Je}u0W=S5@kh+0`cC(o|}6Z6`u zz^Jqo1oCp>=ws9RGCUZLvGTxmi}FSjIxg>AdWCt@1b*-t%ix3Sk zdIzK3$`D-#Nw(vcc8!1*0@VIm!@S43!VsF)5suc)gX4l5 z0NX)$72%5oo(%X)fW1%nLxgV@`00Ru1lZSv$6&lkYX?W`HU{vY0rS)WehJ}A1wIS# zHh`rNzMJrU0$&Dr7GP%(ejz$(+C^}*ZW{m}4A}XE-%I!-aJn~uwh*+Ns9Ludfja|u zml4-MLrU|*(YpNu@TGv=MEF#~D+up;9Ps`Kq}@i?S~z*@;TS8oUbjf=(G|xY*~kxo zsvbY-P(9ho8z3i|0X?SKG>3uzSreKD$cZ%F)`4cu^=O_qLb|@lzbA9O4v<^$Ys|F) zav}$<+h<@w@&h-4#d}bOuy_iPo%l7fXn_2Z#VsAMpM107nsTe*$~%rKF;>2Xc5Z>0 zv9kWUMQNuXl$R*cy-3KA&@0z1>M;S7l=wVQm*Ur$T?6FA?0Q@b8jc6A-(t92s|;5z z=PqOAPUyWS`}+%k{Y3bq0^f!VIi=}En$}~zP22A_!*w2hLaP^RJ@z4i#IFGOH4_x^ z{zl?%9Xe{-Pe{tS1Bxm@Df0^9=wn4+?Qh3%ZTuPw&;U8H09v;Tz=>Qs-3d+y(G`S6 zAs{9AHL_@c{F22Qus90x6?cKfSz#7_#NzO4WYGZm1&i)`R)ZA7THYrZH1x4~N9h&k z{S1$_c6pu)ogJaq7m0Y2?lD}`@N4AV0Qm)Ptygc1oqBhUygQ;~j9rbKo|8eew>&It zm)S-y>@Cj=+oL#k>xJ5BUxCocCxn-ybVr}LxthK^ioRL>9?VjPp*;a zVlbkdE{eqW=AI|MKXS?uQ^R@VVn+-H|9yTNlaPhG!|+XbNJopZ^TTE-hy-P$~B| z$lLusk+}v@G=m%I73SSZZ>*NxIuS!JtK}>;V+O%&7pW@kL zp$&copwAk?H`-u={NSUody+viq6G~gt#4-vltJ}GM|ts@PFosfdRtl3KK*$V*jUb0 zc3nSx4K!+8XGdl+vO-1rxTfwSf=1JFW`zBv<;(~= zM9Z0xmNO$-%bAguGb1f$Mq18{V7-ZkQp=eUD52%d2wFqSnGu+YEoVkr&WyC28EH8) z(sE|x|KynwhZT)Uw(llg(>hMXZcx=MEz`Ty+=9g#uYJ5)Gaq8iK3;8@wT#)vt6gSS z#;%qJc^p5QfOA9M8Wr=Kk2B3adL3s5m{zOO;?09tPV!!>VhQGzOsi9|fZ2z1E7V!8 zBr}7tmE1sc1XDH7)sXV9AohD#n-`Jn9-jWe$s6+sS>CH+F0IoCK>R;+8iuUoG|UkM zxHBl{b8s3agR9Jc_%uvFordWFCiZEVvl0Bg(=gnIYkwu2-#ZOcM#Kl<{N8Dp<-qa8 zW10L%XfR$M)UK*@nx>!0r9kR+EVQiW@4{Lk&m%9yDNVgV9bQ65U0#t6U8=$*kTo=qQgqh`B1~S@j8Ghe zv83BwzlI5^O>#j2mH;Cy9=jB22yjjFZ}{nB()%Kc_3`u}@b$47CG?6j>yUUieqCNh z9L42TEc(Y3VvoH!9Q+3Q)}NPB1hXj8PAP6MmEm0q{tj1icPll>>7f@@m}iP!lEqmq z?Fq1^TnCWd;I$%C2BMUyr}*CVLE`(9j*sgOYxARzzmQ?aV#} z4`vuZM%Ss#u11ut=ti`AnInGCj)hbjdV$ z7Q^KVeh+mr!*0>IB}bnn@YJk{$RleioGvUP8qsECMhRCyvP=IWs`wA0kjgE4Zs~2{ zIad196IHZ}MB}^khMz+nJ`BQ_@JlCaeQY|J>*K;2)Dn4zk^U29yIvQ8FdWU%^g1Qz zH%wTr3UCIRk$#=PJLBxhN+muT&J7aM()xfE zdq$y9UYn%XQYC+GGDNIaGRP2dkCH)#h5tShg~6c;xpA<9)M;CR!A?3CsW&SO4iEZh z)lt!nc(;^(H|4oGJl@FIcauFLe1~-50_t}ahu29`q$TneDt!{`Zc~_4hR`QfQ7}Ah zRtK=s1_6_d4uAo7$DkG-If1g<(ks$(ZzY>dwG|h4!ggL>CuHXbdv(yj9RH8rtJCr>IO;Cg@-8?g_Lg_S)yuZ> z!eaQX#g=!$vAlo>-c=L%)ZyWlPFg15X2PFoTq zWXrqYE$@P(CAiF%cfr{sTHXc!zxQ2m&va}^ZNjQpl0MMnTj=_r@a`AyAkg!f&fPD0 z)w@7#RJu&Q46hGSF|T{-s@iPNCa`B2=bVNl600mwkL#7u#&VJRajn5-{c4ZzcW^s)hcFE z=L|7z-{Rr1MQ&u60b>@`&#P_DG7vG<tiwyait`3>}c@+|Ut5i$mYj8y7ObS09_Y;vu}i^swOy`4D%koQaHhXTQFaa^Iz1 z)o~<#!`PisR8vq&ad(uIf?H>+MRpeG9tj28QK|Q;5+!%W!ZC}m7ox9uRK$Ob{Kuv} z3opbCM+n0g&>Kcj6$}qi@Q%!D zsDh7S_$&!?>tdJ+Q6a+>!p|feA;JWoC-O)Urt=J3{jQHv@PVBHFBJTAz8Icy2eQw2 z08ZKybhgoX2~JW5-?2>7v5JhhWET^)6T%r8bb7*(weYl244n-p=~p>{oSSJULH-uW z=QCrzXPLn-L}=-Ungbqd4tNE2i!#=eax0xZaMJjyOWFZCN8qIQAj*k33~LT}K{LRl z3=17Oqb;38IB8wz^rn*!2mH5@>W}O1_{ov?!yeU1!gKAKia@-(#bPB9bH#RcG*cYI~f%_ zYamF&p_^k`;9bP^g&dpyZSRsME=T{2_;UIBP@=(Ln1hxLaJLNw7^~Dd<`I;fx3LZ!jULf2=tdL0utqlfd0Bn-f~62 z03}i851^YtfkI)?WeNz&rfi~20ZD?IC{sp?z=J)Rb*khO{EXo=33rx*Ch0b7cGp*^ z75s@k(nZMrGY@^Ii%=b7P%+jNutt(EE%RhCZP;HuNRE;?OY_^I%%gi?fDz&@{Hl z-4OBz{C;)H%Kj)4ixXjp6Cqwh)v{)R3ENQNdc#$X--**k);&OAQ}_~z-xHzf)Dz;= z0|`0#=!G)8{elk#{aQel`ho%#7h!e10 zoXxTky$8{onb<>|*jb3&A~3%SSP$bD`UXP}sF~Tdh_5E~Z_ZWF!j-mkWU%q~39=ru z@!tpTNB;%>KW+RAo-ka~@%tTtvRa}2u>i|~d;fod-xc_*#eKm2p7fJN z5|cLqq3IMK;uMbt#z`KvDARn_H8#_cz%Roug-mfapwVi{de}x`@{HzD_Sz`#A^G3U zqGVHYCVkgzvKENJ8jil7eRplN>i5c;{d07qL4AL;Sf?`7JP<8bs0=lKkr^W>L(Mt` z7whyvfh%M3p=dcqCF!!hC&iJI4{&yK^BD0kida?p-ha@Z;)xJ0jue>)IUiLfNyTbmqnkl2h87} zE{Og%e$D0CFkNKLwV8JT;{jpjzxpVsg`B$ZUI6w19jBOJ@c9l z)x5rwY_mWy4!>rG>hU%TlP_!@((-$ME~@2Cc~y`x@}x`F&h1Gd2XXkha*r zO?wO%i}sMoaXaxYntY#{&p^wGa+>b23a=%_5tHL{Vlju=&lFt7^UoDr#`B{lmyXm} z{iVsVI>>uP^{-5s3-*xqYoS%+#y1N7DRI74a2fxA%2v|G&UF{`)vd89}HrBO6XyA2>LTI0W7%mT+{~8o(`Mcg0<#@OJp*k1sEHJ6 z0z(vafzy{+g+Li4l( z?QupLG25N8BqtqUhqJK*Jg>si0d_hYJHRdl7ei;az}52Hi%v0s#8`RBDaMMdl)dbf z4j_&D6`>7^Vf3nmwd4(uiw$8L3i7XQ(g^k-s*g)~i(YZc0eWLoj?f#O@;$wx6a!Rf z0BL^sp#&DKFq8^UYQG!f#i9NZKe$i}@B^g!^(^}?S7h0@xf;v9-PKt39V#qk-05Q3 zRT*D!Ng1W{?{+mVHSQ67RjwCRSn0tQVC2(+IC|&{w7KV}#&%9@@=Q`Y5aET!AiSW1tF8dAfWrQp)Fy$UWR_B2?jF%s00mmo(LSKEc}TfZPh zeGO4`^0fEhhdzNLrTS6=2Nr~mDaeA52c%Ie(Tm$k;DZIB&J@2G7I`N82^?`IH7UmV zQVexR(nOCm+M9?~D#EBroE%ZSDG|jhizwdIh~iCC@UzHgdSm&@?ebMZ6qd0NW&7K1 zDc{YAauB;$d~eDl;``H{h97zXj+FOJ381_mD#(J+rxHMUzm)*W>tH!iUVaBxPvKnj zT9fj=q{=H#3oonkN;SM1QQp@h%DXqByl+I5_sxj%?o;qPncG{cym-`jyRqc&DCTY0 zir$rQdOv(twmF-pnWv70ME%2-YWmibBme2-$WKE(oP_Z6PmX-^Ns*t7k)O=l|Jl+H zpoO3EinQ{p5M?XBUVLxLUE=#g>)=PNMB{x@07Pho|ANq$ z2*BL`nOC7oyXu?D-Nd#KceP@Apl4 zqMt_eX7X$_<@?&quLtJZF!NtG<+Enm_zwejFkJ zeVi&?c~UhpB#C=t|z6sg(pY8_2kHZ zIyv&)-O>DH@2<=%dw17$gEE?~NT0a&b0$&dV*rX+xJ*C0IpFMOfWN!;ll~g1{`iFI zL6J^^eE7+c*Payl$xLbKW{;C9cn!&ayXN~5<;0pVZVouT8Q|~N{2o&M@tSvHEIkSG zf|Da(c2eXgQ}fO@k#*yWrBh2z?TaguF*65X*&Nv?*3CnR(z@9!zBgs3`2Li=;>U$P zfRAmqiJ^K4z{>er0tY9CG)zOV@E4?c5eUVr*!)lu0x)fIB>us~P+tk`oERFSFy@6y zh*2E6fZo{93<2+-7^+t3rJ*Y%@Ycjoodoty%-Y*a8AyE~_(k|NXRL?~E(THqRucm$ zr%i87yBZH@Aq^u51fQ7AmBs(OYPdSS29|8&zgSs3VaH9&nhPehvU@yB|_81zUJ0*vL3LRt_S{Z{F+&Dec47~ z@~h3GMD(exEYg=qjD7RJ zE7Ag+X;vY3%C}@xA#;u@JR#;->6JrbAs!OLrU-YFad=L8YHOhP!!LzB z6+=RJyFB@6@T3r{kr?~7@ZIP@bt zIT=_-5jM7h^Dq0$!fFBPBX{F7%0ah0qsa5eC+^1Ow|cicm&mioA;Hm-w}BreSq%ve zC@Bh=#pslC=@q3+r&pL(1utze94%n<17sJUAv${^ACuzMVv0N_ohpkUiENUm+Jf%OD>ml1*l<~^_QqCZv>@3;v zvD(^)-nf*(^om2p^a?}g!;=-d3sqo2=pqSVx#CK}NF51g6Y)#C4)L_x;UKr($c+bG zRxqc(N^a77$Ex02tYuybjQ3c)_Ti&avIW&nP86%-QSIc|6i;X+NGK^I9YprI(d1_k zW;TAXk9|+F7=|bcGLGK3&}4eWGKAa?oagZq24N9!rPTmU;~8cB$M6UsGW;ODUTt6f z6vfAIb#V6QsK&?t|3nM|$Lv91FxXM50HpbklIV3M%KP*RL;r#&%KSh$Mr^{}q~OvOZV|Y&pj&0%O|3WFruNrlz2SDX zrzR_-cLKii>LC^1 zES{D*dJw+v$_nlj-eyo0EZYWZU$MQ~TIkOfoDi|i&{1tO$k-N8TL{wn6C<`6IxD!W zvji1f)>)DiT-H;PU5)E0DYE?_stKu}?8u}_R%~NwLil@!7ot(B6DRoecFh5^n*sjr zV~m!3-PkV{)O*vD1e@dbFaiMeJ!~CucO_u=9wN)VyTC8FV zLf1;*U}b2Pf>eg?LjXNwJ-x!v7J9{@-Soz0c_097-VT4mnje0VW>DmA`UjOw&7cg> z(F}SSG+&eML^G%q2sDGfMPgr+tU1drYUTdQrrV55ZMJ2gSdQN>4Iw$Q#H4$gP1btI zXArvZO^E2IzzO%J^o+bWrDx>5DLo=@Oi2P+uO?qU=#j)$JC1W-bkxCeT!nH5j3S4| zF9#ZWURzDuKOow56e9J)GH%ONC@oi^+)0Du|Jkch_-SS18TqvG1qOmgcB4Nz&WJ|v zt2Yt!EQ>-gx}8Zmn&D{$gzk;&Y(Z*GYIC)cO<< zm(?GKQ{C1l=r$hfsRS^vYCFQZw~n1c$V}kGSgGLPvx>3l?YBk+V9r=Ii7+*-1>n}& zx)I#sG!MVbZbT2YE=RA^tR5mp2iRKtm?Bn^giiyIWs_TMw%@ zAU&;Xz^#{cAr8+54Yxl zYJ~M98rVpy7jhhB4MpyS)iZ2{&yYc^`R!lLb7X&nTl%Gv~~YU>AZxX4FW_%-V(0Ews9#)h)8lMJ|_H2a&qidK+?HVQmNPmDaydmL=8}q%O7g0KUx1 zKwei_8vy^4m4Zsh}h zhh;)L{W zI@;3X)_8D!!g>Ij*=TuCmM5)L@Y!Td2j*tYo8;yo^R{kv0#vikMLp@(FtmGz^$>E6 z@;n6Y^--Q$6z))z=OXCy(_j<^M0wW0`z*@yICA|w%F_;HUqpFs2f=W| z!%tt0Fg)*}K1Uj!GKewC@bp1iq2bvKaYh@SJK+@>o@A)97$_)NiQ%~&IgBwpyq$8a z;n5-7IK%TcG8%7qzJzzS;W3bQj^SB_VooqTJgj!E;kg!E&NDm@K+oqJo_CI!>&j2hnJU^iflMD~v)|+g20+4Kq;aLKnWrimOH96JrIDt9M@OVHs-SB8oZMot3 z2AaIk@O*$O!6)P8MlCZd8~Tgc;XyBVqMevozK^4zMtcn;sQLI+ODjfB%;EJ~-}j9A z?5NB4nio;O9rgM;xDbuCqkdnA$gS*XobMk*Zf!^7eUDg(#@W#XUml}v>}bHZk*rR! zqe;GRAf^>>M^k8^I%^BOO&k}usKH~#d|Mek!;X&kMWbO^18gzQ^`(*XAl)OZF3=qJBX0I% z?f9=Sz#w0aMfta)b{v!B{>WGZD2B7R)p(>kNAt?%R_l=LEMkJ@jDx$)VZXc+rA7Bf z+~q7W9|X)9{+_(q7Q#A<`I&H3ujbevjc5r;qs!rVT^-FmVDCy$`q9ht^%{H~zFPgF{<@jEMgm*%KPcCKI*P(6p>8158nE;wpdHKfw5pIKC^7)+zA z5=HMr4MTezk*j>WRpQ37i_aNPK;yD;fx)qqg9f@l^F%`pa^dx#sA<2HP7TMvXI znvP>Aj_opT9i8=bw$Ry4=NYgT2ZTd_8AHql8|v|D}A&;hoF9;JX*7nBVjeb0Nj%Tjw)aibby?7e_GOY)77#eO1Yw~$E~ixE`%2_fI-(o{;-*2)ALUb{q8wx(#W7Q7qY%9|Uk5ZtFN`S8-q{j!3|jYJZKDSe6X1 z+sJ_1wkL7pn5M> zCfj;A@Z_#6X$o;1uHslDn*UwSThsONKxkdj6ieEt!deF*thxFkVyz+;3!->28Xi?S zE%-+hw^Cn6+^3u1YK}{xP;)%zp6E}JVWK zfEwKn>&Gtd4256L#bVUG!oN_(fPW70XYkcDM*`~H6YL2&9cxfrPts5Z{R}2gVDMQ6 zQ>HSwo4BE`7~I8R>M?;5A+6y?El<`B0669lnwQS}ClI%vo54>|FwdY)4Dw4ko+14i ze3Z};!x+4exJ7XcZa~BEjF&0*b~2k%N$6L^E#J@JwG37n%gpkL1_Y0e)I$|DDwV~eDnlX%*AFI zz%iFd!O`*Cp|!`%4_AIne;}3u9r6S9MKcKYvF6W}XkV1V-;*q& zXMudNf25hftcNj%2BtX|A}|cUu#g?04gbioOzubGF-&x zq5{E~*MT(@q(-X}b0u7rh$vm`T+DGuZ=I!LhWRbIWj`U@T;?9g z)jCI|dCe$d=Bk+A{EWioC9`f}(HuZqY28(&#haap*-cFi31%+y<2zZv3}}v}OzhDP z0y&}??8~+k{WIb@t%sPWQh-7H8azkv4$S0C7M?TC42n}gOd43Hk$CWWiKS{zFP@7U zM!fc#qm)`2vIWV}Sx7Qkk21%RK5PPOjun(^)G0`GOk}P_Y_rifARga(qIo;npQB2o znXM_v1Qj#PTZw*dSgZxaJWr*0&GF3ld{qFy<~T~lOgs}zqc@5eQ_WY2UuJXG9H*1n z)VnCgy-c}KQm!L(6+1zP5qP+J5nL0z&+0yYM#cM_P8byA8wR<&+w7>}JB%WEx7$&d z?;oJ@?vODV8uO*2{NCs7sNYx3=uSHt=Nm}QyKLHcG#`HSqytxo76CEd`yajI#EF+^ z-eWpp%v@t`$L*+z)XADxbCgI$dwo}<1YX^a#vrv+^EwE!n93&k=xKqr>cp`r;gvaW*WYY{FHAO~SG#NgA#f6j*E;9~K z(s5}rD5J?l;o&Q;i;Ted4$4I-h-Jwjj21i^4KyxW#$njx-!aD=8McE7<{3=ORXGGq zKGDVHsT@+xnQ@49Q_o46=1q9mj_cKjeLR?BZXsPC>HNWN<{iwv;B$^*!Cs~xV@TX! z73*)lNxC5_HpFbj+{ef$9V|2x7#pi%C0a}`JjmxIVSs5k2hqIRCJvO`J?0dsrEO=jl27v7fj~olJg#}(N8C7Nvb6#1HH%N4y0sgf z!(n|6Lc?kUh-tkI*JZ_kvB%nku-Dpxb`hf`@{>HLEdB&c;{SqFy@MMydkZP!PuG3C z8Z5q_y)XdPtVKe6zJ3Jg9rA!EpX7-jVj~W1MC4!;U#PbMPKOC_&PHxVe6fvK(ulZ$ zh!gaFz==siWv#^eOE>*abt&0h>M>7Cn1t`F+^u@HeJ7dyaO5)kK;`MpYlLm)WXCB{VrRM#ScSbWN8<0y?z#u7RnMp^a8r?JFeBEADdX{!E|xfESb ze_G~ubhm^=#I`CC40B*-#GX?zSAy*CZsX$)$7|W}-k}QVSD!0-UZusEYpI-FDlOhD zAkP<6EJ1y|Xb&a8^r1dp^rDI-agZYX6^N$4%wS9=>SZ^&q)UH8QNBqC=Mwqs(LNP3 zKp92&J3!UnW-u_Q16~b7zdF;ezi-}^0r&@bHmMZ(LsewECJ!j_yi(==P$l-O%KE2L zdYmfbLGtBe{>uo3;Ee6}=;1K1Qwb^d?eQ2h36s>4(TRDtKSO+=Y74 z4=dyc0%mX4%n_CPP{3RsK=gAJT^}&pXCnHAiarrA53wQqo0^UaZVo7=e9b+gsNhyx zpWmqHwg47^kiZ_@nI_6{AM|uOmGA--qkqR>%x+-3g~2OcKPH7g&YYm&j@ZIijS7ZH z$Enjb`<@xh+&&XSpMBK~C!)A4M5A?b!Uw5*QZuF<DcI4*GG^`f6p2!ddYceE&mpe&HYc zSfliOcz<)5}1@4ls`wZaItZ&s{jsVfT{4XH_S%z zmf)a9!)@P#Qwc0ABWxrss>?X;(&5|yU{3OZ;=COfKz{&%m5}N(ypSm9CqoF`c-C(x zLkNC6!#^294ZteuCh;8Ng#Kcny}yf5k3&)~b~!01bB#kFb{+D&rc$~*c@Ba!A}HY` z?&st86NJ+5h(pcURDD;ZP6I#hS zEs=W>P1r#KbZaDYol(Cnl5kEXiM~DZsD>y>!yOz=U^%%nlBQ-VxkI^&vmMSS04n(i zE<`geK{hLi;^q=5OXQgf#Lx9fkV=oCj*xyL%R!b}#iASD6$^r1^>Q9(IQD}%~ zP?9c2s27b*M)2k-t4z*7#Fa~##jfcT%y-R0z|6avBTxHXRa8*s@=;La@^g^(0D`js z5qlc!Bz#?jFJAD}(mT+mSY zg(M!Lp}SCch^C2Ct`-W)T{o)K9Tb#h<)blC9rCGFj=--M)mfz|CBmsBiAovIG|D=R zB=u(CnEo`X>hF+F{Gp%HJYyhB|Iv?RDV{xx{hjG$j+|2*;Q>Bxa0DM{;+U5BB|s5T zQ2<}{1ru~FK`&3*O2Pc(-3VNJDPHVqqo54mcO%`{1(Qy{E-KLf#;6`y-V{Znpe2q) zMe3m*kndN}e;^q1lS5IWrIR74uelhP-^2s}{VIk4jp6nC^%znH@w~FX!QY*T=SREV zRQbHB|2l@{pC-}UF+BV{ao&kxoss|<(0?04^Iu7MXADm+o;t_4X#(qucNu&Fd)+(E zah_7|scc>Y-&fUn0sKJaufjG!|B&OELqU#n8eNL$aur>waM3a|D0+bsyF^QAMmDJx z-D^B7s)$~!2Z*jzpY39zm#BOu+QTYb8#jxVl(1;sl2`$$C59gWqn%&#P) zER;MOrw!=AYr0XJ+^NnOKs{wv;nFAHGS^ed1;X^xB{J+@RGSLn<1OxaEwLPu`Y~wP z2YT;2%QSyOq?ITAfB;WACrPxx4?o5`iB@vGOs(a-t}a8-);^21lx!F>zb8aL9H7jWF*MVUF;nB& zw0m~|uLV4#k25FZSqR=!ah|RxR2|j~9}Hk^Fb+5D_1^^z$VWUNN*ny1>$3*ac^pP!5V%Rruh?40PYDxaT={$Azt1I2$ENHBS6{9zzZOrDJA2J))F@^OA3n_Q$Y zejLbpgvVavQ{zk>&HEJg%>D$Jzd;*5h%6HAr?XP|?oRv+HEGm}Fj^b_$|JT6NgA;R zgfJx5a}sYIP;!3KZJZpObRUNoCqIVJMUR4D@W@*V4<7qVDRO;C*+p5;pbwg$%h1PG z{QAT>`&HC>7^u2J5rLZH5lQ`vRZhn*Xtov`mUntH4aOj{Qkw?_MxJ~tG6u&-uXV&~0rC(DGQou@)m7A>DLE9a6 zg!w@bYu;6?aT9-!GlB6elKCie~I z3CgD0{ex-FGyM-R#6IZ%k&waf3}|2UgQB0Z%9Dm8Ah}585cG2h`VqQj-i+5yH6VLEwr8aRa232T|bLs-kuVm4$* zKoMOugr@`T&4%*b7uqXd%(2XsIJq$PFLzP&T6CGbl`gw*$=pSGKi$)0cJxvA=s&1? zwvW1B{)4*1(CLLZ44}L|aF~qzRQ{MiCG+E_Bj&ge)Z)HDY3X}Wpl>1-baT-DXD9D} zSh4ToJrB#rZr%xLiMNiyff5FBF+?HH5<FfEf?6vqvqpfy#F#gb_ZH>%7EUc|3Mvp{r%{-%_khK| z;RtfE@y}{8K$M{LFn$++VBRh>$_%8i{V-ZDe?8(F9BS!hB@iP$1S%fzFVA@H&+z&@F*uOuk_V4_fDqUL=EkwW+&CVX8}Au&<0RS;_yYj@ zg#vvifhkJ9AA##Jj%(?*Oys>nCgI+oZU3IYw*MYu+n<7p1oI4Fg_e{uC+-2;a<5|nz%!>~n z+^DEJ9K4y2OjG$>VYg0aq^XTwsM%X|g2US4R#w~&WyIaik4@%=pwOz{uIIfIiJorf z{dnFw6)yo6c@6zIpY~d0{xwsj1cFGnBoV)X3UC6q0X^d3DPW#>6N-tr3=kC`!W`O6 zgq0`VjDQxWRt}?F4{=!KdWwpRUC&ccG+`Fn&Bf342Bpg;63}EqG&vd83#f>gKh#OrxVWYUw z)x(WXfoLMRJRx3WfCt|zKHP&Ogu0yr*E0w(#au5^ve@+&=T4Y{s?+duy-(?~i3BT| zFiReR3(h&oH_f*sV9PDWIcK$nCj1!OB~Y=1EwLzGVWFC-O)Km1wR(LP-J=_?F>W6?enr*T3O-W+&QQxSIadND2E3s*!A~J5)kTydxVgw;=N*2%TzY zVvCW4eO*C8xoZUiHY`?i(VeH4)7@(qgy^6)ImS)2)O}RV=k1vr?zS{70%Et?hVPtYD2K&O8!EBW_h0)na zJa2ecv0KuFw=o~|H7d^L_gWR_qltAY&PNm1aGaTat;*&jmi1vYPMKN2I}h2MpErP0|16%0V<|KRLGOL;37??jN4y%)^c<3XG~9>m$> z%-IAM*AvVVCC2Y_oVoUa;uQc#w35ds_*x)Kqxc#q`> z#5wY0}Ch+}fd+6v1ns%Oeb+>U#l1+rW*n39&Q$tXo;_BGARo$uNwP6p( zGt&VebqT&Tppv7Iboy~gz7dy9J0)Mm1?N8G@xytBEw^uhRr0M8tla2P8nfLuGxT8B!V+FD01Kbo;8sU9)Com-z zcwa?DLyb?DF~=^l9t8o)*1Cv41QtI}qS8hD7(Gk!#asoq67%uu7RK!b49ThfEJjZu zNfY@w4kKKzBgA5GoPzS~GW2)?&|RNX8k>TrkU<0YLo_V(7z}I=%d)OV5%GbF%BhIi zmqzqZaxH$!^~yZudS!kR4F+V6h6AUMTGl&=kmbG$Rqr4OG(e`^o|OjVsp~T+X#ny; zT?-UZ*Hm;l6$QGcaPJ_Cr;1~9L$L=tm#83n~I@@RscO-jTh_}&mlV2Of=lugTp;0BQlO>GMj(fyi+;g^6B#5pkwJnJ84#Q( zB{-w20Dv5#>Ywxo@gzbV))1jihtY)eA=D87Y7&w-8D|E>{R6#twLgeg`xURo(Ms?H^Gc1& zlN@)bCmBwLe=(dmlUNCWL_rZc`D74d|2g$vmh@*v!}TKt^Idk-(~I-ZpiS~%#KBa3 z3Le8Gxp>j8j@Oi29I>-p@MA(p*+XbNKkf4zdj*Z>M}3q#QT24eOLmeMh2zUAK9Y`% zU*Yml~1F{BR#H9ISt$@~aDk>q`+QlzaakinZjNp?!Qo>hpQ?<*wI)YbmzL&j- zJn?FoGlAewR_Lqy%53Z_b6a1Td-}?JqL0izR{gkXc!w8!j>G5;8_6U1Ad)nK2RMvK zI>KR8(l0rTbsa+p!)v|kBqEr6f8_Lm^{($Z^5}XOy;j8*LKGs>0i zh5u@Fxdgup*^#xzs6d4)`>Jr4QNcPiM7r_&34|j?g&ipTgIS@M8J+c!QRURd&?&?E zfN|ca@ErMX4#+5m2wM8mCe~%>qr4#tl}dnK1{{y;t(IM9zo&_kZs%lF()~=D>v0N-UC(lEz3WvDYh1sj?D?+W zbF#|y6(x&Zf1#krWkDynca`!O!q;HA>#rK;N@~B_5ykg=@1Tw1YaGYHAF2{=CxO$i z;u)`78H#Hk1;yIvuMnOXiTGcmbc=dS?R%qf$P7&*0B@sVUILHLN2*oI>nMsM7DgKn z1u7jK70oJ#Z#70mvkGA=KPH;=K*EASXwg5K_p_`*VpZHldU-%JsbQs(2dcK`X%!fx z;wB725nCy zGjj$Zi8X381;ws(3d&u12zX`}a0Ir0vC3KGs^G}ei(D%Zfm&G2=>v;gn>h05BG*oi zJiN%&N;QhIi_mE{kaa!6X?45h8g}>hB~_OXJZY#pt=}2_TlrdFn|Y zX6StNG!U&|MDLrNR`d=_4UrS@3(%|Xg_mLZza0%)Nl;Gr zS7sq^Q$UoO{049hE+$CinHoyR&iDxtN1aT z1XdTT`RN=j@iuf%xb6dvt6hxeJ4lkE_=v-Zq%R56qNMLAC{NPSz_M$wD;yy-!w^o^ zyAmi_>>5J>R6^`!n)Wm;;=7IK2NYE|@vVPF)%Jmb8+1GPe!rq>r;0OGyVP?4Ow}za zem(K(RuyNeZsR8o6jitL;{;mb3Up7DwSb~oX-w5ajHpa{io=Mc=LyrIq&FxiPkN7Y z2fI#Fa=xpZll88@Q?l3<25>}`emP#5AmLB87&`<$_)fCWZ09|iiYmh+#S%E|PPNcs zw_&+CEhON%p988@cUsg5x6?u@Nu6*z`2`wvrt7p|x#p>X6K3`ulSO2Ir=1qIma97h;?G2(Yw)aw-LT=q`>ia8wz-^n~n z;KS9sIXB@&G7MWet|iJ@7(oD;j9zZeP$P&W$>mcVM!1e5gf{#Y1sI%Wv~Z>(e#~%f zsJiTAfa-~*PDLEub5A@rZ8=e*E=1K7fv2>_ovP z6=!+dtWL3c^S@Ql3dAeT_3A(yB>gOKw0#4&BQkDOF?=fiCXOYrS+bq0YKad310w2e z5VI?j2|7;5%}eS+Km>iwVN}w8a2V?fK?~dxibCMJ2p76vkicP$E1k-UT{#qBXu{{< zfi)W4B&#x;c&;R>Z7GwHsJ5cS_+-vj*rl*FL)fQsZYr>Ms2D9BPF0K;Tf3MASEDB) zWgke`b_tX53?YG&OA3lyZz8}q>Rs<~Smip+p~v+#6_>gGNYbYplZKD9=K4`9{eTQA4 zE_)rl3w89)CWbYXAM0TgBZQCPm30*sO4gOS8(`x)3491Bz`k9{rhrmLt%=pajk*Ums8$#JU$SeYi z!8y6(kzv(u2vz#@1_q||=?$SJP?Soa-Vhq3Pj3h%LX|$fA@l}Pr-qI;dVzMep+@4L zaUqUQ1}6vRFgKSGtME840!$B=A0b;FH&T9)>kbOaUH7TfV_XVz;WUF<@%lsWTYl8~xNTI$by?yC%^Z~53%OZ+2RQO8l}@Vz|l^j-p3*624J!KBDo3Aj$cI~u1_Jqr=dGlVlw$X9Xw7obE4T)@_Rbi%?D_@eyKkZP11Sw)I)@} zJVajl5g7~_W|kFM)9960eJopCAtD1%!qQ6dh$SW@KaT#RHth*w#dv)`Xz|f;?5Hl`BMKQ_dd{)h{)2CQ#0OvB;Upbccw^l#}K}PN9)AjdBk3N6uwNP8R5# zHrj=p%Z;3D%DItd`YdKoh?q&O=Fz5Uo<0G)x)3o7IZ*BwVMbk!(;I|eE-=-vqrFto?s{6f3_aqe|GZyXY29(XD8o(wjSSqcJlpabLfvT#puPQL$aJ-+|!&k!2<{6zuy{7{TF@|qh<{$jwIiIA@g?Q8cDwYLgrI}7WNjdFQ7eZc=-PN25A|h zeE)^aq0=aO5q=;Hi;&`bP{tl($oF4J2{jEFg=j>m^8FXu%lBXCFoMPP$@gFA@N-mu zKB7^f%J*MrFW-Nmqf~vv_h0B}7pnHV9~Wy_VpKga(W2P*U(^o-H>wyVB8q+gMX~R{ zDE9pqRZe6@wc{$Il<&WO2N_6q6#M>*3iACIHuEJE*{r|BHTv(kFsEZE7IPBP6XV9X z$IucSLtkl#X`u@-g)eBRqf$8491WgM2vffQ!kXt|6p3%-`!8(O&5#!GAyfkw!+QDt z3+v_kFRYjEzp(X$w(0vXY{ORcZTkKT^FPWd<@+zJlxO8Nc^ z+p1E^_g~mHl~TU{!fsG0<@+z}rZmQyeE)q$L=q?Z1EKgZ<@+z}7W#w-5&1`u9(Jor zDc^r#y?p;WYL%J*N`Lzi+{98jPkuvzN}hpAw{%}U+< z#P?s=<-0ih4qT&&L;7wEfErF}rhNZ}%{j=mj#4e+Twu^O_Wc(&_XJn?J+86jn_6cO z%J*N`g73KS@3=-2j{>cg$WWdVnLdO^8=!pugT%)}`Py%gP=7`7`x+vd& zVU^_C&1PLijYz0e*A$Csr3;BC%5O)!KTT?z^*%)5O%GQK`Th&@Jjoe{aE*Qo7X^W0 zF;oe4dDzMKUzqpz$gx?;WlQWCTy*|a3|y08RM_`lnDYG>ww!oGl0d%y!d7IUE{Qw& z{tK(=~Y+(D40N2>3QDNkTX|bn5_GGEDjY3+v_kFKjgz>^?+DXa@y+|AjsAD1*Hc*O2#cafT}2f1zV3i?Amkp_$Z94q{TG_`B%;dqU+5(SiGBZtj^9VQ_-Ua5-+!S2-+!S2-+$7PO=|%A z{u_K2yt6$PPOB38{rFlQXtn(^ zihch@QK25izW<^O-+#0U_2_#-A|DxHox!=8S_CcgwwbzGSZK|u(Eorc(Yy`09-XPL z2GM>aCV^;fs;|IotDCSeLU5gN3}@hs9KaXwQ3b4CxU$c z*?hX2>iT-s)!6r+bpfqCArGKPhAZEH;gw2-X%~_2zwjk0W%&LJcW*$|kWQ|zeE)@; zzW-GH<#Z6w3l{nQ3tvID2mAiB2Ymn81HS+40pEZ2fbTzh!1td$;QP-W@cm~G`2Mp8 zeE-=4zW?k2-+%Ui?>~FM_n$rB`_CTm{bvvO{X2GAaG185Jp0kj9)0NP*Jhp}Zhfc6)8Af^Kmd%z8#J>Uk= z{wj9AnuXi|+5>I??Z5mZ<&qmf`|AvW+yI6vH-I-`gj&Lt8^G}4l)@C&!uBB2fL3hI z7;XT=M>JD0xdDt!qzd65;=*nKBa|D!h+b|0BYNBbhLd|(b_3W?xdH4~5bOr9UvD>n zkpVY=k>g2}LdYj-OQdoG7)LXqV9oy8(<&Qz_*JFgkq=LsM=5qkFjlj2@$EDmQ@9 zV@Yk8ZUCcuxdDvMQmce=0~p=g4Pf-R-%}SMz%5$20ek@nW<)DDfYF!U!w4uhfYH;4 zcqnsr0~kGnYMO2UqYIii1vh|iBhsT14L5+%GyTX7p)VC#qm>)LXww>2ZUCd_enbulBS zvd}8Wbups|6g#eqL8M25e$@Jr%Qb6%cN9CWi~1DY(4*LKUDTg=z79Z6Xw;*qHd>Cy4Zl@x(ISy7du^Ff;vMV#)Tc% z#m+P;1{~K#Y^H`q`i)ePzM#gA>tc(IiUG%U5#+co_DcO})Cr%3v$9obxQ(S3T*NP7 z%~X?9Q;ypT)iky$$7PqRGWbwL3w<`VrTNCry5^`pYjjVLEgfv5e@$ym){~eSif4i z+*?HE3bouq;44hU#ZVV3I8s5aRH=y2uL#@{m5K@trFL$D3&n*VZ=zThWiGt~(YWjA z?6H-aJgKJ2NZgQojB-aZ>mDcejN-%i{lvFXr>O1|lsmer3HM{JN7eX83E4OKlzI430Di)xAOxFkJ;3yC%fh|PK)6_Z~?))gaBxxv7JyRN7GgzCDUx*px= zMTd<9PfN+b`K%4i=+yGMOX-w4btsa!U6C5kVMJ;=hf%4y2yvTwIs(UB&Z}`Oq`cxJ zF9PQdTs{Su%ch3NRKim)P9;qBc@DxAw{tZYIat+~6P3>!@42OcPruNKQE80r5kCJ& zXHGq*6TTV5pBHpu&=_XWi#l;=4Bx4ENhcPKVHPQ^G`0P38xXv20)qD~k3MnpF9B)$Ye3q*4@leJ`j)noQasK?$Y?V{WG8+Qms^n}rtRf0 zBK2VoqmrINm~<2u2Yt2%9P32DtO!BF2K@e!klaAeOjQso;&nw63CU2%o`nr3IF8|gSrx&VpVWxJv7X{Z_!udL^y)Z{`~$Er3&5Tg1bemtI~-5! z5&S5?ovUEKLU86Mk>^>*`xFQ4ar9u{y#%{H2zFfnb_2uKQp!+~U={&ZgMt@FZHtmp z5oj(yB_5(N-4+CBYXH#o2B3RUk$|-T$UX(An%Wj6`4DI>`mmJ#6k#NcM_Y)K77K|7 zbJA*20`?Uu5-2K9F~Xm(a~A>kitd>iQ*g zbIQ6?C9;A)$~PI!#`XRvUncCR*ebs5r0d$Fz}cexArkHN0w*3as;XP*P4_g`txorN zm$=-keCf6IO*QGuYO0sGU1QTS)5fNGd}Gp=G*{PnTuqH$Z+dlR_Ba<6r@MX4>F&m+ z+O*>TJ8*)!AV^xloYJ@{#c^ZP#$=`CWTa)Jjo0)RJsRhk(QqFr4;3zqxGoJ z7+gi<(8z>H@&s)esENp2d!D@zs!GHoVP^;ZRz#(WhV<9<{&qW6f_V_$Q=bkC!gQ2T zQ#n#A?4OPbwto1~8Rdi29$mSked`iO`}2p8O9S~ zLD(rgViGyGzp96UqHf^{xIX|)z#tDKd~ni|)r0P&2n!Gf55SlIHlFk*0`kVp2aAZA z@cV5h!Ixl;MFw*WZ@~n38D(-TI>50Q#j*a1MX@G}1}GK{G+8uAv1qU<0WfF?a)8Gd zp;xJ7gU}lqggm6_Vx!bRepn)yJKU%eq6P_H$uj|96-fi|NfAogXlUawUL!+##s_vl zV6b2bAYpV4Gs7rhSxT@25SCG+0_P>!v9C=I(Z--4C5wYpmPjD#2HI}-jNG9P(U-8MJ2-Tx+;9=%bWZbZx z)|xhcn63cf8N>?_HR0z3kR{-`JqUpuLO0Jqmx-AW;38F?7)VZvpqY^$;HAp=FIEdd zQUuih51j%~oyHXCJtN|RXT-=0$D76yhlebBJeH#a1Ft3l2_=`9lb}aSK+ti=GN3<_ zX-1^fJ@>@bP{@tPNFF~Nv7yPz?3>O^{rCN4kba( zU>&8DChnV>asmw-tOL^nvXx;f&M^VSIo1@P%pRb2Q;%l_WDOeDAc^gdae)$&((!?$ zlG1D=10?^q=)vGs+-|Po5k0w>&*7YlNMvuF*)K59XIEYEex9encObSe$$pNV+(xwEGO6I2qn5i-@4bGq@ z(*hZk{9g_J-=V>K)E#N?9>bJOg`T}zpY}3Oe3%NDC`!m#d&5%hnPEMU|Fx+Qm=4*Vu1ypgV1qA1hBZPaRFGIv2)3@KPgFX_BEzs!=Jv)?WT=?dUY0` z0Ms_GNzcRyL1ub&t-Ge# z+{)EfH>J7JH%Re#yi4g61s{A~TkrKDilgP#?yAa0MDdV7ML`7`Ev;ULB%WhfMi3B% zUeO-J&!Sz4Yj39gKRxHrG#qqP2N-;2CVV1{)rUKWmk;+aU%~Z1ZUfgxAv4z!g8q?H zLgQdJstxxzovz&BT>Bj$YthO<;stpAr+LkzVlZBDIXFiPPLRB4TK$rm>ZMJ-f6iqv zzq(Fw`5!PG{5KhnDC$=>(l~$;h=$n~*+?lk<``n6nyOcNRi>|cna|sVI7Zgzt?{}k z9;iXN?kcZGRj6;OYV=lmOh72~R5yBSjpjXZGzX1n!haza?M5*FTV0PAYaPO#Bbpr| zx=pMq5H|OsDvwLH2)keI5D_xx{F1`ryp%HOk>xV>&*58Z^@}t9af>} z+;HyD33PPeTEh5k;h%tST_Z)^9utJlqg>J{4kG^8wM5Ht;h0~RS6O}`K7>g75~qw2 zHcOT+e<$|%EgAZu_tCJ6f!r(F7kk#mSn+3Z&XN%&mKR{a8{QRbWS8ZV zXmRG6?Msu>WZo&U&M$rt9hONk>#7pP5x;aCI^nHsK_5{|$}9=d(;vA@ymPHXJR#iE z^TgZNO8+CP#N%j?5mk6-fq3d#h{)0u*Sp6E&@R!yL~PkWMEqTE$WH|7TQ(5t=XDm5 z>oyc{!f{x{6uc{H<#zNmM}mw35#C@)j~1&+#XL(Q7=xw{GN9k-1rzbva-;~*$GYr3 zMwq<@cdv<2Tg6;idg#P4izB-3>}&G;oZpEnED5Ul32y$dPRu;9!H>p|=&}=ucNvRE zbjM-Ks6oFL3yEr9aXDJc2SueN6U}9z%-tdub{snKi=>@0&nspVXCB)4zMLhuJ}cIA zG?tW!b@E(eYMEH;K18f*SS{8$%HBQpp6~oDu_{N{hw$$aS;j>d{z5d%Zt;}A)sh-58V_2=M2lxax;@#sr>@$u z#4{t;;)%A@_80%QRt^*4-ExcX%7t>0SeYXRcIJwe4dQvfbniTol_7>X#Qf6T9+8HM zOQhpiwo}A(i>u|ZSK4LC9x?bJGS%3gFbJ! z=%-pzotZM;DH>ZX@zHz4?RvwlVr|YEsQEcAk>D4VUAL_sBO8USKy+x`JIbA6M5*vN zwr<WJ*}CUI$wnCK8QhK(z05&3>m+pvT3#p;Iaoluy=_FPuz6hlizRl~xo z7i8yNoLkn?SmG4_=6B>x&nw#@KGfV|pTAVRqZMR(${I`1_n{JT>w340nDrg$FFnNM2ZR0b-Rw`c8x^^_?itvuAAwb6^Y#lor4a$(YLaZHD z2rOHcichq*;U#4YUw?hSu(!p{cY0^-+qd6hfvmobots4~`!AN&YG38b|KG@K+#`_J zCqr}*K8$p8xL*zz;jMC1ZfdS@x}Ojix3!dYf zQ*w!D)n!9rN{cwZZo62QGiK}T)2qdnkTyt{7-$)%i)b=!o?hDkt^0N;Rt*upJ#M2V zd4Slw)^e#Xeh76V=Jtw~Fc=&WotO(VMXVo!d{Evh`pJS#miXAJqTPx4vZzY*vn1={ zVZUX9F1G6j#h*90#VvZ5jLR;YwUNX<96fFpS2~0<$C4Q(&aWvDKWaJR+y)0ihuGrJ zIV@I}id}kvh%9|yT-_=5hWbTKo49+OTYMcNb39`Ax(0Dah+llUt`wGxTikn%Y!&ZW z{i5xfQiKORV!T^KStjYCYaN!3mr(K?N*=YAieuNvHsO;w;?eb`vR&A=Tf>{JaDNjn zra01ty+BTOW|xVy1~KiRa7kLM!W%q4c)*#}=a8^9$eR%VB(zjCT2geUSV2qI^J^PY zJtwKs%c0!n=-LLk1j&a{FQQv|N<6@%Q;t|ER<<>YQ(>}TR8jlHrj*Sxl_T3WitARl z{wq%I05@)1(*n+RXpu-#x#LpsRfmkIw#6e$& zg7kJon|RjOx?ij-Ju23uy?3J z@u*G$9u8w17EX8$Fg;PVZlOGz;u3K%RATowIYmVmtg$L#YZYrd+Qk*X=8WD3vKEVQ z_xmTF{YIp0$JC(d61hDe_8+8CM0PvH&+0ms%bAyprULP&DEDr0N8NUDLq8ZTc9~;I zhIADCReYx%6pvy6F{!ogc2NPgl*;qe*9zEe^3X`J4VosUR9q!H(XN5p`Q=&>*@~JX zgJ${6Qh7-9D-}tl;!4?u8oyFCW8M^98(@_05zkoMB4U_ma!i6r$1$WEVDB|lw?G(V zK7`bgs*}h@7FZHv#d5c}*df0Y?v5kvNiCwvu}8e5`TqqB`M_yFNOg)xH(-=cD3oVr z<;sBoa|QUe&T&`)>eNa{Bh{WSzFz5u9uv35IK($A-CIeW-5A3YC&G_0b&nCY?%g7H zyWD6=17?0e&E0rqp(Q?QbFN%2cjj(fPzduMiRUa?QBbAgi<*BqclN_p{B~uVXos8){1tLXKBDmb8mmr9ih7=w9l#OFtWsFRSo}0y^8cwF+T^EyrE$24I4Z+v9_R{C^YPEp)S53SSr4*f^s|J z6Rm?7al*5+O18=}Q*Fz446XfzGuwpf7p`trLK_&Qq)m^l;T4a(7*MYt2&I2aEbiKo z?Sb7E;dph1C*xY_5x-agmi@D3Xm9^cak_@6{vgILe!j94A%^|)6{Y4ty1Hj2E*$R@ z)7z@okVJYL#H0o+%5HIm()|8Lu^$WZu1h9~sDjs^CIxg8tO=iAM3;(Ht)l)Mmh`tR zvNU)>FFoxknTXYVd8=B>Z;I%C4$G*#4rd><06Y=ukfV`tA50Brji`}1l>5%ogTj6g zRbV$a0Ef*P`KF@UE^J*mD1kW*X@pX?wPD*Cj&qa-AC`QlsBa?x^Bq1*`~dND9b!xB zvk8IQCB{IwI(Exrvi$wCsFt=5g&iAZ6Rp@oEo1ckMEcrXu@=~3u>;BPX|mz-LJ`}r zFLARRffbhQ7)5nd>8we4xuV)H&To)zX4;2ZgLudfyTWMw?^bA7+c2>j+TAZ!L-e=f zIWSp7CQvt^U~>Is7(p?^@ZpQJfBKTlE=C`A!@?cESpP z;@X3Arv~x2H8?zj;g+b&jj$v;aQ64DcqAMZX=~wtj;{Jpo?4Y(v>ERYJRoO6D8t>^ z_=)Dy#&K!+o8_Ka$L3<`eobre{dgT2DW~hi(TLXeN1fs&pZ`=#qxjmsy?HVA0WH~B zx!sdoa_6Si$2Lpnw$+KNWWL<&g?Rvb1RI$rb?L{MYUyPBMkTJP^UC2*P@l`kQ;(}l z^Kw_F<*hm-uJfIHq*y%F)GB^6*q>Wc<{2ZNSmyr`y5m(Ci_~XJ_(88|UsmuuWxh59 z^o>ea4OYVg{8VhL>?@0 zrh4SUnkp=69gRNG3@jTg4qY7Z%X53ge`vC6M2f3&^6Ek;nF3#GBdq&w5jjjWIz%Mq zvRm}e!SR7;YCxpr4RP+O&eP&&qj>@8cd)T>a^57dI>*Xz*&ddK5FERGEAp6io`H$jPIPq-#G8%LKp;@6tYDHPA) z*zeU4hjsIgI&u{l{0uo}sNrU#f4R(@yLnQ=J*o zDK0Kp<;k90E*6}V@mZS-KQC;ebMC1SmnATN56ya7e0kNm*{e6z!CV#Vy2ZIs4d>f& zkh`5sBCPpY3qfpnCroq(N$QJ8vO^0-!fH&6o(mr1XmlaYFlL{h3KPMBQCeI8AYW+* z=}`THDnPh%L7RYW{Kq6YjQE2#;+w_piHF7R5#3wFsDnQ7+~RH|UmZaloheIl599o1 zj64J2=g0i*UEwV_k19~ViqsoMG_2Z)1v|VO#+P_+aSsn#R$~{E)FyT38Mbpwq} zI?M+9cG2v{@&2Jy=i@te%DEz`ZARlajbcE9+yPu3tB~6_iZ9|o|Dui);<}OYps-;- zI-nZcBnN zF4!Y3cT*ovh?5nteJduq#J|OLzjaGizBmT!+J-rcq1!mhO}sjQvrh4clAP0GucP~| z$1ZVBDE6k`H-_xsLCpWPKC$=ebIUf0&qsCN_HJ%TE>6!U1(Q*oWsaoelngR8bLJ1p8pci&d%!>)^Y>cFB0 zwmvRkeZ6%R;mG3Evbq6x20Fwao!xx1B*LGCxh*1cFjCmfF3L~L7tYo%vPKruademwT4v zz9%*<>=eg6#d)89};s` zFAxn4WPvx}7Kb=kBMZiF3(LcRkkyC>-jK1E1p7 z-WVJdPXGh)2CU_0VClb6Q|d)uZ2>a4uUF!>i(^0Oz^f2>0)>AsmZhw1&p2?9R3?sB zw_?&SnJ}w-foE^ZQZm|hiq?@yEfXr6#fOb;v=)px{gC33n|LHgc;67~3TBIS!^Vi~ zm*wP*-&t3_r$?pV4GDF~&IvoPy&IV{1}vV4^P8FJ<<5AE5jv3p(9uuZJlE)&X9oonT>%f?I)YaIDmn_5IPoho6M zS$ZXQb!du7JUL%vwu;h&YV~u-J-as_n+213nz*WUbCDb+zR@~96@v>P3K@^!PG5^~ z%dWG|ys2y2Va>m$%MO}ETh8ysi5TspBRlUB!w()RE0KAyH$Cm(gx`~&Rn zcb*bE#5t08x!em?MCvzIM4S_^ulG+Z6h|$s;#I9wY+m05sY$~OsOpd-ac+WL0nb+P zxJ9~Q_1iHM!b`JgYfk40D8=?EA4iO~))Sk=E&dZ)87v70OsBr0~dn3ys^)mm2$C4T)<4W4)&A3-4aMMbc zd#khC<$e3)WpeLz;<%2JpqZ(0$q=R^=h1-;8<=$I__pYE@td{o6mcZ9LA<&)=Pqxa zI2h{oiH@}mWpd^z@lq&+jc&L=)jv{Jg4=V#+c66pX4fMJ~f(TPhCJW5UqF zDt;Dz?p+bl(LKJR!!mC`$>22o@CsoIA3mS5g%CmYb+_z zo-G^qoiCjD31pzi>ZPEp;}^16uazIm_oHXmMzI}}cOn4)wF)G*mIQDnGqs*$}AUoV>ie7Mwj~iZ#%9tuUCe zKw$QfGBo%Csd+4a>Oy(wb&!--?C}(PZ}P~ipj0*%leL$(8Z(OrX|5>lI=}lCHEN#}9-qHEcU<*RoEpes?P7K*lEShIn8}b610$N$*a_s_PW1{DoNh9uc`vjJvS= zk*6MzkQbNSI5xLX?!a;0^Umu%B|F3d%Pf8Wv^{iN155Jo!Xvn8Gfd{b?vjnLt|Gb* z(}B{=+4&U{Yjej>Om^nImMfaNTJSK!9&Es{U*aQ}PTbFt4bO|OHQCmV8~J!7#y>r8 zyzj2Umeu!+bMD-{+a+gC6WMN24mH0~RJV$u+uN_G7CCM)r)?D%_G^Q*K(lx^ibb8m zwY`15s5vNdW$W`ei^R(Dsn%*qiJFB~;V!@bb<7v&E;{_QHRPqpbVAoFMzy-gPI@5hTzX}h@q|GvK-;?%RQux_FJIEF7thGIBnHlsGslKL27lkIH_UPtC+Y2 z+n24Yk1Wc-MBe`Gu_d0vODnyzoOg(t);(e+PR^i~+C@&OxWm6)e2IPQEx7ISHNrcv z=i8=Z$$A0n`imP#z+KQuUux%OB|a{9X3uQ7Zx$&@$CW>}+(3MW)^5eNeqq&)Y;37Y z8`q$pveci8`qmk_H#x=f?(yYfjBNN);nFcH@yL#n7H6SceM*iXoXS$Y>%q#`c&h%BtlwPhvVO^HjJ@a#v<#;U#Ny~|}2FMHv%aIb}k)7|Npb!b^SLYsh< zpfqdMvA1OITWqUz7J43D1|{QJvJBe;KI1Eej8$zcXDb9FkDaW$*!!2P{pHCp@`~xE zCzjCjc%sUU8yVHoi{;@o?w&vBm&0g*5F4A%?b;|>>}_K;*yvwLwU)ZYXxv1|E6K*xwj@PE|8?Gxdy{w;XAL&oWRvfTpWAT^ zS&K@!*&cCKo7mipI0`S(A^taQkp5G7({f$8d*A(HT-xJ1<$JR?j`z;mi=7fq0k5SU z!~*PrC2o`-;fFf@t8bK7Rr;#_>9N}Xki)Z{hx3BZ%r1OTkKT+IPw2XsT*`A~YQf?O za-*+BzOa?klXFD=K`|9qH(wpt3qn#Jc?Raa^z6ndD$a=4wdUqSTj%D#inVtqjPXX? z&hYtVtvoHh(`Dy^d6mzfFhW88wdI_6ay^b?aK}o84zDa zdZpLXB7C?r+z5!nyyEWlILk`g=qoG9l@D$e9|OvLfby}$FCJSj@sP!WX%miB(LMJ9 zZ%Ue2)zAV3Qi_|^r8uuB6+dnWB5osR9;RKt?GyIqr%*(?C+y9j*teShlhuvbq_2^!*m&@R z9@qVU`9v(e`itXcdgM5?5Q7+_8_%~QL%$xUpEg}R?@G@b|A;?4fqbouuv)K2D|~`L z{oQDlci{!^DUouEWm#BwJTO=g>1a4}o8d z3t$Ax2$jG6xK(zVupk3dwuu6wk$6Dm2liX#Uqb`5p!~94<+$CnA|wF6Fh~Zu|07np z+w32*ePQ_v&*O9SK{9w@`I#52vL9rO@egVrXW*xGSmkAAdz1seOSf8QV}wDwQK#rt ztK9w%>X>w%d=0$rqaU+8?oF$F6YdDiF`at>oo70&@;>xumS4!neaCQHE~xy%afo}@ zD%S*+o9$`LiI4kGJ~^nI<__hbM1EONzA3*{Hu<JXDJQSVzNy_R9ZFzGV;i2J}QKLR{1$M|6Wp$d8m>O=d` zDnB>t0MDPu0Lp&=E(`-QY?k*W_r#YH3_jg@>ZPlUc}-=DKeo!bCcGfN5KUBmpvx*B zGs}UqNt0Q=_!B&|Zqf{V3P@X{l35=0nN=?6qdko!!LR?qD#x1i0>0Vq0P?R5lEDl6 z&G_0Xmzw?df!Dr2VJ!Z^Tw}VKUn35;EyRQ<~W;tn{2_?Li*ra3-X8c0oQD|PvCPAW;@Vr<{vqVnxo%Q9 ze^1^l?_*r(d+xtB%ljC2`lh#_Je)EFw6Oy z&q1;S7=_zJK<4RVzN3Q5e=_#?0BuPh@J$@)!>zq|*cXoYJnF5%Ft&<9;-d+JzA>6? z(g{AOwE$8SL??a4@|?MzftRL?nRth_~yMbS#FH=vM zy3&MAp9WlEmh(6%TZ3TJXZ0FP{y|1e8_?uGeN}FnNn0O%)2H0XrZn+3`!?ItC)D2S z)wfy;%yRk|*_(Zon{$G`+*M(gqkoeo`qxb)L+E*lL!L=DeSxS)cl0rL=$ksngZqHoZz4#+ zFz`8=KLz(=*ajw#=*uy$1;Ys95q-mj{Lz{^&s_IS{OEfoH<@w~B(G*Uefs13KKkx! zZKO8!aO^N zBuCsgIpqo}H}lEw)ucZ1$$!wUH@XBO$ZByphil+ZJ zTs2ix(3^aKRZ&rJ>D)PG6@_yyojbc|*7TC;h!&NW^c2j!98r3L#*2{O8w4KJO%+Ss zXbha_)lG)eSW~@nTvjm1S+k}WOqo?NZF=#g^9zeg=FSg-u(VF|Rn;{%#WmOBO~P8Q zCl1tUJqdbM6t$auUcmSG7^=Ijxwgqm+1z)&L~acw5lYJE+3p_WmqZ5lIndc2;BrHyqfQA-i9q^WMT+kjHHbSdhR>#9rR_+8kzu^AbeW5#BTi%YI=^fuzv z#!89WnFe!~)T}UTC~Ru# zDhb27CCl*=B@wW+zRqVeHGqXkV3U8nn@fG8pCJs+8jG{(t~7ET?IX| zMQzZ;09@^1998S-vx`cu=oxpn2UV+U>w+rGnM*>#*{kZ@l}*)kwRnNo9FBSeSaSsr zDXMW9!iMHb)lYLpOUl=#tXUOvOG}i*1&voz9V(NIHX6Ky04{B&0Vg7O z8dOxk86uZ9R~Yi5*hP#-MPC)(V6CXCto76o@hhuqO<@3VC47p79xq8SAsELOm20q` z+3u-qssxC-=B6dhOM`0m$g677Y|w@mZ2nLBMN67HHh_X@@&Fy0l$5CwCnq1oHG)|f6nG^z2{ax0K(AZvo1 zJ$*LdLKPVKK?*`mN3&fvM?5{WnAB2sL9l4n)>PLj9DS?75N>AhZBEJb`E#Hbr_Z0y zDiLqhlX~SU%M1x(5{)>}HRL^*xZVR>i!ttDQ(?iJx$~zh_{GTWVX_*3aq$rR| zB1lJ?sv>B%^irKls#JZ028@ff2 zOCLWp0FoNiDyS_GBEZz^jKW#dwFeyhM)(%_>ZWsaxDR$HRp0|nO6ZOnpQVfLx`4Ou~MWrHPbXR z(n~!R=xzlQzp}D%1(s2a#!_BQS8_MK2x8jZn7Zy&O%;t^Uvo|GC9-ERH2I%DTq-s&sNx zIdOn7-mCv)zmD3+CNVqH~PU8^-T*Fj8|)Xc=4 zo|4KXHQowHMR1a4Bp^Z1DHyBOV89WtuC0P&jV8u|l6A(=Ev;2tq=|{~B`?>+za^Lz z&GqI$nlejbS5a95(}~AwDQqNm)De&bngc5dPxuF?dK#$#H8ISQ^)@!vHEK1UYPR4^ z&^#S58ylNpXn>&0y=!Mc>=kupf(SAA*jQZ$a@O_;P+hH?lo@d!Oy#C(){zScg@F=5 zACWnKdI3QFU!|RUl;lTM$A6n$AaZh$gcXCl1_(z~GP~J?xJVABr@LpmGd(k%?w)<1 z@MCtSXST`A^f=wK%km6}^3ZcsNc=e^qs>>ej7Wx9V4QC(0Ojwm!Qg+U8zDb%O<#(3AwgnsaB< zqqZ*M(n7q4^wrfgSSkZm#8q1UD5RF7F1_P2Vg-t~e> zBh6(kWhJ4ZXwl%(g6Q=9LFmt>#)589!;!biJ+(Ss>x}fxI&z?%osm^9+wE>3$ZqEx zF@1xO@2%{v1>GeB0AbD7LsJiSdfS#7WwN#>Lnjng53$E?_YsdXL7Hqt^TL`kjoQlU z!#FeOLb+%>h{AMwDzcHS_0RTqZ_4(}c0(YBef2*X9z}e~!B*Zsi?0}^!a`DvKAom} zljvGYI!}jESjYRjXlZX%V~~a;dlht87!L4aYf4;RM7*yKR{Q7&S}dn{Xk<7$)0n5< zqT7{~k06WEeUX!{by@|={Df4s{)j;y;PnL@&W(4+Z#ifTh%JW?o6-3v}UurZXGG#>TWUe(yvU#@LgFvIJUAov$x*qH)LAt1+gR%ka<>ryQ|+V zk>ht`YbX{G;VS)e#G)%*rw@sccx4l@I-GwUvX7Y+M4r)JY|L0JF9~QIK|bioeWN0l^MhQ?dIwZN=DVRl8(|^ z{mJC4D!bd;z0-PP%7sIODVeGl!-HthoIUJyh8$LHSnI638Yki>Q!8 zZ?J|6w=#6MD5Y{Sg9O8aXJf0B-m+N&=*kRhr5J;(?G)T**tS01o!#4B)od!;?o#^U ziU{`TgZf?PS9vMLTz9yDE*Hi4rn0vKie$2WOcMh`{uRwy(gIk~MXqzYHxMnEE-Um9 zy5ztH3zO$aWEPPRxpMzj)2eL7~lt&TgS%mZFzG!H)m)xk-ju1_=2#2WHe zZ8kX4QXyg-sqmDF<++JTP^(y3JyppvE$ zSZBa?#4@wDhyza)dML>=#${I9?r^xW;nI>});dp>(s@UVS!8@8!7(ZJ7s_^i zRJ^hV9S>7q*xQvesFum0m-;mQxX3wE#wv8)F6Yg9Jzr|q^YT)sEh_WtqHjUv2D&zH zR~yxGr@pk9q2(cbO2Z|CffAQ%rB=RBUo_AjLremdJk2A^%gl0Tx$84AuTc2iem{^^ z0cJ%1xXf>pEz3^t?E%HUE9SviO|XsniKS+Bk=a501ko@OlzwFg@nVRH*Ub9ncRZErpShdwwi=d8X#AS*)&tNtNhm!X_#`QQ+BX_2;mE~qAGjOqyFSO^Z z1_3SlbNl2X^U9^g`ctYEj0@xI`f1Dn*<{3x#b|d*2#B}8)y;xoY@-PW;VXXq#GY2Q ztVPjQeqy%T%G=Pjh&L?FAb5+N)>6Z8rP?T+?9>;CkZ(YTj;E%k|lM*>XQtVbqvmlB#8d2KHgiL>y^6G1GnmWmW5s34!=A z*IHU`whL~xPa@DufqS%0owkZY?}(1qc_d0PgCd|DC5klPO9)e`vo1AL?^p}$^kp$p zv>=P^8p|x8nNq7&M<9|QEftqfTHQ-(OSPd{gEGVl21rt6@u(`YOU%-zz2ego#=FX> zMPu#Ay4|cVN}A`}bS`O>!OkWYn9(EnNFk^uG?e04!A^v)QCcjduU$GOQLC62H@$cTt>5J6G+@welc21&P20Iz&SvWATpU?c)*w_5Atu(I^*3Sh^x>LdF+OEF_08 zH*k(VR5j9Ki*!gS=#aqTcAy^wp9ILXGnRGjHED81Tqrf0)We7y`>g#7ErYHZX_ZZE zsL-C$!6*|JviSS#BGXt}oXgeh0-aW=TxF0#Tl5&9^{QQKMb!hSo@lo6#cF%>W>!VB zh|8{{yizurV0bWfun0jRmCEI%<;6~Yk=diji!o!okj!*;F|X{)1yM>&Ihrm0q04qk zMUzkyqc9=%p*bpHR8|hlZMt~uU`)(;)2yAOOO)oSp*1GDao$3k*|!6WT&f(ax0hO4 zW!L;xMXtj78VhwKPy5zH-}b)c>|h*C^|aQdM2&VhzSNp`ejLeXmteTbm5qVu!7htu z#AL!4m_ux@L!{x_O(Y zhb9YR?^&9lV>K|^jMx0$h0aPyZ{aIJC{(*vZ8VfwTV2=c6f!tbULLF03`{PUSp1P@ zCcccj*hRuX2 z5_W_ddTHhctdLM-lM)RfVSuyTHOgW|Z;71sUKvt6OSidM|NR8R43hPnL2hS7Q_67} zx2Lx^=MFvGtE*vq%YcdV5yGeHj>$M z=~&t~P(0S}(C8vCsb9XA(izpy7AY*PObNQ-@fO2pE2?p;N0{*33#niwc_*^`&Gy=Io{XloFmpe#ub@7;uZZ4k3dM2vdn)_1aW zVEt2Z>>@12yuI9PG925hHczEWUD~+Ci0C5jQ!k|&w-O`w!a%aHjOB5XHekM#cL}XvTu;?rYFv9?5B*v5 z9e+b@mNB_VjU{ceLWd`UOQCmzG2!{XflgY=Ada4x%@;1HiIHaNG)E#@sA>sa%w>nQ zBa;JTfZHfa9ZXg&6~F||r8H%AKA7I}T6!%C`dH0g3DTBpd<0DNYPQWM2K8pme(Q5G zlxn5L3WiFU5RbhIsssIX<8n0)$tqkj~&bzl)&C5%}q<6Bz>(~S*AX7 zh+iB|dMuWsTx}J~G6?hbGCMOyQxz=*khVPET*4SK#xQ>gtcjKmhLg9m^FYq$;&TBN0YzmA%u2Yey1= zG(9G$t&W&@k1G!5D|*{lnqz`ojI0#hb~31d+p;*^*pnnI1Vx*%_-fyMNRIqzfsLVY zVKhb*W0^9Dt894-#aI}{`qnUAJKuv$E&;J%>7o)aDBs5F1E{xYU6T_Y;CO}fr5&|NbBr#Yp z<<`k2g9MVn^aX1z&R@(X4$I{V3+p-Ra$)J+L|7{h^_k^PTw7TlEgy|{gJPOHTBH)q zal0$3wzx>poV(h}RKRN_5A*A$s*Q8Q{B$w5LI66fDnnAe$`VFhIyQ_N3qxC^1uVqD zmeH8eniwIBa|?knab%t}3dcHoK_nHN$a5<+`)$~MVGSd;>N_04rneb#SfE%BAB^YM zk(?5L!$qZFo?;fg`bA*`*ov!?XxhSBvGt*~o<6RVgxPN)KW-9-1>Nw)#Ud59hMA~Q zCy1mG)9O{#6ud?DmC#~-=J7gxm4MH$-7Q;P@%Lfks=}xMjDEHPnOEjoVg1Pm5C7=G z{-Q!X7t=CvH-4TNSxcS+EHc^Dy0ev0ia+S|F$EDiQ0#7-wc%*$So05BR8|#d3+mwX zslC;ky4nQF3*q<)Uyot0!N9&9=?f8M)>o@cVfy+_&-Ol;tOQ$%J!To7&zaGUoxToqY+%;MDb#A|IJ(^`7<^BZsSGoOaK9S>l z++FTnZoi)K3t9GT?wh$^%I(+F=5V^n{T%M!kQWe{nxxo;>;e zI=5f%e=5A?{tWlObAOEcliVNT{%h{ynjW0nLSC|Iede`a_9KQT+X=CgO>g&y-RaUy z{Yrg`o|c$q(`)CpNf>^S;b}JMO`l;~i}p68ASaA*M)AYL4qFSSZA;O#HY#V+>i~lK znyN$3{_XN5&o=KV-3r^YvguXUE%|FyYvJb^Y~Y;Uz>uCkHQ=pQ1Js44`IFdt8#!w^ z+Z)U+BHYHpG+$u0%Kc;9N^>Xi?j+t6&rVOj>ff8(9`8Ky&J*uq z3Z-z>&*RB&fXYg6ra$ZTZ!q&GdG^cc?(o9n9eBxsiw}^=lnN0q#nb(4ZjYxw&UX0z z{JpjJ$4LB$ce-A{?eX+C#_stLf3ey^!attxi(@=xHHGJeslTF=L({LR`0!i&ik{je zdpc+P?&fbH>N#Fc?^dwliC%?xmAgm0<5j`OSMw~Mh+d6&wYyOQJgYr)iJtiUMsCmd zfh+g9_<>&t?|E&P=leF0$Ge<(mw%6Vf0o3XBHk47oQ4Sc^ZSx`R}k+C;@zSM@lrh9 zcW|qms>dC~yF>AGh$>!F@%Ju%_r+)ZDBcT_7ykG+6Y*;QjGqY)Bushf`W$!iI(z#0 zEc?6{J_-9u^2}rQr9T4>IZICl9CDC83^;H{dN1J6E2Q57R?k7s3XD?WlD^XK{wO8VO987ELH`6C zDj+=*urwC>5PcG`4j`g;(HjAW_|gvnN5POD;M$*I-EgVD>o<5m3H>@?wF>;Ce*_Gp zxztYs4kM5HW55UXld0bYEbkzpe+8UaM7-EPrcs42SG3~VpFN~_*2DhnrzUW!85N#% zV2l6oiTID0z*uF;wLhCmkmx;X0zbNtLj@ejzV=<$+m2JYQuwiig7C@&)_COCy@gNG zpG-fQ-(>vB@E=s3cX?s>Re6#j%J6*?f(l=pz?1Ql;2(-#lk`qPP=8cY#k?rHB@Evh0Omm)Ct*O1}+udEJ*C%w7q;ILiM%`on9%A3=Wkp{*aBy@iLHll(pi zz9Yet`Ts592c!He|IdOSR^SI^Ujlo7+lQw5PjFhE{iv8bV*geB9+D_K)$a%Ke=&*cez7x-@S+lK_Heg9%2z3MZS#8>(&68sUc z`;AflUjU!)jq3MRu=|Wr`283n+((S?L%{A6M))e>=p#tD40gXY!fmkohY{|A?}`3k zgog@`m+G(bKQ1Y+%K!KTKZp2-6Z}H(H3@zN_-KOv2<*OOl;3;7mFJD>dnfpD3H~_v z@d^Gs*!|5Y{nx;?B>dZ8_urv#3Ca~o_(8Dy|4{hD!S_Tz7s8JRyYCF)qu|3y`dQ)V ze?;LY!S2UGcth!B9Zx7*H6^=iWf8s~@55ZH>rqZ-(&a6drw42!9zo75z~Ne@i&}xDdV{CYbxh z5PlH&W6{rs@FT(Q>qGc3*!@=s&w$5T79i+@S>b71#^{yEz74*G@aM<&d>&Zq z6GSEc{j(SG^m@YI8N+{9A<;*i(!UApzTSl22X?<#!gqn+LHge?dW_Xde_QbLr|^FP zyPq!MZ-Cujl<<8tWr2V4sV96X_>MTftNk7WzB9p30N);c=qY{~d_DO+Hm1K3?7rs| zehTb%i^@OYz?dK2P|sBj*bL zFj#*_T>dE){spl6(-Qs`*nPAJ-&a$v*#45IhX~W&TE|lO&w$-er0_N11B@R*o*$h3 zBKY0#hv+7c^I-RXsrXH>`wSHRW$-sC?|&QpEIS8I^M4umz)M+gis65dgim3w{W16; z;Vy6Q0lWV;(Z37q^GV6qhrw46|GG%;vtaj&rubh3yMH&~{{de^{Mi`)0Zdsd;P*uN zd=$6?J|4rLpeZdrFW+qVl57^dM);Fr_*1~{Cr$L90Ui?W`sG<*_vxtc7lYmRpzy8W z7ZLyCk=`4?DZk$gzCGICmtAy8_CfG1#Q#)`|Bqmw-(H&iMD`W%>j{5*4F3+egT4Y< z`#~bhlJ>m>>^?VDp3A}SAbl&Q|5@;dlK$}|u=}-B{5kO5^pC48{w3Klu>0v$_!`)K zUJA?S(4EkCefI+JC%{^7m3+S%oXX3eg0D#Q>j%K@4^Z?z3U+^;!k+=(6Ma7le*^6P zm4v?w9??f1A`erPUn>O)e<=7o<@r~`S#}8Q{sk5OM6h2|JS>3SpQXZ|3jQYPwKl8z zY=IA;4_qFe3w~G}PcKE@UjlZYno9o)@YEZF4^`n;f&H4|;Vs~U(DVM2U8j!&>@buvA{#jZQG*V`Ok+1q|{wsNX>rF|i3|A@2)dxu1e zk1S-MFC=_3JaoFh)jhPf+dq4VuM$_To*5kCob=|Q4Hf6gBhyz;ADLboTy;prS-TP^ z4BbOXX`#5vv1eTV{>XIJy6b~jEPb${XsaCi^^lW?| z_TSB_I39EIJZ5~aod%=Rz+-1!V+_8W`{~#C#*Y~TZ4W{?gb%Xq62-|#UQB+s=T)&^ zz_-ToF79d2Mhk5!v%NPCY@dFbF77i>vT#~MfyL>uxYNV7+3DFf%Xsp*;oKoLo7nK< zAvHdJjy{!Z&%%XCN81TVRp)cNb{IN=u%W>Ub2@HJ6tIJHMI2aPBv6iVuYqx~*jz_! zKY!^7EzHkA@lu)F&MSS+FBljDY%7VU498DnNYVh|$PMquwl4a1wy<5kNM(CmL1K$B zL6uN8VVk497i(iv*rppVnYX6Z(LOOp9-(c-jM2fD`0VYcI>tQ*u^^+J844SD}wEpJPiIJEqVfBr3M^C=>elsGb%=t0~slZj`)ol1(g}F}38Ahktk( zGd~t9fltJH}!a+cc({48H)yZ)w zbZRwU9qd_7Vv>U6o}*9``Gqn6cWKFD#CzF=j_0RA8Z$Ug2@WjM_en|ATeMFUe37XX?{IM z9c{SOAu>+u(I)(#(gsr9^i8Oz9Z`}`7rC7YUO4avHxaM!tugZNWU241DU!ZGQzx<% z?3JYTWo)Tll2!R4;j!4Bp0mLu)@n=Ml?XE-ky?r*j2=CyH&(0QI42QbYKADK71CxG z=hy`u!s->qYq_^!lgy@^?4;=}O4yqzQ5g;T@i4KfvvV#@K^Z1Bi?MudZ>(oSc--5} zVEe)zYq^{944bs2k<+{g7pFqsbP)Fccc0lCV?^E+E8u7E+N0M_Z?JK0XEh(5-rK%u z`V^;F*~d!9T1|=PbB(2$622s7XE`XBa~Osl`L-u`ELL=}5Vx|cTJXdi%kVqsjunD# zFy4Yz!FbY8NfT!=ky3OC15!n+a literal 0 HcmV?d00001 diff --git a/src/pbl/pbliftst.c b/src/pbl/pbliftst.c new file mode 100644 index 0000000..a8e7daf --- /dev/null +++ b/src/pbl/pbliftst.c @@ -0,0 +1,982 @@ +/* + pbliftst.c - interactive ISAM file test frame + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + 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 + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + $Log$ + Revision 1.1 2004/06/24 21:11:54 sears + Initial revision + + Revision 1.1 2003/12/11 09:10:48 jim + pbl + + Revision 1.2 2002/09/12 20:57:15 peter + fixed a documentation bug + + Revision 1.1 2002/09/12 20:47:05 peter + Initial revision + + +------------------------------------------------------------------------------ +*/ + +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char * rcsid = "$Id$"; +static int rcsid_fkt() { return( rcsid ? 0 : rcsid_fkt() ); } + +#include +#include +#include +#include + +#include "pbl.h" + +#define PBL_ISAMTEST_BUFLEN 2048 + +static FILE * logfile; +static FILE * infile; + +static void pblsay(); + +static void putChar( int c ) +{ + static int last = 0; + + if( last == '\n' && c == '\n' ) + { + return; + } + + last = c; + putc( last, logfile ); +} + +static int getChar( void ) +{ + int c; + c = getc( infile ); + + /* + * a '#' starts a comment for the rest of the line + */ + if( c == '#') + { + /* + * comments starting with ## are duplicated to the output + */ + c = getc( infile ); + if( c == '#' ) + { + putChar( '#' ); + putChar( '#' ); + + while( c != '\n' && c != EOF ) + { + c = getc( infile ); + if( c != EOF ) + { + putChar( c ); + } + } + } + else + { + while( c != '\n' && c != EOF ) + { + c = getc( infile ); + } + } + } + + if( c != EOF ) + { + putChar( c ); + } + + return( c ); +} + +static void getWord( char * buffer ) +{ + int c; + int i; + + /* + * skip preceeding blanks + */ + c = ' '; + while( c == '\t' || c == ' ' || c == '\n' || c == '\r' ) + { + c = getChar(); + } + + /* + * read one word + */ + for( i = 0; i < PBL_ISAMTEST_BUFLEN - 1; i++, c = getChar() ) + { + if( c == EOF ) + { + exit( 0 ); + } + + + if( c == '\r' ) + { + continue; + } + + if( c == '\t' || c == ' ' || c == '\n' || c == '\r' ) + { + *buffer = '\0'; + return; + } + + *buffer++ = c; + } + + *buffer = '\0'; +} + +static int commastrlen( char * s ) +{ + char *ptr = s; + + while( ptr && *ptr && *ptr != ',' ) + { + ptr++; + } + + return( ptr - s ); +} + +/* + * if given a string of the form ",key1,key2,key3" etc, + * replaces the "," commas with the length of the following word + */ +static void commatolength( char * s ) +{ + while( s && *s ) + { + if( *s == ',' ) + { + *s = 0xff & commastrlen( s + 1 ); + } + + s++; + } +} + +/** + * test frame for the ISAM file library + * + * This test frame calls the PBL ISAM file library, + * it is an interactive test frame capable of regression tests. + * + * Interactive mode: + *

+ * Regression mode: + *
    + * Five regression test cases are supplied with the PBL ISAM library. + * + * ISAM0001.TST, ISAM0002.TST, ISAM0003.TST, ISAM0004.TST and ISAM0005.TST. + * + * ISAM0001.TST and ISAM0004.TST are run when the "make test" + * is done. Do the following if you want to run the test cases per hand + *
    +   1. Build the pbliftst executable.          make all
    +   2. Create the sub directory isamtest.      mkdir isamtest
    +   3. Clear the sub directory isamtest.       rm imamtest/0*
    +   4. Run the test frame on this file.        pbliftst ISAM0001.TST
    +   5. Compare ISAM0001.TST and pbliftst.log   diff ISAM0001.TST pbliftst.log
    + 
    + * There should be no differences reported, if so your build of the + * PBL library is most likely ok! + * + *
+ */ + +int pblISAMFILE_TestFrame( int argc, char * argv[] ) +{ + char command [ PBL_ISAMTEST_BUFLEN ]; + char filename [ PBL_ISAMTEST_BUFLEN ]; + char buffer [ PBL_ISAMTEST_BUFLEN ]; + int update; + int ival; + int dowork = 1; + long rc = 0; + int len; + char * ptr; + + pblIsamFile_t * isam = ( pblIsamFile_t *) 0; + + /* + * if an argument is given it is treated as a command file + */ + infile = stdin; + if( argc > 1 ) + { + infile = fopen( argv[ 1 ], "r" ); + if( !infile ) + { + fprintf( stderr, "Failed to open %s, %s\n", + argv[ 1 ], strerror( errno )); + exit( -1 ); + } + } + + /* + * open the log file + */ + logfile = fopen( "./pbliftst.log", "wb" ); + if( !logfile ) + { + fprintf( stderr, "cant open logfile, ./pbliftst.log, %s\n", + strerror( errno )); + exit( 1 ); + } + + /* + * main command loop + */ + while( dowork ) + { + memset( command, 0, sizeof( command )); + memset( filename, 0, sizeof( filename )); + memset( buffer, 0, sizeof( buffer )); + + errno = 0; + + /* + * read the next command + */ + printf( "\n##command: \n" ); + getWord( command ); + + /* + * interpret the command given + */ + if( command[0] == 'q' || command[0] == 'Q' ) + { + dowork = 0; + } + + else if( !strcmp( command, "open" )) + { + int k; + int nkeys; + char * keyfilenames[ PBL_ISAMTEST_BUFLEN ]; + int keydup[ PBL_ISAMTEST_BUFLEN ]; + + printf( "# open filename keyfile1,dkeyfile2,... update\n" ); + getWord( filename ); + + getWord( buffer ); + ptr = buffer; + + for( nkeys = 0; nkeys < PBL_ISAMTEST_BUFLEN; nkeys++ ) + { + keyfilenames[ nkeys ] = ptr; + + ptr = strchr( ptr, ',' ); + if( !ptr ) + { + break; + } + + *ptr = 0; + ptr++; + } + + for( k = 0; k < nkeys; k++ ) + { + if( strstr( keyfilenames[ k ], "dup" )) + { + keydup[ k ] = 1; + } + else + { + keydup[ k ] = 0; + } + } + + getWord( command ); + update = atoi( command ); + + pblsay( "# pblIsamOpen( %s, %d, %d )\n", + filename, nkeys + 1, update ); + + if( isam ) + { + pblIsamClose( isam ); + } + + isam = pblIsamOpen( filename, update, NULL, nkeys + 1, + keyfilenames, keydup ); + if( isam ) + { + pblsay( "# ok!\n" ); + } + else + { + pblsay( "# not ok! pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + } + + else if( !strcmp( command, "transaction" )) + { + printf( "# transaction < START | COMMIT | ROLLBACK >\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + + if( !strncmp( buffer, "ST", 2 )) + { + pblsay( "# pblIsamStartTransaction( )\n" ); + rc = pblIsamStartTransaction( 1, &isam ); + + } + else if( !strncmp( buffer, "CO", 2 )) + { + pblsay( "# pblIsamCommit( COMMIT )\n" ); + rc = pblIsamCommit( 1, &isam, 0 ); + } + else if( !strncmp( buffer, "RO", 2 )) + { + pblsay( "# pblIsamCommit( ROLLBACK )\n" ); + rc = pblIsamCommit( 1, &isam, 1 ); + } + else + { + rc = 0; + } + + if( !rc ) + { + pblsay( "# rc 0\n" ); + continue; + } + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "close" )) + { + printf( "# close\n" ); + if( !isam ) + { + continue; + } + + pblsay( "# pblIsamClose( %d )\n", 1 ); + + rc = pblIsamClose( isam ); + + isam = 0; + + if( !rc ) + { + pblsay( "# rc 0\n" ); + continue; + } + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + + } + + else if( !strcmp( command, "flush" )) + { + printf( "# flush\n" ); + if( !isam ) + { + continue; + } + + pblsay( "# pblIsamFlush( %d )\n", 1 ); + + rc = pblIsamFlush( isam ); + if( !rc ) + { + pblsay( "# rc 0\n" ); + continue; + } + + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "readdata" )) + { + printf( "# readdata\n" ); + if( !isam ) + { + continue; + } + + pblsay( "# pblIsamReadData( currentrecord )\n" ); + + rc = pblIsamReadData( isam, buffer, sizeof( buffer ) ); + if( rc < 0 ) + { + pblsay( "# rd %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + else + { + pblsay( "# datalen %ld, data %s\n", rc, buffer ); + } + } + + else if( !strcmp( command, "readkey" )) + { + int index; + + printf( "# readkey index\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + index = atoi( buffer ); + + pblsay( "# pblIsamReadKey( currentrecord, %d )\n", index ); + + rc = pblIsamReadKey( isam, index, buffer ); + if( rc < 0 ) + { + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + else + { + pblsay( "# keylen %ld, key %s\n", rc, buffer ); + } + } + + else if( !strcmp( command, "updatedata" )) + { + printf( "# updatedata data\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + ival = strlen( buffer ) + 1; + + pblsay( "# pblIsamUpdateData( %s, %d )\n", buffer, ival ); + + rc = pblIsamUpdateData( isam, buffer, ival ); + if( rc < 0 ) + { + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + else + { + pblsay( "# datalen %ld\n", rc ); + } + } + + else if( !strcmp( command, "updatekey" )) + { + int index; + + printf( "# updatekey index key\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + index = atoi( buffer ); + + getWord( buffer ); + ival = strlen( buffer ); + + pblsay( "# pblIsamUpdateKey( %d, %s, %d )\n", index, buffer, ival ); + + rc = pblIsamUpdateKey( isam, index, buffer, ival ); + if( rc < 0 ) + { + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + else + { + pblsay( "# rc %ld\n", rc ); + } + } + + else if( !strcmp( command, "ndelete" )) + { + int n; + int i; + + printf( "# ndelete n\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + n = atoi( buffer ); + + pblsay( "# pblIsamDelete( %d records )\n", n ); + + for( i = 0; i < n; i++ ) + { + rc = pblIsamGet( isam, PBLTHIS, 0, buffer ); + if( rc < 0 ) + { + pblsay( "# i %d, rc %ld, pbl_errno %d, errno %d\n", + i, rc, pbl_errno, errno ); + break; + } + + rc = pblIsamDelete( isam ); + if( rc < 0 ) + { + pblsay( "# i %d, rc %ld, pbl_errno %d, errno %d\n", + i, rc, pbl_errno, errno ); + break; + } + } + if( rc >= 0 ) + { + pblsay( "# deleted %d records, rc %ld\n", i, rc ); + } + } + + else if( !strcmp( command, "insert" )) + { + printf( "# insert ,key1,key2... data\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + getWord( filename ); + ival = strlen( buffer ); + len = strlen( filename ) + 1; + + pblsay( "# pblIsamInsert( %d, %s, %d, %s, %d )\n", + 1, buffer, ival, filename, len ); + + commatolength( buffer ); + + rc = pblIsamInsert( isam, buffer, ival, filename, len ); + if( !rc ) + { + pblsay( "# rc 0\n" ); + continue; + } + + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "ninsert" )) + { + int nkeys = 3; + char * keys[ PBL_ISAMTEST_BUFLEN ]; + int n; + int i; + int k; + + printf( "# ninsert n key1,key2,... data\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + n = atoi( buffer ); + + getWord( buffer ); + getWord( filename ); + len = strlen( filename ) + 1; + + ptr = buffer; + + for( nkeys = 0; nkeys < PBL_ISAMTEST_BUFLEN; nkeys++ ) + { + keys[ nkeys ] = ptr; + + ptr = strchr( ptr, ',' ); + if( !ptr ) + { + break; + } + + *ptr = 0; + ptr++; + } + + for( i = 0; i < n; i++ ) + { + ival = 0; + command[ 0 ] = 0; + for( k = 0; k <= nkeys; k++ ) + { + snprintf( command + ival, sizeof( command ) - ival, + ",%s%d", keys[ k ], i ); + + ival += strlen( command + ival ); + } + + if( i == 0 ) + { + ival = strlen( command ); + pblsay( "# pblIsamInsert( %d, %s, %d, %s, %d )\n", + 1, command, ival, filename, len ); + } + + commatolength( command ); + + rc = pblIsamInsert( isam, command, ival, filename, len ); + if( rc < 0 ) + { + pblsay( "# i %d, rc %ld, pbl_errno %d, errno %d\n", + i, rc, pbl_errno, errno ); + break; + } + } + + if( rc >= 0 ) + { + pblsay( "# inserted %d records, rc %ld\n", i, rc ); + } + } + + else if( !strcmp( command, "datalen" )) + { + printf( "# datalen\n" ); + if( !isam ) + { + continue; + } + + pblsay( "# pblIsamReadDatalen( currentrecord )\n" ); + + rc = pblIsamReadDatalen( isam ); + if( rc < 0 ) + { + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + else + { + pblsay( "# datalen %ld\n", rc ); + } + } + + else if( !strcmp( command, "get" )) + { + int index; + + printf( "# get index < NEXT | PREV | FIRST | LAST | THIS >\n" ); + if( !isam ) + { + continue; + } + + + getWord( buffer ); + index = atoi( buffer ); + + getWord( filename ); + if( !strncmp( filename, "NE", 2 )) + { + ival = PBLNEXT; + } + else if( !strncmp( filename, "PR", 2 )) + { + ival = PBLPREV; + } + else if( !strncmp( filename, "FI", 2 )) + { + ival = PBLFIRST; + } + else if( !strncmp( filename, "LA", 2 )) + { + ival = PBLLAST; + } + else + { + ival = PBLTHIS; + } + + pblsay( "# pblIsamGet( %d, %d )\n", ival, index ); + + rc = pblIsamGet( isam, ival, index, buffer ); + if( rc < 0 ) + { + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + else + { + pblsay( "# keylen %ld, key %.*s\n", rc, rc, buffer ); + } + } + + else if( !strcmp( command, "find" )) + { + int index = 0; + + printf( "# find index key < LT | LE | FI | EQ | LA | GE | GT >\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + index = atoi( buffer ); + + getWord( buffer ); + getWord( filename ); + + if( !strncmp( filename, "GT", 2 )) + { + ival = PBLGT; + } + else if( !strncmp( filename, "FI", 2 )) + { + ival = PBLFI; + } + else if( !strncmp( filename, "LA", 2 )) + { + ival = PBLLA; + } + else if( !strncmp( filename, "GE", 2 )) + { + ival = PBLGE; + } + else if( !strncmp( filename, "LE", 2 )) + { + ival = PBLLE; + } + else if( !strncmp( filename, "LT", 2 )) + { + ival = PBLLT; + } + else + { + strcpy( filename, "EQ" ); + ival = PBLEQ; + } + + len = strlen( buffer ); + pblsay( "# pblIsamFind( %s, %s, %d )\n", + filename, buffer, len ); + + rc = pblIsamFind( isam, ival, index, buffer, len, filename ); + + if( rc < 0 ) + { + pblsay( "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + else + { + pblsay( "# keylen %ld, key %s\n", rc, filename ); + } + } + + + else if( !strcmp( command, "nfind" )) + { + int index; + int n; + int i; + + printf( "# nfind n index key " + "< LT | LE | FI | EQ | LA | GE | GT >\n" ); + if( !isam ) + { + continue; + } + + getWord( buffer ); + n = atoi( buffer ); + + getWord( buffer ); + index = atoi( buffer ); + + /* + * read the key to search for + */ + getWord( buffer ); + + getWord( filename ); + if( !strncmp( filename, "GT", 2 )) + { + ival = PBLGT; + } + else if( !strncmp( filename, "FI", 2 )) + { + ival = PBLFI; + } + else if( !strncmp( filename, "LA", 2 )) + { + ival = PBLLA; + } + else if( !strncmp( filename, "GE", 2 )) + { + ival = PBLGE; + } + else if( !strncmp( filename, "LE", 2 )) + { + ival = PBLLE; + } + else if( !strncmp( filename, "LT", 2 )) + { + ival = PBLLT; + } + else + { + strcpy( filename, "EQ" ); + ival = PBLEQ; + } + + for( i = 0; i < n; i++ ) + { + if( i == 127 ) + { + len = strlen( command ); + } + snprintf( command, sizeof( command ), + "%s%d", buffer, + ((( rand() << 16 ) ^ rand()) & 0x7fffffff ) % n ); + + + if( i == 0 ) + { + len = strlen( buffer ); + pblsay( "# pblIsamFind( %d, %s, %d, %s, %d )\n", + 1, filename, index, buffer, len ); + } + + len = strlen( command ); + + if( i == 127 ) + { + len = strlen( command ); + } + rc = pblIsamFind( isam, ival, index, command, len, filename ); + + if(( rc < 0 ) && ( pbl_errno != PBL_ERROR_NOT_FOUND )) + { + pblsay( "# i %d, %s, %d, rc %ld, pbl_errno %d, errno %d\n", + i, command, len, rc, pbl_errno, errno ); + break; + } + } + + if( i >= n ) + { + pblsay( "# found %d records, rc %ld\n", i, 0 ); + } + } + + else + { + printf( "# q FOR QUIT\n" ); + printf( "# open filename keyfile1,dkeyfile2,... update\n" ); + printf( "# transaction < START | COMMIT | ROLLBACK >\n" ); + printf( "# close\n" ); + printf( "# flush\n" ); + printf( "# insert ,key1,key2... data\n" ); + printf( "# ninsert n key1,key2,... data\n" ); + printf( "# find index key < LT | LE | FI | EQ | LA | GE | GT >\n" ); + printf( "# nfind n index key " + "< LT | LE | FI | EQ | LA | GE | GT >\n" ); + printf( "# get index < NEXT | PREV | FIRST | LAST | THIS >\n" ); + printf( "# datalen\n" ); + printf( "# readdata\n" ); + printf( "# readkey index\n" ); + printf( "# updatedata data\n" ); + printf( "# updatekey index key\n" ); + printf( "# ndelete n\n" ); + } + } + +#ifdef PBL_MEMTRACE + + pbl_memtrace_out( 0 ); + +#endif + + return( 0 ); +} + +int main( int argc, char * argv[] ) +{ + return( pblISAMFILE_TestFrame( argc, argv )); +} + +static void pblsay( +char *p1, char *p2, char *p3, char *p4, char *p5, +char *p6, char *p7, char *p8, char *p9, char *p10, +char *p11, char *p12, char *p13, char *p14, char *p15 +) +{ + fprintf( stdout, p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15 ); + fprintf( logfile, p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15 ); + //fflush( logfile ); + //fflush( stdout ); +} + diff --git a/src/pbl/pbliftst.log b/src/pbl/pbliftst.log new file mode 100644 index 0000000..e1f0ec7 --- /dev/null +++ b/src/pbl/pbliftst.log @@ -0,0 +1,406 @@ +########################################################################### +## +## PBL - Program Base Library, Copyright 2002 Peter Graf +## +## This file is part of PBL - The Program Base Library. +## PBL is free software. +## +## 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 +## +## For more information on the Program Base Library or Peter Graf, +## please see: http://mission.base.com/. +## +## ISAM file implementation test case, this test case is set up for +## a regression test of the ISAM library, don't change it unless you +## know what you are doing! +## +## Usage: +## +## 1. Build the pbliftst executable. make all +## 2. Create the sub directory isamtest. mkdir isamtest +## 3. Clear the sub directory isamtest. rm imamtest/* +## 4. Run the test frame on this file. pbliftst ISAM0004.TST +## 5. Compare ISAM0004.TST and pbliftst.log diff ISAM0004.TST pbliftst.log +## +## there should be no differences reported, if so your build of the +## PBL library is most likely ok! +## +########################################################################### +## +## Test case 4, tests insert, find, get on duplicate keys +## +## Open the file isam file isamtest/0004main with three index files +## 0004key0, 0004dup1 and 0004key2 +## open the file for update, create if necessary +## the index 0004key0 contains unique keys +## the index 0004dup1 can contain duplicate keys, +## ( the test frame allows that because its name contains the string 'dup' ) +## the index 0004key2 contains unique keys +## +## open filename keyfile1,dkeyfile2,... update +## +open isamtest/0004main 0004key0,0004dup1,0004key2 1 +# pblIsamOpen( isamtest/0004main, 3, 1 ) +# ok! +## +## Start a transaction +## +transaction START +# pblIsamStartTransaction( ) +# rc 0 +## +## Get the first record according to index 0004key0, should report an error +## +## get index < NEXT | PREV | FIRST | LAST | THIS > +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Delete 100000 records, should report an error +## +## ndelete n +## +ndelete 100000 +# pblIsamDelete( 100000 records ) +# i 0, rc -1, pbl_errno 1041, errno 0 +ninsert 2000 key0,dup1,key2 data +# pblIsamInsert( 1, ,key00,dup10,key20, 18, data, 5 ) +# inserted 2000 records, rc 0 +## +## Read alphabetically last record according to index 0004dup1 +## Try reading and searching beyond the last record +## +get 1 LAST +# pblIsamGet( 5, 1 ) +# keylen 7, key dup1999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +find 1 dup1999 LA +# pblIsamFind( LA, dup1999, 7 ) +# keylen 7, key dup1999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +find 1 dup1999 GE +# pblIsamFind( GE, dup1999, 7 ) +# keylen 7, key dup1999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +find 1 dup1999 GT +# pblIsamFind( GT, dup1999, 7 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0999 +## +## Read alphabetically first record according to index 0004dup1 +## Try reading and searching beyond the first record +## +get 1 FIRST +# pblIsamGet( 4, 1 ) +# keylen 5, key dup10 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +get 1 PREV +# pblIsamGet( 3, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +find 1 dup10 FI +# pblIsamFind( FI, dup10, 5 ) +# keylen 5, key dup10 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +find 1 dup10 LE +# pblIsamFind( LE, dup10, 5 ) +# keylen 5, key dup10 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +find 1 dup10 LT +# pblIsamFind( LT, dup10, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key00 +## +## Find a record in the middle and read the records surounding it +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 7, key dup1200 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 7, key key0200 +## +## Test all possible find operations on an inner record +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LE +# pblIsamFind( LE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 EQ +# pblIsamFind( EQ, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 LA +# pblIsamFind( LA, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 GE +# pblIsamFind( GE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 GT +# pblIsamFind( GT, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +## +## Tnsert two records with a duplicate key +## +insert ,key1insert1,dup12,key2insert1 data1 +# pblIsamInsert( 1, ,key1insert1,dup12,key2insert1, 30, data1, 6 ) +# rc 0 +insert ,key1insert2,dup12,key2insert2 data1 +# pblIsamInsert( 1, ,key1insert2,dup12,key2insert2, 30, data1, 6 ) +# rc 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +## +## Test the find operations on the records with duplicate keys +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LE +# pblIsamFind( LE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert1 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +get 1 NEXT +# pblIsamGet( 2, 1 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +find 1 dup12 EQ +# pblIsamFind( EQ, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +find 1 dup12 LA +# pblIsamFind( LA, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +find 1 dup12 GE +# pblIsamFind( GE, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +find 1 dup12 GT +# pblIsamFind( GT, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +## +## Delete the three records with duplicate key dup150 +## +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 5, key key02 +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert1 +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# keylen 5, key dup12 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 11, key key1insert2 +ndelete 1 +# pblIsamDelete( 1 records ) +# deleted 1 records, rc 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +## +## Test the find operations on the deleted records with duplicate keys +## +find 1 dup12 LT +# pblIsamFind( LT, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LE +# pblIsamFind( LE, dup12, 5 ) +# keylen 8, key dup11999 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 FI +# pblIsamFind( FI, dup12, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 EQ +# pblIsamFind( EQ, dup12, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 LA +# pblIsamFind( LA, dup12, 5 ) +# rc -1, pbl_errno 1003, errno 0 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 8, key key01999 +find 1 dup12 GE +# pblIsamFind( GE, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +find 1 dup12 GT +# pblIsamFind( GT, dup12, 5 ) +# keylen 6, key dup120 +get 0 THIS +# pblIsamGet( 1, 0 ) +# keylen 6, key key020 +## +## Delete 1999 records, i.e. all of them +## +ndelete 1999 +# pblIsamDelete( 1999 records ) +# deleted 1999 records, rc 0 +## +## Verify the file is empty now +## +get 0 FIRST +# pblIsamGet( 4, 0 ) +# rc -1, pbl_errno 1003, errno 0 +get 1 FIRST +# pblIsamGet( 4, 1 ) +# rc -1, pbl_errno 1003, errno 0 +get 2 FIRST +# pblIsamGet( 4, 2 ) +# rc -1, pbl_errno 1003, errno 0 +## +## Rollback the transaction, the inserts that happened +## after the transaction started are NOT committed +## +transaction ROLLBACK +# pblIsamCommit( ROLLBACK ) +# rc 1, pbl_errno 0, errno 0 +## +## Close the file +## +close +# pblIsamClose( 1 ) +# rc 0 +quit diff --git a/src/pbl/pbliftstdeb.dsp b/src/pbl/pbliftstdeb.dsp new file mode 100644 index 0000000..9d5bac3 --- /dev/null +++ b/src/pbl/pbliftstdeb.dsp @@ -0,0 +1,93 @@ +# Microsoft Developer Studio Project File - Name="pbliftst" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=pbliftst - Win32 Debug mt 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 "pbliftstdeb.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 "pbliftstdeb.mak" CFG="pbliftst - Win32 Debug mt static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pbliftst - Win32 Debug mt static" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "pbliftst" +# PROP BASE Intermediate_Dir "pbliftst" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "winbuild\debugbin" +# PROP Intermediate_Dir "winbuild\debugtmp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /D "DEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT CPP /YX +# 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 wsock32.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 /machine:I386 +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 wsock32.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 /debug /machine:I386 /out:"winbuild\debugbin\pbliftst.exe" +# Begin Target + +# Name "pbliftst - Win32 Debug mt static" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\pbl.c +# End Source File +# Begin Source File + +SOURCE=.\pblhash.c +# End Source File +# Begin Source File + +SOURCE=.\pbliftst.c +# End Source File +# Begin Source File + +SOURCE=.\pblisam.c +# End Source File +# Begin Source File + +SOURCE=.\pblkf.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\pbl.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/src/pbl/pbliftstdeb.dsw b/src/pbl/pbliftstdeb.dsw new file mode 100755 index 0000000..0319b62 --- /dev/null +++ b/src/pbl/pbliftstdeb.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "pbliftst"=.\pbliftstdeb.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/pbl/pbliftstdeb.ncb b/src/pbl/pbliftstdeb.ncb new file mode 100755 index 0000000000000000000000000000000000000000..b2031c1e880facc3fbcab5b5d165c24eb9e3890f GIT binary patch literal 99327 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 WP{2R|0|g8eFi^li0Rw+d82EoL3HB2J literal 0 HcmV?d00001 diff --git a/src/pbl/pbliftstdeb.opt b/src/pbl/pbliftstdeb.opt new file mode 100755 index 0000000000000000000000000000000000000000..bd1327e77011c52feb5c5b44ad69b37b91084c61 GIT binary patch literal 55808 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 Q|JURHdi?+Y@A&^e0eV~L2LJ#7 literal 0 HcmV?d00001 diff --git a/src/pbl/pbliftstdeb.plg b/src/pbl/pbliftstdeb.plg new file mode 100755 index 0000000..fba81d9 --- /dev/null +++ b/src/pbl/pbliftstdeb.plg @@ -0,0 +1,45 @@ + + +
+

Build Log

+

+--------------------Configuration: pbliftst - Win32 Debug mt static-------------------- +

+

Command Lines

+Creating temporary file "C:\DOKUME~1\graf\LOKALE~1\Temp\RSP30.tmp" with contents +[ +/nologo /MTd /W3 /GX /Zi /Od /D "DEBUG" /D "WIN32" /D "_CONSOLE" /Fo"winbuild\debugtmp/" /Fd"winbuild\debugtmp/" /FD /c +"H:\bsi\source\pbl\pbl.c" +"H:\bsi\source\pbl\pblhash.c" +"H:\bsi\source\pbl\pbliftst.c" +"H:\bsi\source\pbl\pblisam.c" +"H:\bsi\source\pbl\pblkf.c" +] +Creating command line "cl.exe @C:\DOKUME~1\graf\LOKALE~1\Temp\RSP30.tmp" +Creating temporary file "C:\DOKUME~1\graf\LOKALE~1\Temp\RSP31.tmp" with contents +[ +wsock32.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 /incremental:no /pdb:"winbuild\debugbin/pbliftst.pdb" /debug /machine:I386 /out:"winbuild\debugbin\pbliftst.exe" +.\winbuild\debugtmp\pbl.obj +.\winbuild\debugtmp\pblhash.obj +.\winbuild\debugtmp\pbliftst.obj +.\winbuild\debugtmp\pblisam.obj +.\winbuild\debugtmp\pblkf.obj +] +Creating command line "link.exe @C:\DOKUME~1\graf\LOKALE~1\Temp\RSP31.tmp" +

Output Window

+Compiling... +pbl.c +pblhash.c +pbliftst.c +pblisam.c +pblkf.c +Generating Code... +Linking... + + + +

Results

+pbliftst.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/src/pbl/pblisam.c b/src/pbl/pblisam.c new file mode 100644 index 0000000..3dacb28 --- /dev/null +++ b/src/pbl/pblisam.c @@ -0,0 +1,3399 @@ +/* + pblisam.c - isam file library implementation + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + $Log$ + Revision 1.1 2004/06/24 21:11:57 sears + Initial revision + + Revision 1.1 2003/12/11 09:10:49 jim + pbl + + Revision 1.2 2003/02/19 22:19:39 peter + fixed a bug related to finding non existing + duplicated keys + + bug was reported by Csaba Pálos + + Revision 1.1 2002/09/12 20:47:06 peter + Initial revision + + +*/ + +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char * rcsid = "$Id$"; +static int rcsid_fkt() { return( rcsid ? 0 : rcsid_fkt() ); } + +#include +#include +#include + +#include /* program base library */ + +/******************************************************************************/ +/* #defines */ +/******************************************************************************/ + +/******************************************************************************/ +/* typedefs */ +/******************************************************************************/ + +/* + * PBL ISAM FILE DESCRIPTOR + */ +typedef struct PBLISAMFILE_s +{ + char * magic; /* magic string pointing to file descriptor */ + + pblKeyFile_t * mainfile; /* file desriptor of main isam file */ + int update; /* flag: file open for update */ + + int transactions; /* number of transactions active for file */ + int rollback; /* next commit should lead to a rollback */ + + int nkeys; /* number of key files of file */ + pblKeyFile_t ** keyfiles; /* file descriptors of key files */ + + int * keydup; /* flag array does the key allow duplicates */ + void ** keycompare; /* compare functions for keyfile */ + +} PBLISAMFILE_t; + +/******************************************************************************/ +/* globals */ +/******************************************************************************/ +static int (*pblkeycompare)( void * left, size_t llen, + void * right, size_t rlen ); + +/******************************************************************************/ +/* functions */ +/******************************************************************************/ + +/* + * conversion between keys of the main file and reference keys + * + * main file keys are 8 byte unsigned string numbers + * between "00000000" and "ffffffff" + * or 17 byte unsigned string numbers + * between "g0000000100000000" and "gffffffffffffffff" + * this implements a 64 bit key. + * + * reference keys are compressed binary representations + * of the same values. + * + * function pblRKey2MainKey converts from the binary reference key + * to the unsigned string main key representing the same 64 bit value + * + * function pblMainKey2RKey converts from the unsigned string + * representation to the compressed representation + * + * reference keys are used as data for index records of index + * keyfiles for non duplicate keys + * and as key postfixes for index records of index + * keyfiles for keys allowing duplicates + * + * they provide the reference from the index records back + * to the main file records containing the data + */ +static int pblRKey2MainKey( +unsigned char * rkey, +int rkeylen, +unsigned char * okey +) +{ + unsigned long keyhigh = 0; + unsigned long keylow = 0; + int hkeylen = 0; + int lkeylen = 0; + int len; + + /* + * at least two bytes are needed, one for the length and one for + * the value of lowkey + */ + if( rkeylen < 2 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read the length of the compressed data from the end of the rkey + */ + lkeylen = 0xff & rkey[ rkeylen - 1 ]; + + /* + * the upper halfbyte of the length stores the length of the highkey + */ + hkeylen = lkeylen >> 4; + + /* + * the lower halfbyte of the length stores the length of the lowkey + */ + lkeylen &= 0x0f; + + /* + * the length of a the low key variable string must be between 1 and 5 + */ + if( lkeylen < 1 || lkeylen > 5 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * additional to the length byte, lkeylen bytes are needed + */ + if( rkeylen < 1 + lkeylen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read the value of the low key from the end of the key + */ + len = pbl_VarBufToLong( rkey + rkeylen - ( lkeylen + 1 ), &keylow ); + if( len != lkeylen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * if there is no high key, just return the low key as a string + */ + if( hkeylen < 1 ) + { + if( okey ) + { + snprintf( okey, PBLKEYLENGTH, "%08lx", keylow ); + } + + /* + * return the number of bytes of the rkey parsed + */ + return( lkeylen + 1 ); + } + + /* + * the length of a the high key variable string cannot be greater than 5 + */ + if( hkeylen > 5 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * additional to the length byte, lkeylen + hkeylen bytes are needed + */ + if( rkeylen < 1 + lkeylen + hkeylen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read the value of the high key from the end of the key + */ + len = pbl_VarBufToLong( rkey + rkeylen - (hkeylen + lkeylen + 1), &keyhigh); + if( len != lkeylen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * keyhigh must have a positive value, otherwise it would not have been + * stored at all + */ + if( !keyhigh ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * return highkey and lowkey as one string + */ + if( okey ) + { + snprintf( okey, PBLKEYLENGTH, "g%08lx%08lx", keyhigh, keylow ); + } + + /* + * return the number of bytes of the rkey parsed + */ + return( hkeylen + lkeylen + 1 ); +} + +static int pblLongs2RKey( +unsigned long keylow, +unsigned long keyhigh, +unsigned char * rkey +) +{ + int hkeylen = 0; + int lkeylen = 0; + int len; + + if( keyhigh ) + { + /* + * only store the higher four byte value if it is not 0 + */ + hkeylen = pbl_LongToVarBuf( rkey, keyhigh ); + } + + /* + * store the low 4 bytes + */ + lkeylen = pbl_LongToVarBuf( rkey + hkeylen, keylow ); + + /* + * store the length of both 4 bytes values in one byte at the end + * the upper halfbyte of the length stores the length of the highkey + * the lower halfbyte of the length stores the length of the lowkey + */ + len = ( hkeylen << 4 ) | lkeylen; + rkey[ hkeylen + lkeylen ] = 0xff & len; + + /* + * return the bytes used for the rkey + */ + return( hkeylen + lkeylen + 1 ); +} + + +static int pblMainKey2RKey( +unsigned char * okey, +int okeylen, +unsigned char * rkey +) +{ + unsigned long keylow; + unsigned long keyhigh; + int len; + + if( okeylen > PBLKEYLENGTH - 1 ) + { + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + /* + * copy the input key, because the parsing destroys it + */ + memcpy( rkey, okey, okeylen ); + if( *rkey == 'g' ) + { + rkey[ 17 ] = 0; + keylow = strtoul( rkey + 9, 0, 16 ); + rkey[ 9 ] = 0; + keyhigh = strtoul( rkey + 1, 0, 16 ); + } + else + { + rkey[ 8 ] = 0; + keylow = strtoul( rkey, 0, 16 ); + keyhigh = 0; + } + + /* + * store both long values as variable length byte buffers + */ + len = pblLongs2RKey( keylow, keyhigh, rkey ); + + return( len ); +} + +/* + * return the length a duplicate index key without the + * reference postfix + */ +static int pblIsamDupKeyLen( char * fkey, int fkeylen ) +{ + int len; + + /* + * parse the reference from the end of the key + * this calculates the length of the reference needed below + */ + len = pblRKey2MainKey( fkey, fkeylen, NULL ); + if( len < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + return( fkeylen - len ); +} + +/* + * compare two duplicate keys + */ +static int pblIsamDupKeyCompare( +void * left, /** first buffer for compare */ +size_t llen, /** length of that buffer */ +void * right, /** second buffer for compare */ +size_t rlen /** length of that buffer */ +) +{ + int rc; + + char lkey[ PBLKEYLENGTH ]; + char rkey[ PBLKEYLENGTH ]; + + size_t leftlen; + size_t rightlen; + + /* + * a buffer with a length 0 is logically smaller than any other buffer + */ + if( !llen ) + { + if( !rlen ) + { + return( 0 ); + } + return( -1 ); + } + if( !rlen ) + { + return( 1 ); + } + + leftlen = pblRKey2MainKey( left, llen, lkey ); + rightlen = pblRKey2MainKey( right, rlen, rkey ); + + if( leftlen < 1 || rightlen < 1 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( leftlen >= llen || rightlen >= rlen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( pblkeycompare ) + { + /* + * use the default key compare function + */ + rc = (*pblkeycompare)( left, llen - leftlen, + right, rlen - rightlen ); + } + else + { + /* + * use the default key compare function + */ + rc = pbl_memcmp( left, llen - leftlen, + right, rlen - rightlen ); + } + + if( !rc ) + { + rc = strcmp( lkey, rkey ); + } + + return( rc ); +} + +/* +------------------------------------------------------------------------------ + FUNCTION: pblIsamStartTransOnFile + + DESCRIPTION: start a transaction on a single ISAM file + + RESTRICTIONS: transactions can be nested + + RETURNS: int rc == 0: the transaction was started successfully + int rc > 0: the transaction was started + but another transaction has resulted in + a rollback request on the file already +------------------------------------------------------------------------------ +*/ +static int pblIsamStartTransOnFile( PBLISAMFILE_t * isam ) +{ + int n; + + /* + * if there is no transaction active for the file + */ + if( isam->transactions < 1 ) + { + isam->transactions = 1; + isam->rollback = 0; + } + else + { + isam->transactions++; + } + + /* + * start a transaction on the main file + */ + if( pblKfStartTransaction( isam->mainfile ) > 0 ) + { + isam->rollback = 1; + } + + /* + * start transactions for all keyfiles + */ + for( n = 0; n < isam->nkeys; n++ ) + { + if( pblKfStartTransaction( isam->keyfiles[ n ] ) > 0 ) + { + isam->rollback = 1; + } + } + + return( isam->rollback ); +} + + +/** + * start a transaction on a set of ISAM files + * + * transactions can be nested + * + * @return int rc == 0: the transaction was started successfully + * @return int rc > 0: the transaction was started + * but another transaction has resulted in + * a rollback request on the file already + */ + +int pblIsamStartTransaction( +int nfiles, /** number of files in ISAM file list */ +pblIsamFile_t ** isamfiles /** ISAM file list to start transaction on */ +) +{ + PBLISAMFILE_t ** files = ( PBLISAMFILE_t ** ) isamfiles; + int n; + int rollback = 0; + + for( n = 0; n < nfiles; n++ ) + { + if( pblIsamStartTransOnFile( files[ n ] ) > 0 ) + { + rollback = 1; + } + } + + return( rollback ); +} + + + +/* +------------------------------------------------------------------------------ + FUNCTION: pblIsamCommitFile + + DESCRIPTION: commit or rollback changes done during a transaction + on a single ISAM file + + RESTRICTIONS: transactions can be nested, if so the commit + only happens when the outermost transaction + calls a commit. + + the commit only happens to process space buffer cache, + call pblIsamFlush() after pblIsamCommitFile() if you want to + flush to kernel space buffer cache. + + RETURNS: int rc == 0: the commit went ok + int rc > 0: a rollback happened, + either because the caller requested it + or because an inner transaction + resulted in a rollback + int rc < 0: an error see pbl_errno +------------------------------------------------------------------------------ +*/ +static int pblIsamCommitFile( PBLISAMFILE_t * isam, int rollback ) +{ + int n; + + /* + * remember if this is a rollback + */ + if( rollback ) + { + isam->rollback = 1; + } + else + { + /* + * find out if any of the keyfiles needs a rollback + * do this by starting another transaction on the ISAM file + * if any of the index files have a rollback isam->rollback is set! + */ + pblIsamStartTransOnFile( isam ); + + /* + * commit the main file transaction started above + */ + pblKfCommit( isam->mainfile, isam->rollback ); + } + + /* + * commit the outer transaction on the main file + */ + pblKfCommit( isam->mainfile, isam->rollback ); + + /* + * do the rollback or commit on all key files + */ + for( n = 0; n < isam->nkeys; n++ ) + { + if( !rollback ) + { + /* + * commit the transaction started above + */ + pblKfCommit( isam->keyfiles[ n ], isam->rollback ); + } + + /* + * commit the outer transaction + */ + pblKfCommit( isam->keyfiles[ n ], isam->rollback ); + } + + if( !rollback ) + { + /* + * count the transaction started above + */ + isam->transactions -= 1; + } + + /* + * we have one transaction less on the ISAM file + */ + isam->transactions -= 1; + + return( isam->rollback ); +} + +/** + * commit or rollback changes done during a transaction + * + * transactions can be nested, if so the commit + * only happens when the outermost transaction + * calls a commit. + * + * the commit only happens to process space buffer cache, + * call \Ref{pblIsamFlush}() after \Ref{pblIsamCommit}() if you want to + * flush to kernel space buffer cache. + * + * @return int rc == 0: the commit went ok + * @return int rc > 0: a rollback happened, either because the caller + * requested it or because an inner transaction resulted + * in a rollback + * @return int rc < 0: some error, see pbl_errno + */ + +int pblIsamCommit( +int nfiles, /** number of files in ISAM file list */ +pblIsamFile_t ** isamfiles, /** ISAM file list to commit changes of */ +int rollback /** != 0: roll back the changes, == 0: commit the changes */ +) +{ + PBLISAMFILE_t ** files = ( PBLISAMFILE_t ** ) isamfiles; + + int n; + int dorollback = rollback; + + if( !rollback ) + { + /* + * find out if any of the files needs a rollback + * do this by starting another transaction on the file set + * if any of the ISAM files have a rollback dorollback is set! + */ + if( pblIsamStartTransaction( nfiles, isamfiles ) > 0 ) + { + dorollback = 1; + } + } + + /* + * commit or rollback all files in the set + */ + for( n = 0; n < nfiles; n++ ) + { + if( !rollback ) + { + /* + * commit the transaction done above + */ + pblIsamCommitFile( files[ n ], dorollback ); + } + + /* + * commit the outer transaction + */ + pblIsamCommitFile( files[ n ], dorollback ); + } + + return( dorollback ); +} + +/** + * open an ISAM file, creates the file if necessary + * + * if update is 0, the ISAM file is opened for read access only, + * if update is not 0 the ISAM file is opened for reading and writing + * + * a file set tag can be attached to the ISAM file, + * if a file having a non NULL file set tag is flushed + * to disk all files having the same file set tag attached + * are flushed as well. + * + * @return pblIsamFile_t * retptr == NULL: an error occured, see pbl_errno + * @return pblIsamFile_t * retptr != NULL: a pointer to an ISAM file descriptor + */ + +pblIsamFile_t * pblIsamOpen( +char * path, /** path of file to create */ +int update, /** flag: should file be opened for update? */ +void * filesettag, /** filesettag, for flushing multiple files consistently */ +int nkeys, /** number of key files to create */ +char **keyfilenames, /** list of names of key index files to create */ +int * keydup /** flaglist: is the i'th index key a duplicate key? */ +) +{ + char * ptr; + char * keyfile; + + PBLISAMFILE_t * isam; + int i; + + /* + * create the descriptor + */ + isam = pbl_malloc0( "pblIsamOpen ISAMFILE", sizeof( PBLISAMFILE_t )); + if( !isam ) + { + return( 0 ); + } + + /* + * if the user did not specify an external file set tag + * the isam file descriptor is used in order to make sure + * all key files of the isam file are flushed at the same time + */ + if( update && !filesettag ) + { + filesettag = isam; + } + + isam->nkeys = nkeys; + if( isam->nkeys ) + { + /* + * create space for pointers to key file descriptors + */ + isam->keyfiles = pbl_malloc0( "pblIsamOpen keyfiles", + nkeys * sizeof( pblKeyFile_t * )); + if( !isam->keyfiles ) + { + PBL_FREE( isam ); + return( 0 ); + } + + /* + * save the duplicate key flags for all keys + */ + isam->keydup = pbl_memdup( "pblIsamOpen keydup", + keydup, nkeys * sizeof( int * )); + if( !isam->keydup ) + { + PBL_FREE( isam->keyfiles ); + PBL_FREE( isam ); + pbl_errno = PBL_ERROR_OUT_OF_MEMORY; + return( 0 ); + } + + /* + * create the array of keycompare functions for all keys + */ + isam->keycompare = pbl_malloc0( "pblIsamOpen keycompare", + nkeys * sizeof( void * )); + if( !isam->keycompare ) + { + PBL_FREE( isam->keydup ); + PBL_FREE( isam->keyfiles ); + PBL_FREE( isam ); + pbl_errno = PBL_ERROR_OUT_OF_MEMORY; + return( 0 ); + } + } + + /* + * open the main file + */ + if( update ) + { + /* + * try to create + */ + isam->mainfile = pblKfCreate( path, filesettag ); + } + + if( !isam->mainfile ) + { + /* + * try to open + */ + isam->mainfile = pblKfOpen( path, update, filesettag ); + + /* + * if the main file is not open + */ + if( !isam->mainfile ) + { + PBL_FREE( isam->keycompare ); + PBL_FREE( isam->keydup ); + PBL_FREE( isam->keyfiles ); + PBL_FREE( isam ); + return( 0 ); + } + } + + /* + * if the name of the main file has a directory part + * and the names of the index files do not + * we prepend the directory part of the main file to + * the names of the index files + * + * get a pointer to last / or \ in path + */ + ptr = strrchr( path, '/' ); + keyfile = strrchr( path, '\\' ); + + if( ptr ) + { + if( keyfile > ptr ) + { + ptr = keyfile; + } + } + else + { + ptr = keyfile; + } + if( ptr ) + { + /* + * set pointer to the character after the slash + */ + ptr++; + } + + /* + * open all key files + */ + for( i = 0; i < nkeys; i++ ) + { + /* + * if the path contains a directory part + * and the name of the keyfile does not + */ + if( ptr + && !strchr( keyfilenames[ i ], '/' ) + && !strchr( keyfilenames[ i ], '\\' )) + { + /* + * build the the path to the keyfile + */ + keyfile = pbl_mem2dup( "pblIsamOpen keyfile", + path, ptr - path, + keyfilenames[ i ], + strlen( keyfilenames[ i ] ) + 1 ); + } + else + { + /* + * use keyfile name as given + */ + keyfile = strdup( keyfilenames[ i ] ); + } + + if( !keyfile ) + { + pblKfClose( isam->mainfile ); + PBL_FREE( isam->keycompare ); + PBL_FREE( isam->keydup ); + PBL_FREE( isam->keyfiles ); + PBL_FREE( isam ); + pbl_errno = PBL_ERROR_OUT_OF_MEMORY; + return( 0 ); + } + + if( update ) + { + /* + * try create + */ + isam->keyfiles[ i ] = pblKfCreate( keyfile, filesettag ); + } + + if( !isam->keyfiles[ i ] ) + { + /* + * try open + */ + isam->keyfiles[ i ] = pblKfOpen( keyfile, update, filesettag ); + } + + if( !isam->keyfiles[ i ] ) + { + int j; + + for( j = 0; j < i; j++ ) + { + pblKfClose( isam->keyfiles[ j ] ); + } + + pblKfClose( isam->mainfile ); + PBL_FREE( keyfile ); + PBL_FREE( isam->keycompare ); + PBL_FREE( isam->keydup ); + PBL_FREE( isam->keyfiles ); + PBL_FREE( isam ); + return( 0 ); + } + + /* + * set our custom compare function for keyfiles allowing + * duplicate keys + */ + if( isam->keydup[ i ] ) + { + pblKfSetCompareFunction( isam->keyfiles[ i ], pblIsamDupKeyCompare); + } + + /* + * the key file is open, we don't need its name anymore + */ + PBL_FREE( keyfile ); + } + + isam->magic = rcsid; + return( ( pblIsamFile_t * )isam ); +} + +/** + * close an ISAM file + * + * all changes are flushed to disk before, + * all memory allocated for the file is released. + * + * @return int rc == 0: call went ok, file is closed + * @return int rc != 0: some error, see pbl_errno + */ + +int pblIsamClose( +pblIsamFile_t * isamfile /** ISAM file to close */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + int rc = 0; + int i; + int saveerrno = 0; + + /* + * close all the keyfiles + */ + for( i = 0; i < isam->nkeys; i++ ) + { + if( pblKfClose( isam->keyfiles[ i ] )) + { + saveerrno = pbl_errno; + rc = -1; + } + } + + /* + * close the main file + */ + if( pblKfClose( isam->mainfile )) + { + saveerrno = pbl_errno; + rc = -1; + } + + PBL_FREE( isam->keycompare ); + PBL_FREE( isam->keydup ); + PBL_FREE( isam->keyfiles ); + PBL_FREE( isam ); + + if( rc ) + { + pbl_errno = saveerrno; + } + + return( rc ); +} + +/** + * flush an ISAM file + * + * all changes are flushed to disk, + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error, see pbl_errno + */ + +int pblIsamFlush( +pblIsamFile_t * isamfile /** ISAM file to flush */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + int rc = 0; + int i; + int saveerrno = 0; + + /* + * flush all the keyfiles + */ + for( i = 0; i < isam->nkeys; i++ ) + { + if( pblKfFlush( isam->keyfiles[ i ] )) + { + saveerrno = pbl_errno; + rc = -1; + } + } + + /* + * flush the main file + */ + if( pblKfFlush( isam->mainfile )) + { + saveerrno = pbl_errno; + rc = -1; + } + + if( rc ) + { + pbl_errno = saveerrno; + } + + return( rc ); +} + +/* + * set the current record of the main file + * used after deletes of records in the main file + */ +static int pblIsamSetCurrentRecord( PBLISAMFILE_t * isam ) +{ + long datalen; + char okey[ PBLKEYLENGTH ]; + int okeylen; + int saveerrno = pbl_errno; + + /* + * read the key of the current record in the main file + */ + datalen = pblKfThis( isam->mainfile, okey, &okeylen ); + if( datalen >= 0 ) + { + if( okeylen == 9 ) + { + okeylen = 8; + } + else if( okeylen == 18 ) + { + okeylen = 17; + } + okey[ okeylen ] = 0; + + /* + * position the current record of the main file to the allkeys record + */ + datalen = pblKfFind( isam->mainfile, PBLFI, okey, okeylen, 0, 0 ); + if( datalen < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + } + + pbl_errno = saveerrno; + return( 0 ); +} + +/** + * insert a new record with the given keys and data into the isam file, + * + * the current record of the file will be set to the new record + * + *

+ * RESTRICTIONS: + *
- the file must be open for update, + *
- allkeys must point to the keys to be inserted, + *
- allkeyslen must be bigger than 0 and smaller than 1024, + *
- data must point to the data be inserted, + *
- datalen must not be negative, + *
- if datalen == 0, the pointer data is not evaluated at all + * + * Parameter allkeys must contain all values for all keys + * of the record. The values have to be prepended by one byte giving + * the length of the following value. All values have to be concatenated + * into one string. + * + * Example: + *

 4isam4file3key 
+ * with the numbers as binary values and the letters ascii, + * specifies three keys with the values "isam", "file" and "key". + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error occured, see pbl_errno + */ + +int pblIsamInsert( +pblIsamFile_t * isamfile, /** ISAM file to insert to */ +unsigned char * allkeys, /** pointers to all keys to insert */ +int allkeyslen, /** total length of all keys to insert */ +unsigned char * data, /** data to insert */ +long datalen /** length of the data */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + unsigned long lastkeyhigh = 0; + unsigned long lastkeylow = 0; + char rkey[ PBLKEYLENGTH ]; + int rkeylen; + char okey[ PBLKEYLENGTH ]; + int okeylen; + int ndatarecords = 0; + int n = 0; + int rc; + unsigned char * ldata; + long ldatalen; + unsigned char * key; + int keylen; + + /* + * start a transaction + */ + pblIsamStartTransaction( 1, &isamfile ); + + /* + * the sum of the length of all keys + * cannot be longer than a single data record + */ + if( allkeyslen > PBLDATALENGTH ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + /* + * find out the last key used in the main file + */ + if( pblKfLast( isam->mainfile, okey, &okeylen ) < 0 ) + { + if( pbl_errno != PBL_ERROR_NOT_FOUND ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * 00000000 is the smallest key we use in the main file + */ + strcpy( okey, "00000000" ); + okeylen = 8; + } + + /* + * generate the next key, a 64 bit logic is used in order to make + * sure we never run out of new keys + */ + if( *okey == 'g' ) + { + /* + * values over unsigned 0xffffffff are represented + * as 17 byte strings with a preceding "g" + */ + okey[ 17 ] = 0; + lastkeylow = strtoul( okey + 9, 0, 16 ); + okey[ 9 ] = 0; + lastkeyhigh = strtoul( okey + 1, 0, 16 ); + } + else + { + /* + * values below unsigned 0xffffffff are represented + * as 8 byte strings we no prefix + */ + okey[ 8 ] = 0; + lastkeylow = strtoul( okey, 0, 16 ); + } + + if( lastkeylow == 0xffffffff ) + { + /* + * 32 bit overflow + */ + lastkeylow = 0; + lastkeyhigh += 1; + } + else + { + lastkeylow += 1; + } + + if( lastkeyhigh ) + { + snprintf( okey, PBLKEYLENGTH, "g%08lx%08lx", lastkeyhigh, lastkeylow ); + } + else + { + snprintf( okey, PBLKEYLENGTH, "%08lx", lastkeylow ); + } + okeylen = strlen( okey ); + + /* + * create the reference key used as link to the main file + */ + rkeylen = pblMainKey2RKey( okey, okeylen, rkey ); + if( rkeylen < 1 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * insert all the keys into the key files + */ + for( key = allkeys, n = 0; n < isam->nkeys; n++ ) + { + keylen = 0xff & *key++; + if( keylen < 1 ) + { + /* + * non duplicate keys cannot be empty + */ + if( !isam->keydup[ n ] ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = PBL_ERROR_PARAM_KEY; + return( -1 ); + } + } + + /* + * check the sanity of the allkeys record given + */ + if( key + keylen > allkeys + allkeyslen ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = PBL_ERROR_PARAM_KEY; + return( -1 ); + } + + /* + * if the key is allowing duplicates + */ + if( isam->keydup[ n ] ) + { + unsigned char ikey[ PBLKEYLENGTH ]; + + /* + * create a unique key for the insert + */ + if( keylen + rkeylen > PBLKEYLENGTH ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + /* + * concatenate the key and the reference key + * the reference key is used as postfix of the index key + */ + if( keylen ) + { + memcpy( ikey, key, keylen ); + } + memcpy( ikey + keylen, rkey, rkeylen ); + + /* + * make sure any user defined key compare function gets used + */ + pblkeycompare = isam->keycompare[ n ]; + + /* + * search for the key in the file + */ + if( pblKfFind( isam->keyfiles[ n ], + PBLEQ, ikey, keylen + rkeylen, 0, 0 ) >= 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = PBL_ERROR_EXISTS; + return( -1 ); + } + + /* + * insert the key to the file + */ + if( pblKfInsert( isam->keyfiles[ n ], + ikey, keylen + rkeylen, 0, 0 )) + { + int saveerrno = pbl_errno; + + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = saveerrno; + return( -1 ); + } + } + else + { + /* + * search for the key in the file + */ + if( pblKfFind( isam->keyfiles[ n ], + PBLEQ, key, keylen, 0, 0 ) >= 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = PBL_ERROR_EXISTS; + return( -1 ); + } + + /* + * insert the key to the file + * the reference key is the data of the record in the index + */ + if( pblKfInsert( isam->keyfiles[ n ], + key, keylen, rkey, rkeylen )) + { + int saveerrno = pbl_errno; + + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = saveerrno; + return( -1 ); + } + } + + /* + * move the key along the record + */ + key += keylen; + } + + /* + * insert the data records into the main file + */ + for( ldata = data, ndatarecords = 0; ; ndatarecords++ ) + { + ldatalen = datalen - ndatarecords * PBLDATALENGTH; + if( ldatalen < 0 ) + { + break; + } + + if( ldatalen > PBLDATALENGTH ) + { + ldatalen = PBLDATALENGTH; + } + + /* + * the data records in the main file use a 9/18 byte + * version of the main key string, including the trailing \0 + * we use the trailing \0 of the main key in order to differentiate + * between the allkeys record and the data records + */ + if( pblKfInsert( isam->mainfile, okey, okeylen + 1, ldata, ldatalen )) + { + int saveerrno = pbl_errno; + + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = saveerrno; + return( -1 ); + } + + if( ldatalen < PBLDATALENGTH ) + { + break; + } + + ldata += ldatalen; + } + + /* + * insert the record for the keys into the main file + * the "allkeys" record in the main file uses the 8/17 byte main key + */ + rc = pblKfInsert( isam->mainfile, okey, okeylen, allkeys, allkeyslen ); + if( rc ) + { + int saveerrno = pbl_errno; + + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = saveerrno; + return( -1 ); + } + + /* + * commit all changes + */ + if( pblIsamCommit( 1, &isamfile, 0 )) + { + return( -1 ); + } + + return( 0 ); +} + +/** + * delete the current record of the ISAM file. + * + * the current record of the file is set to the next record or + * if the last record is deleted, to the previous record, + * + * if there are no more records in the file after the delete + * the current record is of course unpositioned + * + *

+ * RESTRICTIONS: + *
- the file must be open for update, + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error occured, see pbl_errno + */ + +int pblIsamDelete( +pblIsamFile_t * isamfile /** ISAM file to delete from */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + char okey[ PBLKEYLENGTH ]; + int okeylen; + char rkey[ PBLKEYLENGTH ]; + int rkeylen = -1; + unsigned char * key; + int keylen; + unsigned char data[ PBLDATALENGTH ]; + long datalen; + long rc; + int n; + int retval = 0; + + /* + * start a transaction + */ + pblIsamStartTransaction( 1, &isamfile ); + + /* + * read the key of the current record in the main file + */ + datalen = pblKfThis( isam->mainfile, okey, &okeylen ); + if( datalen < 0 ) + { + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( okeylen != 8 && okeylen != 17 ) + { + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_POSITION; + return( -1 ); + } + okey[ okeylen ] = 0; + + /* + * the allkeys record can not be longer than a single data record + */ + if( datalen > PBLDATALENGTH ) + { + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read all the keys + */ + rc = pblKfRead( isam->mainfile, data, datalen ); + if( rc < 0 ) + { + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + else if( rc != datalen ) + { + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * delete all the keys from the key files + */ + for( key = data, n = 0; n < isam->nkeys; n++ ) + { + keylen = 0xff & *key++; + + /* + * check the sanity of the allkeys record given + */ + if( key + keylen > data + datalen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + continue; + } + + /* + * if the key is allowing duplicates + */ + if( isam->keydup[ n ] ) + { + unsigned char ikey[ PBLKEYLENGTH ]; + + /* + * a non unique key is deleted, we need the reference key + */ + if( rkeylen < 0 ) + { + rkeylen = pblMainKey2RKey( okey, okeylen, rkey ); + } + if( rkeylen < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + continue; + } + + /* + * the key in the index record has the reference key + * as a postfix appended to it + * + * create a unique key for the delete + */ + if( keylen + rkeylen > PBLKEYLENGTH ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + continue; + } + + /* + * concatenate the key and the reference + */ + memcpy( ikey, key, keylen ); + memcpy( ikey + keylen, rkey, rkeylen ); + + /* + * make sure any user defined key compare function gets used + */ + pblkeycompare = isam->keycompare[ n ]; + + /* + * delete the key from the file + */ + if( pblKfFind( isam->keyfiles[ n ], + PBLEQ, ikey, keylen + rkeylen, 0, 0 ) < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + continue; + } + + if( pblKfDelete( isam->keyfiles[ n ] )) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + continue; + } + } + else + { + /* + * directly use the key as stored in the allkeys record + * of the main file + * + * delete the key from the index file + */ + if( pblKfFind( isam->keyfiles[ n ], + PBLEQ, key, keylen, 0, 0 ) < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + continue; + } + + if( pblKfDelete( isam->keyfiles[ n ] )) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + continue; + } + } + + /* + * move the key along the keys + */ + key += keylen; + } + + /* + * delete all records from the main file + * this deletes the "allkeys" record having a keylength of 8/17 bytes + */ + while( pblKfFind( isam->mainfile, PBLEQ, okey, okeylen, 0, 0 ) >= 0 ) + { + if( pblKfDelete( isam->mainfile )) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + } + } + + /* + * this deletes the data records having a keylength of 9/18 bytes + */ + while( pblKfFind( isam->mainfile, PBLEQ, okey, okeylen + 1, 0, 0 ) >= 0 ) + { + if( pblKfDelete( isam->mainfile )) + { + pbl_errno = PBL_ERROR_BAD_FILE; + retval = -1; + } + } + + /* + * position the current record of the main file to the + * allkeys record of another entry of the main file + */ + pblIsamSetCurrentRecord( isam ); + + if( retval < 0 ) + { + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + if( pblIsamCommit( 1, &isamfile, 0 )) + { + return( -1 ); + } + return( retval ); +} + +/* + * get the main key from a given index key + * + * for non duplicate index keys this assumes + * that the index keyfile is positioned + * on the record who's key is given as skey + * + * for index keys allowing duplicates this assumes + * that the skey given is the "long" version, + * with the reference key postfix attached. + * + * the current record of the main file is + * positioned on the allkeys record having the key + */ +static int pblIsamGetMainKey( +PBLISAMFILE_t * isam, +int index, +unsigned char * skey, +int skeylen, +unsigned char * okey +) +{ + long rc; + char key[ PBLKEYLENGTH ]; + int keylen; + long datalen; + + /* + * make sure the index is in bounds + */ + if( index >= isam->nkeys ) + { + pbl_errno = PBL_ERROR_PARAM_INDEX; + return( -1 ); + } + + /* + * if the key has duplicates + */ + if( isam->keydup[ index ] ) + { + /* + * the main key is a postfix of the referece key + * read the key from there and convert it to an unsigned string + */ + keylen = pblRKey2MainKey( skey, skeylen, okey ); + if( keylen < 0 ) + { + return( -1 ); + } + } + else + { + /* + * read the reference, this assumes that the record is positioned! + */ + rc = pblKfRead( isam->keyfiles[ index ], key, sizeof( key ) ); + if( rc < 0 ) + { + return( -1 ); + } + keylen = rc; + + /* + * get the key used in the main file + */ + if( pblRKey2MainKey( key, keylen, okey ) < 0 ) + { + return( -1 ); + } + } + + /* + * get the length of the key + */ + keylen = strlen( okey ); + + /* + * position the current record of the main file to the allkeys record + */ + datalen = pblKfFind( isam->mainfile, PBLFI, okey, keylen, 0, 0 ); + if( datalen < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + return( keylen ); +} + + +/* + * find for index keys with possible duplicates + * + * writes the index key found with the reference postfix attached + * to the supplied buffer rkey + * + * returns the length of that key excluding the reference postfix + * + * sets the length of that key including the reference postfix to rkeylen + */ +static int pblIsamFindDupKey( +PBLISAMFILE_t * isam, +int which, +int index, +unsigned char * skey, +int skeylen, +unsigned char * rkey, +int * rkeylen +) +{ + long datalen; + char fkey[ PBLKEYLENGTH ]; + int fkeylen = 0; + char ikey[ PBLKEYLENGTH ]; + int ikeylen = 0; + int keylen; + int lwhich = PBLLT; + + /* + * the search key needs to leave space for the reference + */ + if( skeylen > PBLKEYLENGTH - 2 ) + { + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + switch( which ) + { + case PBLLT: + /* + * create a reference key smaller than all real ones + */ + fkeylen = pblLongs2RKey( 0, 0, fkey ); + + /* + * search for key lower than the one created + */ + lwhich = PBLLT; + break; + + case PBLLE: + /* + * the lower equal case is treated as FIRST or LOWER THAN + */ + fkeylen = pblIsamFindDupKey( isam, PBLFI, index, + skey, skeylen, rkey, rkeylen ); + if( fkeylen > 0 ) + { + return( fkeylen ); + } + + fkeylen = pblIsamFindDupKey( isam, PBLLT, index, skey, skeylen, rkey, rkeylen ); + return( fkeylen ); + break; + + case PBLFI: + case PBLEQ: + /* + * create a reference key smaller than all real ones + */ + fkeylen = pblLongs2RKey( 0, 0, fkey ); + + /* + * search for key greater than the one created + */ + lwhich = PBLGT; + break; + + case PBLLA: + /* + * create a reference key bigger than all real ones + */ + fkeylen = pblLongs2RKey( 0xffffffff, 0xffffffff, fkey ); + + /* + * search for a key lower than the one created + */ + lwhich = PBLLT; + break; + + case PBLGE: + /* + * the lower equal case is treated as LAST or GREATER THAN + */ + fkeylen = pblIsamFindDupKey( isam, PBLLA, index, + skey, skeylen, rkey, rkeylen ); + if( fkeylen > 0 ) + { + return( fkeylen ); + } + + fkeylen = pblIsamFindDupKey( isam, PBLGT, index, skey, skeylen, rkey, rkeylen ); + return( fkeylen ); + break; + + default: /* PBLGT */ + /* + * create a reference key bigger than all real ones + */ + fkeylen = pblLongs2RKey( 0xffffffff, 0xffffffff, fkey ); + + /* + * search for a key greater than the one created + */ + lwhich = PBLGT; + break; + } + + /* + * create the key for the search + */ + if( fkeylen + skeylen >= PBLKEYLENGTH ) + { + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + /* + * concatenate the key and the reference key + * the reference key is used as postfix of the index key + */ + if( skeylen ) + { + memcpy( ikey, skey, skeylen ); + } + memcpy( ikey + skeylen, fkey, fkeylen ); + ikeylen = skeylen + fkeylen; + + /* + * find the record in the key file + */ + datalen = pblKfFind( isam->keyfiles[ index ], lwhich, + ikey, ikeylen, fkey, &fkeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + + /* + * calculate the length of the key without the reference + */ + keylen = pblIsamDupKeyLen( fkey, fkeylen ); + if( keylen < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * in the FIRST, EQUAL and the LAST case the key has to match + */ + if( which == PBLFI || which == PBLEQ || which == PBLLA ) + { + /* + * see whether the key matches the searchkey + */ + if( skeylen != keylen || memcmp( skey, fkey, skeylen )) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + return( -1 ); + } + } + + /* + * save the key including the reference as return value + */ + memcpy( rkey, fkey, fkeylen ); + *rkeylen = fkeylen; + + return( keylen ); +} + + +/** + * find a record in an ISAM file, set the current record + * + * parameter which specifies which record to find relative + * to the search key specified by skey and skeylen. + * the following values for which are possible + * + *
PBLEQ - find a record whose key is equal to skey + *
PBLFI - find the first record that is equal + *
PBLLA - find the last record that is equal + *
PBLGE - find the last record that is equal or the smallest + * record that is greater + *
PBLGT - find the smallest record that is greater + *
PBLLE - find the first record that is equal or the biggest + * record that is smaller + *
PBLLT - find the biggest record that is smaller + * + * parameter index specifies which of the keys to use + * + *

+ * RESTRICTIONS: + *
- the out parameter okey must point to a memory area that is + * big enough to hold any possible key, i.e 255 bytes + * + * @return int rc >= 0: + *

    + *
  • call went ok, + * the value returned is the length + * of the key of the record found, + *
  • the key of the record is copied to okey, + *
  • the current record of the file is set to the + * record found + *
+ * + * @return int rc < 0: + *
    + *
  • some error occured, see pbl_errno + * especially PBL_ERROR_NOT_FOUND, if there is no + * matching record + *
+ */ + +int pblIsamFind( +pblIsamFile_t * isamfile, /** ISAM file to search in */ +int which, /** mode to use for search */ +int index, /** index of key to use for search */ +unsigned char * skey, /** key to use for search */ +int skeylen, /** length of search key */ +unsigned char * okey /** buffer for result key */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + long datalen; + char key[ PBLKEYLENGTH ]; + int keylen; + int okeylen; + + /* + * make sure the index is in bounds + */ + if( index >= isam->nkeys ) + { + pbl_errno = PBL_ERROR_PARAM_INDEX; + return( -1 ); + } + + /* + * if the key has duplicates + */ + if( isam->keydup[ index ] ) + { + /* + * make sure any user defined key compare function gets used + */ + pblkeycompare = isam->keycompare[ index ]; + + /* + * search the duplicate key + */ + keylen = pblIsamFindDupKey( isam, which, index, + skey, skeylen, okey, &okeylen ); + if( keylen < 0 ) + { + return( keylen ); + } + } + else + { + /* + * find the record in the key file + */ + datalen = pblKfFind( isam->keyfiles[ index ], which, + skey, skeylen, okey, &okeylen ); + if( datalen < 0 ) + { + return( datalen ); + } + + if( datalen < 2 || datalen > PBLKEYLENGTH ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * set the return value + */ + keylen = okeylen; + } + + /* + * position current record of the main file on that key + */ + if( pblIsamGetMainKey( isam, index, okey, okeylen, key ) < 1 ) + { + return( -1 ); + } + + if( isam->keydup[ index ] ) + { + okey[ keylen ] = 0; + } + + return( keylen ); +} + +/* + * read a key from the allkeys record of an entry in the main file + * + * if the reference is requested it is appended to the key + */ +static int pblIsamThisKey( +PBLISAMFILE_t * isam, +int index, +int reference, +unsigned char * okey +) +{ + int okeylen = -1; + char rkey[ PBLKEYLENGTH ]; + int rkeylen; + char fkey[ PBLKEYLENGTH ]; + int fkeylen; + unsigned char data[ PBLDATALENGTH ]; + long datalen; + long rc; + unsigned char * key; + int n; + + /* + * make sure the index is in bounds + */ + if( index >= isam->nkeys ) + { + pbl_errno = PBL_ERROR_PARAM_INDEX; + return( -1 ); + } + + /* + * read the key of the current record in the main file + */ + datalen = pblKfThis( isam->mainfile, fkey, &fkeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( fkeylen != 8 && fkeylen != 17 ) + { + pbl_errno = PBL_ERROR_POSITION; + return( -1 ); + } + fkey[ fkeylen ] = 0; + + /* + * the allkeys record can not be longer than a single data record + */ + if( datalen > PBLDATALENGTH ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read all the keys + */ + rc = pblKfRead( isam->mainfile, data, datalen ); + if( rc < 0 ) + { + return( -1 ); + } + else if( rc != datalen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * get the key + */ + for( key = data, n = 0; n <= index; n++ ) + { + okeylen = 0xff & *key++; + + if( key + okeylen > data + datalen ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( n < index ) + { + /* + * move the key along the keys + */ + key += okeylen; + continue; + } + + memcpy( okey, key, okeylen ); + + /* + * if the reference of a duplicate key is requested + */ + if( reference && isam->keydup[ n ] ) + { + /* + * create the reference postfix for the key + */ + rkeylen = pblMainKey2RKey( fkey, fkeylen, rkey ); + if( rkeylen < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * concatenate the key and the reference + */ + if( okeylen + rkeylen > PBLKEYLENGTH ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + memcpy( okey + okeylen, rkey, rkeylen ); + okeylen += rkeylen; + } + } + + return( okeylen ); +} + +/** + * get the key and keylen of a record + * + * parameter which specifies which record to get relative + * to the search key specified by index. + * the following values for which are possible + * + *
PBLTHIS - get key and keylen of current record + *
PBLNEXT - get key and keylen of next record + *
PBLPREV - get key and keylen of previous record + *
PBLFIRST - get key and keylen of first record + *
PBLLAST - get key and keylen of last record + * + * parameter index specifies which of the keys to get, + * the pseudo index value -1 can be used in order to access the file + * sequentially in the order the records were inserted. + * okey is not set in this case, a keylength of 0 is returned in case + * the call went ok. + * + *

+ * RESTRICTIONS: + *
- the out parameter okey must point to a memory area that is + * big enough to hold any possible key, i.e 255 bytes + * + * @return int rc >= 0: + *

    + *
  • call went ok, + * the value returned is the length + * of the key of the record found, + *
  • the key of the record is copied to okey, + *
  • the current record of the file is set to the + * record found + *
+ * + * @return int rc < 0: + *
    + *
  • some error occured, see pbl_errno + *
+ */ + +int pblIsamGet( +pblIsamFile_t * isamfile, /** ISAM file to read in */ +int which, /** mode to use for read */ +int index, /** index of key to use for read */ +unsigned char * okey /** buffer for result key */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + char rkey[ PBLKEYLENGTH ]; + int rkeylen = 0; + int okeylen; + long datalen; + + /* + * make sure the index is in bounds + */ + if(( index != -1 ) && ( index >= isam->nkeys )) + { + pbl_errno = PBL_ERROR_PARAM_INDEX; + return( -1 ); + } + + if( index >= 0 && isam->keydup[ index ] ) + { + /* + * make sure any user defined key compare function gets used + */ + pblkeycompare = isam->keycompare[ index ]; + } + + switch( which ) + { + case PBLNEXT: + if( index == -1 ) + { + /* + * save the current position of the main file + */ + if( pblKfSavePosition( isam->mainfile )) + { + return( -1 ); + } + } + + while( index == -1 ) + { + /* + * read the next entry in the main file + */ + datalen = pblKfNext( isam->mainfile, rkey, &rkeylen ); + if( datalen < 0 ) + { + pblKfRestorePosition( isam->mainfile ); + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( rkeylen != 8 && rkeylen != 17 ) + { + /* + * found a datarecord, continue reading records + */ + continue; + } + + return( 0 ); + } + + /* + * position to next record in the index file + */ + datalen = pblKfNext( isam->keyfiles[ index ], okey, &okeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + break; + + case PBLPREV: + if( index == -1 ) + { + /* + * save the current position of the main file + */ + if( pblKfSavePosition( isam->mainfile )) + { + return( -1 ); + } + } + + while( index == -1 ) + { + /* + * read the previous entry in the main file + */ + datalen = pblKfPrev( isam->mainfile, rkey, &rkeylen ); + if( datalen < 0 ) + { + pblKfRestorePosition( isam->mainfile ); + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( rkeylen != 8 && rkeylen != 17 ) + { + /* + * found a datarecord, continue reading records + */ + continue; + } + + return( 0 ); + } + + /* + * position to previous record in the index file + */ + datalen = pblKfPrev( isam->keyfiles[ index ], okey, &okeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + break; + + case PBLFIRST: + if( index == -1 ) + { + datalen = pblKfFirst( isam->mainfile, 0, 0 ); + if( datalen < 0 ) + { + return( -1 ); + } + return( 0 ); + } + + datalen = pblKfFirst( isam->keyfiles[ index ], okey, &okeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + break; + + case PBLLAST: + if( index == -1 ) + { + datalen = pblKfLast( isam->mainfile, rkey, &rkeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + if( rkeylen == 8 || rkeylen == 17 ) + { + return( 0 ); + } + } + + while( index == -1 ) + { + /* + * read the next entry in the main file + */ + datalen = pblKfPrev( isam->mainfile, rkey, &rkeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( rkeylen != 8 && rkeylen != 17 ) + { + /* + * found a datarecord, continue reading records + */ + continue; + } + + return( 0 ); + } + + datalen = pblKfLast( isam->keyfiles[ index ], okey, &okeylen ); + if( datalen < 0 ) + { + return( -1 ); + } + break; + + case PBLTHIS: + if( index == -1 ) + { + datalen = pblKfThis( isam->mainfile, 0, 0 ); + if( datalen < 0 ) + { + return( -1 ); + } + return( 0 ); + } + + /* + * read the key with the reference + */ + okeylen = pblIsamThisKey( isam, index, 1, okey ); + if( okeylen <= 0 ) + { + return( okeylen ); + } + + /* + * find the record in the key file + * position the current record in the index file + */ + datalen = pblKfFind( isam->keyfiles[ index ], + PBLEQ, okey, okeylen, 0, 0 ); + if( datalen < 0 ) + { + return( -1 ); + } + break; + + default: + pbl_errno = PBL_ERROR_PARAM_MODE; + return( -1 ); + } + + /* + * no need to position the current record of the main file in this case + */ + if( which != PBLTHIS ) + { + /* + * position the current record of the main file + */ + rkeylen = pblIsamGetMainKey( isam, index, okey, okeylen, rkey ); + if( rkeylen < 0 ) + { + return( -1 ); + } + } + + /* + * if the key has duplicates + */ + if( isam->keydup[ index ] ) + { + /* + * calculate the length of the key without the reference postfix + */ + okeylen = pblIsamDupKeyLen( okey, okeylen ); + if( okeylen < 0 ) + { + return( -1 ); + } + + okey[ okeylen ] = 0; + } + + return( okeylen ); +} + +/** + * read the key and keylen of the current record + * + * parameter index specifies which of the keys to read + * + *

+ * RESTRICTIONS: + *
- the out parameter okey must point to a memory area that is + * big enough to hold any possible key, i.e 255 bytes + * + * @return int rc >= 0: + *

    + *
  • call went ok, + * the value returned is the length of the key + *
  • the key of the record is copied to okey, + *
  • the current record of the file is not affected + * by this function + *
+ * @return int rc < 0: + *
    + *
  • some error occured, see pbl_errno + *
+ */ + +int pblIsamReadKey( +pblIsamFile_t * isamfile, /** ISAM file to read in */ +int index, /** index of key read */ +unsigned char * okey /** buffer for result key */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + int okeylen; + + /* + * make sure the index is in bounds + */ + if( index >= isam->nkeys ) + { + pbl_errno = PBL_ERROR_PARAM_INDEX; + return( -1 ); + } + + /* + * read the key without the reference + */ + okeylen = pblIsamThisKey( isam, index, 0, okey ); + + return( okeylen ); +} + +/** + * read the datalen of the current record + * + * @return long rc >= 0: call went ok, the value returned is the length + * of the data of the record, + * @return long rc < 0: some error occured, see pbl_errno + */ + +long pblIsamReadDatalen( +pblIsamFile_t * isamfile /** ISAM file to read length of data from */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + char rkey[ PBLKEYLENGTH ]; + int rkeylen; + char fkey[ PBLKEYLENGTH ]; + int fkeylen; + long datalen = 0; + long rc = 0; + + /* + * read the key of the current record in the main file + */ + rc = pblKfThis( isam->mainfile, fkey, &fkeylen ); + if( rc < 0 ) + { + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( fkeylen != 8 && fkeylen != 17 ) + { + pbl_errno = PBL_ERROR_POSITION; + return( -1 ); + } + fkey[ fkeylen ] = 0; + + /* + * save the current position of the main file + */ + if( pblKfSavePosition( isam->mainfile )) + { + return( -1 ); + } + + /* + * calculate the datalength of the record + */ + for( ;; ) + { + rc = pblKfNext( isam->mainfile, rkey, &rkeylen ); + if( rc < 0 ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + break; + } + datalen = -1; + break; + } + + /* + * if we are now positioned on an entry with a different main key + */ + if(( fkeylen != rkeylen - 1 ) || memcmp( fkey, rkey, fkeylen )) + { + break; + } + + datalen += rc; + } + + /* + * restore the current position of the main file + */ + if( pblKfRestorePosition( isam->mainfile )) + { + return( -1 ); + } + + return( datalen ); +} + +/** + * read the data of the current record + * + * parameter bufferlen specifies how many bytes to read + * + * @return long rc >= 0: call went ok, the value returned is the length + * of the data copied + * @return long rc < 0: some error occured, see pbl_errno + */ + +long pblIsamReadData( +pblIsamFile_t * isamfile, /** ISAM file to read from */ +unsigned char * buffer, /** buffer to read to */ +long bufferlen /** length of that buffer */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + char rkey[ PBLKEYLENGTH ]; + int rkeylen; + char fkey[ PBLKEYLENGTH ]; + int fkeylen; + long dataread = 0; + long rc; + + /* + * read the key of the current record in the main file + */ + rc = pblKfThis( isam->mainfile, fkey, &fkeylen ); + if( rc < 0 ) + { + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( fkeylen != 8 && fkeylen != 17 ) + { + pbl_errno = PBL_ERROR_POSITION; + return( -1 ); + } + fkey[ fkeylen ] = 0; + + /* + * save the current position of the main file + */ + if( pblKfSavePosition( isam->mainfile )) + { + return( -1 ); + } + + /* + * read the data of the record + */ + while( bufferlen > 0 ) + { + rc = pblKfNext( isam->mainfile, rkey, &rkeylen ); + if( rc < 0 ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + break; + } + dataread = -1; + break; + } + + /* + * if we are now positioned on an entry with a different main key + */ + if(( fkeylen != rkeylen - 1 ) || memcmp( fkey, rkey, fkeylen )) + { + break; + } + + if( rc > bufferlen ) + { + rc = bufferlen; + } + + if( rc > 0 ) + { + rc = pblKfRead( isam->mainfile, buffer + dataread, rc ); + if( rc < 0 ) + { + dataread = -1; + break; + } + bufferlen -= rc; + dataread += rc; + } + } + + /* + * restore the current position of the main file + */ + if( pblKfRestorePosition( isam->mainfile )) + { + return( -1 ); + } + + return( dataread ); +} + +/** + * update the data of the current record + * + * parameter datalen specifies how many bytes to write + * + * the file must be open for update + * + * @return long rc >= 0: call went ok, the value returned is the length + * of the data copied + * @return long rc < 0: some error occured, see pbl_errno + */ + +long pblIsamUpdateData( +pblIsamFile_t * isamfile, /** ISAM file to update */ +unsigned char * data, /** data to write */ +long datalen /** length of that data */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + char rkey[ PBLKEYLENGTH ]; + int rkeylen; + char fkey[ PBLKEYLENGTH ]; + int fkeylen; + long nwritten = 0; + long n; + long rc; + long olddatalen; + + /* + * start a transaction + */ + pblIsamStartTransaction( 1, &isamfile ); + + /* + * read the key of the current record in the main file + */ + rc = pblKfThis( isam->mainfile, fkey, &fkeylen ); + if( rc < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * read the old datalen of the records + */ + olddatalen = pblIsamReadDatalen( isamfile ); + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( fkeylen != 8 && fkeylen != 17 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_POSITION; + return( -1 ); + } + fkey[ fkeylen ] = 0; + + /* + * when the datalen gets shorter we first delete records + */ + while( datalen < olddatalen ) + { + /* + * position to the last record that has data + */ + rc = pblKfFind( isam->mainfile, PBLLA, fkey, fkeylen + 1, 0, 0 ); + if( rc < 0 ) + { + break; + } + + /* + * we shorten the data of the record + */ + olddatalen -= rc; + + /* + * delete the record + */ + rc = pblKfDelete( isam->mainfile ); + if( rc < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + return( -1 ); + } + + if( datalen < olddatalen ) + { + /* + * we need to delete more records from the end + */ + continue; + } + + /* + * position the current record of the main file to the allkeys record + */ + rc = pblKfFind( isam->mainfile, PBLFI, fkey, fkeylen, 0, 0 ); + if( rc < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + break; + } + + /* + * update existing records + */ + while( datalen > 0 ) + { + rc = pblKfNext( isam->mainfile, rkey, &rkeylen ); + if( rc < 0 ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + break; + } + nwritten = -1; + break; + } + + /* + * if we are now positioned on an entry with a different main key + */ + if(( fkeylen != rkeylen - 1 ) || memcmp( fkey, rkey, fkeylen )) + { + break; + } + + n = datalen; + if( n > PBLDATALENGTH ) + { + n = PBLDATALENGTH; + } + + /* + * udpate the data of the record + */ + if( n > 0 ) + { + rc = pblKfUpdate( isam->mainfile, data + nwritten, n ); + if( rc < 0 ) + { + nwritten = -1; + break; + } + datalen -= n; + nwritten += n; + } + } + + /* + * append new records + */ + while( datalen > 0 && nwritten >= 0 ) + { + n = datalen; + if( n > PBLDATALENGTH ) + { + n = PBLDATALENGTH; + } + + if( n > 0 ) + { + rc = pblKfInsert( isam->mainfile, fkey, fkeylen + 1, + data + nwritten, n ); + if( rc < 0 ) + { + nwritten = -1; + break; + } + datalen -= n; + nwritten += n; + } + } + + /* + * position the current record of the main file to the allkeys record + */ + rc = pblKfFind( isam->mainfile, PBLFI, fkey, fkeylen, 0, 0 ); + if( rc < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( nwritten < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * commit all changes + */ + if( pblIsamCommit( 1, &isamfile, 0 )) + { + return( -1 ); + } + + return( nwritten ); +} + +/** + * update a key of the current record of the ISAM file + * + * parameter index specifies which of the keys to update + * + * the file must be open for update + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error occured, see pbl_errno + */ + +int pblIsamUpdateKey( +pblIsamFile_t * isamfile, /** ISAM file to update key for */ +int index, /** index of key to update */ +unsigned char * ukey, /** new value for the key to update */ +int ukeylen /** length of that value */ +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + char okey[ PBLKEYLENGTH ]; + int okeylen; + char rkey[ PBLKEYLENGTH ]; + int rkeylen = -1; + char fkey[ PBLKEYLENGTH ]; + int fkeylen; + unsigned char * key; + int keylen; + unsigned char data[ PBLDATALENGTH ]; + long datalen; + long rc; + int n; + unsigned char newdata[ 2 * PBLDATALENGTH ]; + long newdatalen = 0; + unsigned char * newkey = newdata; + + /* + * start a transaction + */ + pblIsamStartTransaction( 1, &isamfile ); + + /* + * position the current record of the keyfile in question + */ + fkeylen = pblIsamGet( isamfile, PBLTHIS, index, fkey ); + if( fkeylen < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * read the key of the current record in the main file + */ + datalen = pblKfThis( isam->mainfile, okey, &okeylen ); + if( datalen < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * length 8 or 17 is for allkeys records + * if the length is 9 or 18, the record is a data record + */ + if( okeylen != 8 && okeylen != 17 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_POSITION; + return( -1 ); + } + okey[ okeylen ] = 0; + + /* + * the allkeys record can not be longer than a single data record + */ + if( datalen > PBLDATALENGTH ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read all the keys + */ + rc = pblKfRead( isam->mainfile, data, datalen ); + if( rc < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + else if( rc != datalen ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * make sure the key given is ok + */ + if(( ukeylen > PBLKEYLENGTH ) || ( ukeylen < 1 && !isam->keydup[ index ] )) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + /* + * copy all the keys, update the new one + */ + for( key = data, n = 0; n < isam->nkeys; n++ ) + { + if( n == index ) + { + keylen = 0xff & *key++; + if( keylen == ukeylen && !memcmp( key, ukey, ukeylen )) + { + /* + * the key has not changed + */ + pblIsamCommit( 1, &isamfile, 0 ); + return( 0 ); + } + + /* + * copy the new key into the allkeys array + */ + *newkey++ = 0xff & ukeylen; + if( 0xff & ukeylen ) + { + memcpy( newkey, ukey, 0xff & ukeylen ); + newkey += 0xff & ukeylen; + } + key += keylen; + } + else + { + *newkey++ = keylen = 0xff & *key++; + + /* + * copy the old key + */ + if( keylen ) + { + memcpy( newkey, key, keylen ); + newkey += keylen; + key += keylen; + } + } + + /* + * check whether the new allkeys array is in bounds + */ + if( newkey - newdata > PBLDATALENGTH ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + } + newdatalen = newkey - newdata; + + /* + * update the entry in the index file + * if the key is allowing duplicates + */ + if( isam->keydup[ index ] ) + { + unsigned char ikey[ PBLKEYLENGTH ]; + + /* + * create the reference key + */ + rkeylen = pblMainKey2RKey( okey, okeylen, rkey ); + if( rkeylen < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * create a unique key for the insert + */ + if( ukeylen + rkeylen > PBLKEYLENGTH ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + /* + * concatenate the key and the reference + */ + memcpy( ikey, ukey, ukeylen ); + memcpy( ikey + ukeylen, rkey, rkeylen ); + + /* + * make sure any user defined key compare function gets used + */ + pblkeycompare = isam->keycompare[ index ]; + + /* + * search for the new key in the file + */ + if( pblKfFind( isam->keyfiles[ index ], + PBLEQ, ikey, ukeylen + rkeylen, 0, 0 ) >= 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_EXISTS; + return( -1 ); + } + + /* + * delete the old record + */ + if( pblKfDelete( isam->keyfiles[ index ] )) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * insert the key to the file + */ + if( pblKfInsert( isam->keyfiles[ index ], + ikey, ukeylen + rkeylen, + 0, 0 )) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + } + else + { + /* + * search for the new key in the file + */ + if( pblKfFind( isam->keyfiles[ index ], + PBLEQ, ukey, ukeylen, 0, 0 ) >= 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_EXISTS; + return( -1 ); + } + + /* + * create the reference key + */ + rkeylen = pblMainKey2RKey( okey, okeylen, rkey ); + if( rkeylen < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * delete the old record + */ + if( pblKfDelete( isam->keyfiles[ index ] )) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * insert the key to the file + */ + if( pblKfInsert( isam->keyfiles[ index ], + ukey, ukeylen, + rkey, rkeylen )) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + } + + /* + * update the allkeys record + */ + rc = pblKfUpdate( isam->mainfile, newdata, newdatalen ); + if( rc < 0 ) + { + /* + * rollback all changes + */ + pblIsamCommit( 1, &isamfile, 1 ); + return( -1 ); + } + + /* + * commit all changes + */ + if( pblIsamCommit( 1, &isamfile, 0 )) + { + return( -1 ); + } + + return( rc ); +} + +/** + * set an application specific compare function for a key of an ISAM file + * + * parameter index specifies which of the indices to set + * the compare function for + * + * an application specific compare function can be used in order to + * implement special orderings of the values of an index, e.g. + * because of the use of european "umlauts" in names + * + * the default compare function is the c-library memcmp function + * the keycompare function should behave like memcmp + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error occured, see pbl_errno + */ + +int pblIsamSetCompareFunction( +pblIsamFile_t * isamfile, /** ISAM file to set function for */ +int index, /** index of key to set function for */ +int ( *keycompare ) /** compare function to set */ + ( + void* left, /** "left" buffer for compare */ + size_t llen, /** length of that buffer */ + void* right, /** "right" buffer for compare */ + size_t rlen /** length of that buffer */ + ) +) +{ + PBLISAMFILE_t * isam = ( PBLISAMFILE_t * ) isamfile; + + /* + * make sure the index is in bounds + */ + if( index >= isam->nkeys ) + { + pbl_errno = PBL_ERROR_PARAM_INDEX; + return( -1 ); + } + + /* + * if the key has duplicates + */ + if( isam->keydup[ index ] ) + { + /* + * we need to remember the compare function in the ISAM layer + * for use in the pblIsamDupKeyCompare function + */ + isam->keycompare[ index ] = keycompare; + } + else + { + /* + * set the custom compare function to the KF layer + */ + pblKfSetCompareFunction( isam->keyfiles[ index ], keycompare ); + + } + + return( 0 ); +} + diff --git a/src/pbl/pblkf.c b/src/pbl/pblkf.c new file mode 100644 index 0000000..6deef65 --- /dev/null +++ b/src/pbl/pblkf.c @@ -0,0 +1,6523 @@ +/* + pblkf.c - key file library implementation + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + $Log$ + Revision 1.1 2004/06/24 21:12:03 sears + Initial revision + + Revision 1.1 2003/12/11 09:10:49 jim + pbl + + Revision 1.4 2003/02/19 22:26:49 peter + made sure #defined values can be set by compiler switches + + Revision 1.3 2002/11/01 13:56:24 peter + Truncation of the memory block list is now called + at every file close. + + Revision 1.2 2002/11/01 13:27:30 peter + The block reference hash table is deleted when the + last block is deleted from the table, i.e. when the + last file is closed + + Revision 1.1 2002/09/12 20:47:07 peter + Initial revision + + +*/ + +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char * rcsid = "$Id$"; +static int rcsid_fkt() { return( rcsid ? 0 : rcsid_fkt() ); } + +#ifndef _WIN32 + +#include + +#endif + +#include +#include +#include + +#include +#include + +#include +#include +#include + + +#include /* program base library */ + +/******************************************************************************/ +/* #defines */ +/******************************************************************************/ + +#ifndef PBL_KF_TEST_DEFINES + +#ifndef PBLDATASIZE /* value might be set by compiler switch */ +#define PBLDATASIZE 4096 /* size of entire block data */ +#endif + +#ifndef PBLBLOCKSPERFILE /* value might be set by compiler switch */ +#define PBLBLOCKSPERFILE 64 /* default number of cache blocks per file */ +#endif + +#ifndef PBLNEXPANDED /* value might be set by compiler switch */ +#define PBLNEXPANDED 32 /* default number of expanded blocks */ +#endif + +#ifndef PBLFILEBLOCKS /* value might be set by compiler switch */ +#define PBLFILEBLOCKS 0xffff /* number of blocks per big file on disk */ +#endif + +#ifndef PBL_NFILES /* value might be set by compiler switch */ +#define PBL_NFILES 256 /* maximum number of open key files */ +#endif + +#else /* PBL_TEST_DEFINES */ + +#define PBLDATASIZE 64 /* size of entire block data */ +#define PBLBLOCKSPERFILE 10 /* default number of blocks in our cache */ +#define PBLNEXPANDED 5 /* default number of expanded blocks */ +#define PBLFILEBLOCKS 3 /* number of blocks per file */ + +#undef PBLKEYLENGTH +#define PBLKEYLENGTH 8 /* maximum length of a key */ + +#undef PBLDATALENGTH +#define PBLDATALENGTH 16 /* maximum length of data that is stored */ + /* with an item on the level 0 block */ + /* data that is longer is stored on data */ + /* blocks */ +#ifndef PBL_NFILES +#define PBL_NFILES 256 /* maximum number of open key files */ +#endif + +#endif /* PBL_TEST_DEFINES */ + +#define PBLHEADERSIZE 13 /* offset of first free byte on a new block */ + +#define PBLMAGIC "1.00 Peter's B Tree" + /* during creation this string is written */ + /* to the files */ + +/******************************************************************************/ +/* #macros */ +/******************************************************************************/ + +/* + * macro to determine free space on an index block + */ +#define PBLINDEXBLOCKNFREE( B ) ((PBLDATASIZE - B->free) - (2 * B->nentries)) + +/* + * macro to determine free space on a data block + */ +#define PBLDATABLOCKNFREE( B ) ( PBLDATASIZE - B->free ) + +/* + * macros for getting pointers or buffer offsets from the index + */ +#define PBLINDEXTOPTR( B, I ) ( B->data\ + + ( PBLDATASIZE - 2 * ( 1 + ( I ) ))) + +#define PBLINDEXTOBUFOFF( B, I ) pbl_BufToShort( PBLINDEXTOPTR( B, I )) + +/******************************************************************************/ +/* typedefs */ +/******************************************************************************/ + +/* + * PBL key file descriptor + */ +typedef struct PBLKFILE_s +{ + char * magic; /* magic string */ + int bf; /* file handle from bigfile handling */ + int update; /* flag: file open for update */ + + long blockno; /* of block current record is on */ + int index; /* of current record on this block */ + + long saveblockno; /* block number of saved position */ + int saveindex; /* item index of saved position */ + + void * filesettag; /* file set tag attached to file */ + + int transactions; /* number of transactions active for file */ + int rollback; /* next commit should lead to a rollback */ + + void * writeableListHead; /* head and tail of writeable blocks */ + void * writeableListTail; + + /* a user defined key compare function */ + int (*keycompare)( void * left, size_t llen, void * right, size_t rlen ); + +} PBLKFILE_t; + +/* + * items are the things we store in the data array of the index blocks + */ +typedef struct PBLITEM_s +{ + unsigned int level; /* level where item is inserted */ + + int keycommon; /* number of initial bytes this item has in */ + /* common with its predecessor on tbe block */ + + int keylen; /* length of the key */ + unsigned char * key; /* pointer to the key */ + + long datalen; /* length of the data */ + unsigned char * data; /* the data of the item */ + + long datablock; /* number of block the data is on */ + long dataoffset; /* offset of data on block */ + + struct PBLITEM_s * next; /* we save items in a list */ + struct PBLITEM_s * prev; /* during an insert */ + +} PBLITEM_t; + +/* + * memory blocks that have expanded keys are stored in an extra list + */ +typedef struct PBLBLOCKLINK_s +{ + struct PBLBLOCKLINK_s * next; + struct PBLBLOCKLINK_s * prev; + +} PBLBLOCKLINK_t; + +/* + * a file block in memory has this format + */ +typedef struct PBLBLOCK_s +{ + PBLBLOCKLINK_t blocklink; /* for linking blocks in a list */ + + unsigned int level; /* of block */ + + long blockno; /* block number in file */ + int bf; /* big file handle block belongs to */ + void * filesettag; /* file set tag attached */ + + unsigned char data[ PBLDATASIZE ]; /* the real data */ + + long nblock; /* next block of same level */ + long pblock; /* previous block of same level */ + unsigned int nentries; /* number of entries */ + int free; /* offset of first free byte */ + + long parentblock; /* number of parent block */ + int parentindex; /* index on parentblock */ + + int writeable; /* block can be written to */ + int dirty; /* has the block been written to ? */ + + unsigned char *expandedkeys; /* pointer to expanded keys of */ + /* the block */ + + struct PBLBLOCK_s * next; /* we keep the blocks we have */ + struct PBLBLOCK_s * prev; /* in memory in a LRU chain */ + +} PBLBLOCK_t; + +/* + * all file handles of all open filesystem files of + * all bigfiles are stored in a list + */ +typedef struct PBLBIGFILEHANDLE_s +{ + int bf; /* bigfile handle of file */ + int n; /* bigfile index of file */ + + int fh; /* filesystem handle */ + int mode; /* open mode */ + + struct PBLBIGFILEHANDLE_s * next; + struct PBLBIGFILEHANDLE_s * prev; + +} PBLBIGFILEHANDLE_t; + +/* + * a bigfile in memory + */ +typedef struct PBLBIGFILE_s +{ + char * name; /* name of first filesystem file */ + + int mode; /* open mode */ + long blocksperfile; /* blocks per filesystem file */ + long blocksize; /* size of one block */ + long nextblockno; /* block number of next free block */ + +} PBLBIGFILE_t; + +/* + * references to blocks are stored in a hashtable + */ +typedef struct PBLBLOCKREF_s +{ + long blockno; /* block number in file */ + long bf; /* big file handle block belongs to */ + + PBLBLOCK_t * block; /* address of block */ + +} PBLBLOCKREF_t; + +typedef struct PBLBLOCKHASHKEY_s +{ + long blockno; /* block number in file */ + long bf; /* big file handle block belongs to */ + +} PBLBLOCKHASHKEY_t; + +/******************************************************************************/ +/* globals */ +/******************************************************************************/ + +long pblnreads = 0; +long pblnwrites = 0; + +static char * magic = PBLMAGIC; + +/* + * pool of open bigfiles + */ +static PBLBIGFILE_t pbf_pool[ PBL_NFILES ]; + +/* + * headers for lists + */ +static PBLBIGFILEHANDLE_t * pbf_ft_head; +static PBLBIGFILEHANDLE_t * pbf_ft_tail; +static PBLBLOCKLINK_t * linkListHead; +static PBLBLOCKLINK_t * linkListTail; +static PBLBLOCK_t * blockListHead; +static PBLBLOCK_t * blockListTail; +static PBLITEM_t * itemListHead; +static PBLITEM_t * itemListTail; + +/* + * counters + */ +static int pblnblocks; +static int pblnlinks; +static int pblblocksperfile = PBLBLOCKSPERFILE; +static int pblexpandedperfile = PBLNEXPANDED; +static long pblnfiles; + +/* + * block reference hash table + */ +static pblHashTable_t * pblblockhash; + +/******************************************************************************/ +/* declarations */ +/******************************************************************************/ +static void pblBlockKeysRelease( PBLBLOCK_t * block ); +static int pblBlockKeysExpand( PBLBLOCK_t * block ); + +/******************************************************************************/ +/* functions */ +/******************************************************************************/ +/* + * verify consistency of parameters + */ +static int pblParamsCheck( +unsigned char * key, +unsigned int keylen, +unsigned char * data, +long datalen +) +{ + if(( keylen < 1 ) || ( keylen > 255 )) + { + pbl_errno = PBL_ERROR_PARAM_KEYLEN; + return( -1 ); + } + + if( datalen < 0 ) + { + pbl_errno = PBL_ERROR_PARAM_DATALEN; + return( -1 ); + } + + if( !key ) + { + pbl_errno = PBL_ERROR_PARAM_KEY; + return( -1 ); + } + + if( datalen && ( !data )) + { + pbl_errno = PBL_ERROR_PARAM_DATA; + return( -1 ); + } + + return( 0 ); +} + +/* + * functions on the block reference hash table + */ +/* +------------------------------------------------------------------------------ + FUNCTION: pblBlockHashInsert + + DESCRIPTION: inserts a new block reference into the hash table + + RETURNS: int rc == 0: a new reference was inserted + int rc == 1: the reference was already there, it was udpated + int rc < 0: some error occured, see pbl_errno + PBL_ERROR_OUT_OF_MEMORY: malloc failed, out of memory +------------------------------------------------------------------------------ +*/ +static int pblBlockHashInsert( long blockno, long bf, PBLBLOCK_t * block ) +{ + PBLBLOCKHASHKEY_t key; + PBLBLOCKREF_t * ref; + int rc; + + memset( &key, 0, sizeof( key )); + key.blockno = blockno; + key.bf = bf; + + if( !pblblockhash ) + { + pblblockhash = pblHtCreate(); + if( !pblblockhash ) + { + return( -1 ); + } + } + + /* + * see whether we have the reference already + */ + ref = pblHtLookup( pblblockhash, &key, sizeof( key )); + if( ref ) + { + /* + * the reference is already there, update the block pointer + */ + ref->block = block; + return( 1 ); + } + + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + } + + /* + * allocate memory for new reference + */ + ref = pbl_malloc0( "pblBlockHashInsert BLOCKREF", sizeof( PBLBLOCKREF_t )); + if( !ref ) + { + return( -1 ); + } + + /* + * insert to the hash table + */ + rc = pblHtInsert( pblblockhash, &key, sizeof( key ), ref ); + if( !rc ) + { + ref->block = block; + ref->blockno = blockno; + ref->bf = bf; + } + else + { + PBL_FREE( ref ); + return( -1 ); + } + + return( 0 ); +} + +/* +------------------------------------------------------------------------------ + FUNCTION: pblBlockHashRemove + + DESCRIPTION: Remove a block reference from the hash table + + RETURNS: int rc == 0: call went ok; + otherwise: block not found in hash table +------------------------------------------------------------------------------ +*/ +static int pblBlockHashRemove( long blockno, long bf ) +{ + PBLBLOCKHASHKEY_t key; + PBLBLOCKREF_t * ref; + int rc; + + memset( &key, 0, sizeof( key )); + key.blockno = blockno; + key.bf = bf; + + /* + * if there is no hash table yet, the reference is not found + */ + if( !pblblockhash ) + { + return( 1 ); + } + + /* + * see whether we have the reference + */ + ref = pblHtLookup( pblblockhash, &key, sizeof( key )); + if( !ref ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + } + + return( 1 ); + } + + /* + * remove the reference from the hash table + */ + rc = pblHtRemove( pblblockhash, &key, sizeof( key )); + if( rc ) + { + return( 1 ); + } + + PBL_FREE( ref ); + + /* + * attempt to remove the hashtable + */ + rc = pblHtDelete( pblblockhash ); + if( !rc ) + { + /* + * the hash table was empty and is deleted now + */ + pblblockhash = 0; + } + else + { + /* + * the hash table was not deleted because it is not + * empty, clear the error + */ + pbl_errno = 0; + } + + return( 0 ); +} + +/* +------------------------------------------------------------------------------ + FUNCTION: pblBlockHashFind + + DESCRIPTION: Find a block reference in the hash table + + RETURNS: PBLBLOCK_t * retptr == 0: block not found + otherwise: pointer to block in memory +------------------------------------------------------------------------------ +*/ +static PBLBLOCK_t * pblBlockHashFind( long blockno, long bf ) +{ + PBLBLOCKHASHKEY_t key; + PBLBLOCKREF_t * ref; + + memset( &key, 0, sizeof( key )); + key.blockno = blockno; + key.bf = bf; + + /* + * if there is no hash table yet, the reference is not found + */ + if( !pblblockhash ) + { + return( 0 ); + } + + /* + * see whether we have the reference + */ + ref = pblHtLookup( pblblockhash, &key, sizeof( key )); + if( !ref ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + } + + return( 0 ); + } + + return( ref->block ); +} + +/* + * BIGFILE functions + */ +/* + * find a filehandle of a filesystem file + */ +static PBLBIGFILEHANDLE_t * pbf_fh_find( int bf, int n ) +{ + PBLBIGFILEHANDLE_t * entry; + + /* + * file system handles are kept in an LRU list + */ + for( entry = pbf_ft_head; entry; entry = entry->next ) + { + if( bf == entry->bf && n == entry->n ) + { + if( entry != pbf_ft_head ) + { + PBL_LIST_UNLINK( pbf_ft_head, pbf_ft_tail, entry, next, prev ); + PBL_LIST_PUSH( pbf_ft_head, pbf_ft_tail, entry, next, prev ); + } + return( entry ); + } + } + + return( 0 ); +} + +/* + * close files with the filesystem + */ +static void pbf_fh_close( int bf, int n ) +{ + PBLBIGFILEHANDLE_t * entry; + PBLBIGFILEHANDLE_t * tmp; + + if( n < 0 ) + { + /* + * close all file handles of this big file + */ + for( entry = pbf_ft_head; entry; ) + { + tmp = entry; + entry = entry->next; + + if( bf == tmp->bf ) + { + close( tmp->fh ); + PBL_LIST_UNLINK( pbf_ft_head, pbf_ft_tail, tmp, next, prev ); + PBL_FREE( tmp ); + } + } + + return; + } + + /* + * close a particular file handle + */ + entry = pbf_fh_find( bf, n ); + if( !entry ) + { + return; + } + + close( entry->fh ); + + PBL_LIST_UNLINK( pbf_ft_head, pbf_ft_tail, entry, next, prev ); + PBL_FREE( entry ); +} + +/* + * create the bigfile path of a file + * bigfiles are stored in multiple filesystem files + * if the first one is called "file.ext", + * the others have names like "file_0002.ext" etc. + */ +static char * pbf_fh_path( char * name, long n ) +{ + char * path; + char * dotptr; + + if( n < 1 ) + { + /* + * the name of the first file does not change + */ + path = strdup( name ); + if( !path ) + { + pbl_errno = PBL_ERROR_OUT_OF_MEMORY; + return( 0 ); + } + return( path ); + } + + path = pbl_malloc( "pbf_fh_path path", 6 + strlen( name )); + if( !path ) + { + return( 0 ); + } + + /* + * see if there is a ".ext" after the last slash + */ + dotptr = strrchr( name, '.' ); + if( dotptr ) + { + if( strchr( dotptr, '/' ) || strchr( dotptr, '\\' )) + { + dotptr = 0; + } + } + + /* + * build the filename, start counting at one + */ + n++; + if( dotptr ) + { + memcpy( path, name, dotptr - name ); + snprintf( path + ( dotptr - name ), 6, "_%04lx", 0xffff & n ); + strcat( path, dotptr ); + } + else + { + strcpy( path, name ); + snprintf( path + strlen( path ), 6, "_%04lx", 0xffff & n ); + } + + return( path ); +} + +/* + * open a file with the file system + */ +static int pbf_fh_open( char * name, int mode, int bf, int n ) +{ + PBLBIGFILEHANDLE_t * entry; + int fh = -1; + int i; + char * path; + + /* + * look in LRU list of open filesystem files + */ + entry = pbf_fh_find( bf, n ); + if( entry ) + { + if( entry->mode != mode ) + { + /* + * the file was found, but the open mode is wrong, close the file + */ + pbf_fh_close( bf, n ); + entry = 0; + } + else + { + /* + * the file is open in the right mode, use the file handle + */ + return( entry->fh ); + } + } + + /* + * open the file + */ + path = pbf_fh_path( name, n ); + if( !path ) + { + return( -1 ); + } + + for( i = 0; i < 3; i++ ) + { + fh = open( path, mode, S_IREAD | S_IWRITE ); + if( -1 == fh && pbf_ft_tail ) + { + /* + * maybe the process or the system ran out of filehandles + * close one file and try again + */ + pbf_fh_close( pbf_ft_tail->bf, pbf_ft_tail->n ); + continue; + } + + break; + } + PBL_FREE( path ); + + if( -1 == fh ) + { + pbl_errno = PBL_ERROR_OPEN; + return( -1 ); + } + + /* + * create and link the file handle list entry + */ + entry = pbl_malloc0( "pbf_fh_open *entry", sizeof( *entry )); + if( !entry ) + { + close( fh ); + return( 0 ); + } + + entry->fh = fh; + entry->mode = mode; + entry->bf = bf; + entry->n = n; + + PBL_LIST_PUSH( pbf_ft_head, pbf_ft_tail, entry, next, prev ); + + return( entry->fh ); +} + +/* + * close a bigfile + */ +static int pbf_close( int bf ) +{ + if( bf < 0 || bf >= PBL_NFILES ) + { + return( -1 ); + } + + /* + * close all filesystem files + */ + pbf_fh_close( bf, -1 ); + + PBL_FREE( pbf_pool[ bf ].name ); + pbf_pool[ bf ].name = 0; + + return( 0 ); +} + +/* + * open a bigfile + */ +static int pbf_open( +char * name, +int update, +long blocksperfile, +long blocksize +) +{ + int fh = -1; + int mode; + int i; + char * path; + + path = pbf_fh_path( name, 0 ); + if( !path ) + { + return( -1 ); + } + + if( update ) + { + mode = O_CREAT | O_BINARY | O_RDWR; + } + else + { + mode = O_BINARY | O_RDONLY; + } + + /* + * find a slot in the big file pool that is free + */ + for( i = 0; i < PBL_NFILES; i++ ) + { + if( pbf_pool[ i ].name ) + { + continue; + } + + /* + * reserve the slot + */ + pbf_pool[ i ].mode = mode; + pbf_pool[ i ].nextblockno = -1; + pbf_pool[ i ].blocksperfile = blocksperfile; + pbf_pool[ i ].blocksize = blocksize; + + /* + * open the first filesystem file + */ + fh = pbf_fh_open( path, mode, i, 0 ); + if( -1 == fh ) + { + PBL_FREE( path ); + pbl_errno = PBL_ERROR_OPEN; + return( -1 ); + } + + pbf_pool[ i ].name = path; + return( i ); + } + + PBL_FREE( path ); + pbl_errno = PBL_ERROR_OPEN; + return( -1 ); +} + +/* + * file io for a bigfile + */ +static int pbf_blockio( +int bf, +int blockwrite, +long blockno, +unsigned char * buffer +) +{ + long rc = -1; + long n; + int fh; + int i; + int j; + long offset; + + if( bf < 0 || bf >= PBL_NFILES || !pbf_pool[ bf ].name ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * make sure the n'th filesystem file is open + */ + n = blockno / pbf_pool[ bf ].blocksperfile; + + fh = pbf_fh_open( pbf_pool[ bf ].name, pbf_pool[ bf ].mode, bf, n ); + if( -1 == fh ) + { + pbl_errno = PBL_ERROR_READ; + return( -1 ); + } + + blockno %= pbf_pool[ bf ].blocksperfile; + offset = blockno * pbf_pool[ bf ].blocksize; + + if( blockwrite ) + { + /* + * try the write more than once if needed + */ + for( i = 0; i < 3; i++ ) + { + /* + * try the seek more than once if needed + */ + for( j = 0; j < 3; j++ ) + { + rc = lseek( fh, offset, SEEK_SET ); + if( offset != rc ) + { + continue; + } + break; + } + if( offset != rc ) + { + pbl_errno = PBL_ERROR_SEEK; + return( -1 ); + } + + rc = write( fh, buffer, (unsigned int) pbf_pool[ bf ].blocksize ); + if( rc != pbf_pool[ bf ].blocksize ) + { + if( errno == EINTR ) + { + continue; + } + pbl_errno = PBL_ERROR_WRITE; + return( -1 ); + } + break; + } + if( i >= 3 ) + { + pbl_errno = PBL_ERROR_WRITE; + return( -1 ); + } + + pblnwrites++; + } + else + { + /* + * try the read more than once if needed + */ + for( i = 0; i < 3; i++ ) + { + /* + * try the seek more than once if needed + */ + for( j = 0; j < 3; j++ ) + { + rc = lseek( fh, offset, SEEK_SET ); + if( offset != rc ) + { + continue; + } + break; + } + if( offset != rc ) + { + pbl_errno = PBL_ERROR_SEEK; + return( -1 ); + } + + rc = read( fh, buffer, (unsigned int) pbf_pool[ bf ].blocksize ); + if( rc < 0 ) + { + if( errno == EINTR ) + { + continue; + } + pbl_errno = PBL_ERROR_READ; + return( -1 ); + } + pblnreads++; + + if( rc != pbf_pool[ bf ].blocksize ) + { + if( errno == EINTR ) + { + continue; + } + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + break; + } + if( i >= 3 ) + { + pbl_errno = PBL_ERROR_READ; + return( -1 ); + } + } + + return( 0 ); +} + +/* + * read a block from a bigfile + */ +static int pbf_blockread( int bf, long blockno, unsigned char * buffer ) +{ + int rc; + + rc = pbf_blockio( bf, 0, blockno, buffer ); + + return( rc ); +} + +/* + * write a block to a bigfile + */ +static int pbf_blockwrite( int bf, long blockno, unsigned char * buffer ) +{ + int rc; + + rc = pbf_blockio( bf, 1, blockno, buffer ); + + return( rc ); +} + +/* + * append a block to a bigfile + */ +static long pbf_blockappend( int bf, unsigned char * buffer ) +{ + int fh; + long offset; + int i; + int j; + long rc = -1; + unsigned char c; + + if( bf < 0 || bf >= PBL_NFILES || !pbf_pool[ bf ].name ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( pbf_pool[ bf ].nextblockno == 0x3fff ) + { + rc = -1; + } + + /* + * if we don't know the next free block of the file yet + */ + if( pbf_pool[ bf ].nextblockno < 0 ) + { + /* + * find the next free block of a bigfile + */ + for( i = 0; 1; i++ ) + { + /* + * create and open next filesytem file used for the bigfile + */ + fh = pbf_fh_open( pbf_pool[ bf ].name, pbf_pool[ bf ].mode, bf, i ); + if( -1 == fh ) + { + pbl_errno = PBL_ERROR_WRITE; + return( -1 ); + } + + /* + * reopen the filesystem file read only + */ + fh = pbf_fh_open( pbf_pool[ bf ].name, O_BINARY | O_RDONLY, bf, i ); + if( -1 == fh ) + { + pbl_errno = PBL_ERROR_WRITE; + return( -1 ); + } + + /* + * seek to the end of the file + */ + offset = pbf_pool[ bf ].blocksperfile * pbf_pool[ bf ].blocksize -1; + + for( j = 0; j < 3; j++ ) + { + rc = lseek( fh, offset, SEEK_SET ); + if( offset != rc ) + { + if( errno == EINTR ) + { + continue; + } + rc = -1; + break; + } + + /* + * check whether the block exist, by reading its last byte + */ + rc = read( fh, &c, 1 ); + if( rc < 1 ) + { + if( errno == EINTR ) + { + continue; + } + } + break; + } + + if( rc == 1 ) + { + /* + * we can read the last byte of the block, it is not free + */ + continue; + } + + /* + * we found the last filesystem file used for the bigfile + * seek to the end of the file + */ + for( j = 0; j < 3; j++ ) + { + rc = lseek( fh, 0, SEEK_END ); + if( rc < 0 ) + { + if( errno == EINTR ) + { + continue; + } + + pbl_errno = PBL_ERROR_WRITE; + return( -1 ); + } + break; + } + + if( rc % pbf_pool[ bf ].blocksize ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + pbf_pool[ bf ].nextblockno = rc / pbf_pool[ bf ].blocksize; + break; + } + } + + /* + * append the block to the bigfile + */ + rc = pbf_blockio( bf, 1, pbf_pool[ bf ].nextblockno, buffer ); + if( rc ) + { + return( rc ); + } + + return( pbf_pool[ bf ].nextblockno++ ); +} + +/* + * ITEM functions + * + * Layout of an item in the data of a block with a level greater than 0 + * + * LENGTH NAME SEMANTICS + * + * 1 KEYLEN length of the key of the item + * 1 KEYCOMMON number of bytes the key has in common with + * the key of the predecessor of the item on the block + * VARLONG DATABLOCK block number of block this item points to + * KEYLEN KEY the key itself, only the last KEYLEN - KEYCOMMON + * bytes are stored + * + * Layout of an item in the data of a block with a level 0 and + * with the datalen of the item smaller than or equal to PBLDATALENGTH + * + * LENGTH NAME SEMANTICS + * + * 1 KEYLEN length of the key of the item + * 1 KEYCOMMON number of bytes the key has in common with + * the key of the predecessor of the item on the block + * VARLONG DATALEN length of the data stored on the block + * KEYLEN KEY the key itself, only the last KEYLEN - KEYCOMMON + * bytes are stored + * DATALEN DATA the data is stored on the block + * + * Layout of an item in the data of a block with a level 0 and + * with the datalen of the item greater than PBLDATALENGTH + * + * LENGTH NAME SEMANTICS + * + * 1 KEYLEN length of the key of the item + * 1 KEYCOMMON number of bytes the key has in common with + * the key of the predecessor of the item on the block + * VARLONG DATALEN length of the data stored on the datablock + * KEYLEN KEY the key itself, only the last KEYLEN - KEYCOMMON + * bytes are stored + * VARLONG DATABLOCK block number of block data is stored on + * VARLONG DATAOFFSET offset of the data on that block + * + * The long values stored for an item, DATALEN, DATABLOCK and DATAOFFSET + * are stored as variable length buffers, i.e. the number of bytes + * used in the file for the values depends on their numerical value. + * See the VarBuf* functions for details. + * + * The smallest item of an inner block always has KEYLEN 0, which makes + * it's key logically smaller than any other possible key of an item. + * + * The items stored on a block start at address ( block->data + PBLHEADERSIZE ). + * The items are always stored immediately one after the other starting at + * at this address, we leave no space in between. + * + * As the keys of the items and therefore the items themselves can have + * different lengths, we store the relative offsets of the items in the + * data of a block also in the data of the block. Those relative offsets + * are stored as two byte unsigned shorts at the end of the data of the block. + * The relative offsets are called slots in the code below. + * + * The slots in the slot array are kept in order. + * + * For every block the short block->free gives the relative offset of the first + * free byte of the block, immediately after the end of the last item stored. + * + * Before we append an item we check if there is enough space for the item + * and its slot between the end of the last item stored and the beginning + * of the slot array of the items stored. If not, PBL_ERROR_NOFIT is given + * to the pblinsert procedure which then has to split the block. + * + * During deletion we pack the ordered array of the slots + * and the items themselves by shifting them on the block. + * + * The number of bytes the key of an item has in common with the key + * of the predecessor of the item is stored with each item. + * This is done in order to minimize the space needed for keys. + * + * EG: If a key is "New York" and its predecessor is "New Haven", + * only the string "York" is stored for the second key together + * with one byte indicating that the key has the first 4 bytes + * with its predecessor, the key "New Haven". + * + * Whenever the full keys are needed for the items of a block, + * the keys of the items of the block have to be "expanded" first. + */ + +/* + * The following three static procedures are the only ones that 'know' the + * layout of an item stored on a block + */ +static void pblItemToBuf( PBLBLOCK_t * block, int bufoff, PBLITEM_t * item ) +{ + unsigned char * ptr = &( block->data[ bufoff ] ); + + *ptr++ = ( unsigned char ) item->keylen; + *ptr++ = ( unsigned char ) item->keycommon; + + if( block->level > 0 ) + { + ptr += pbl_LongToVarBuf( ptr, item->datablock ); + } + else + { + ptr += pbl_LongToVarBuf( ptr, item->datalen ); + } + + if( item->keylen - item->keycommon > 0 ) + { + /* + * make sure we don't copy in place + */ + if( ptr != item->key + item->keycommon ) + { + pbl_memlcpy( ptr, PBLKEYLENGTH, + item->key + item->keycommon, + item->keylen - item->keycommon ); + } + ptr += item->keylen - item->keycommon; + } + + /* + * the block needs to be written to the filesystem + */ + block->dirty = 1; + + if( block->level > 0 ) + { + return; + } + + if( item->datalen <= PBLDATALENGTH ) + { + if( item->datalen > 0 ) + { + if( ptr != item->data ) + { + memcpy( ptr, item->data, item->datalen ); + } + } + } + else + { + ptr += pbl_LongToVarBuf( ptr, item->datablock ); + pbl_LongToVarBuf( ptr, item->dataoffset ); + } +} + +static int pblBufToItem( PBLBLOCK_t * block, int bufoff, PBLITEM_t * item ) +{ + unsigned char * ptr; + unsigned char * endptr; + + item->level = block->level; + + /* + * make sure the offset is in bounds + */ + if( bufoff >= sizeof( block->data )) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + endptr = &( block->data[ sizeof( block->data ) ] ); + ptr = &( block->data[ bufoff ] ); + + /* + * parse the item + */ + item->keylen = *ptr++; + item->keycommon = *ptr++; + + if( block->level > 0 ) + { + ptr += pbl_VarBufToLong( ptr, &( item->datablock )); + item->datalen = 0; + } + else + { + ptr += pbl_VarBufToLong( ptr, &( item->datalen )); + item->datablock = 0; + } + + if( ptr >= endptr ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( item->keylen - item->keycommon > 0 ) + { + item->key = ptr; + ptr += item->keylen - item->keycommon; + if( ptr >= endptr ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + } + else + { + item->key = 0; + } + + if( block->level > 0 ) + { + item->dataoffset = 0; + item->data = 0; + + return( 0 ); + } + + if( item->datalen <= PBLDATALENGTH ) + { + item->dataoffset = 0; + if( item->datalen > 0 ) + { + item->data = ptr; + ptr += item->datalen; + if( ptr >= endptr ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + } + else + { + item->data = 0; + } + } + else + { + ptr += pbl_VarBufToLong( ptr, &( item->datablock )); + pbl_VarBufToLong( ptr, &( item->dataoffset )); + item->data = 0; + } + + if( ptr >= endptr ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + return( 0 ); +} + +static int pblItemSize( PBLBLOCK_t * block, PBLITEM_t * item ) +{ + int rc = 2; + + if( block->level > 0 ) + { + rc += pbl_LongSize( item->datablock ); + } + else + { + rc += pbl_LongSize( item->datalen ); + } + + if( item->keylen - item->keycommon > 0 ) + { + rc += item->keylen - item->keycommon; + } + + if( block->level > 0 ) + { + return( rc ); + } + + if( item->datalen <= PBLDATALENGTH ) + { + if( item->datalen > 0 ) + { + rc += item->datalen; + } + } + else + { + rc += pbl_LongSize( item->datablock ); + rc += pbl_LongSize( item->dataoffset ); + } + + return( rc ); +} + +/* + * compare two items + */ +static int pblItemCompare( PBLKFILE_t *kf, PBLITEM_t *left, PBLITEM_t *right ) +{ + int rc; + + if( kf->keycompare ) + { + /* + * there is a specific compare function for the key file + */ + rc = (*kf->keycompare)( left->key, left->keylen, + right->key, right->keylen ); + } + else + { + /* + * use the default key compare function + */ + rc = pbl_memcmp( left->key, left->keylen, + right->key, right->keylen ); + } + + return( rc ); +} + +static int pblItemGet( PBLBLOCK_t * block, unsigned int index, PBLITEM_t *item ) +{ + /* + * if there is no item with required index + */ + if( index >= (unsigned int)block->nentries ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * copy the item with the required index + */ + if( pblBufToItem( block, PBLINDEXTOBUFOFF( block, index ), item )) + { + return( -1 ); + } + + /* + * if we have the expanded keys for the block we + * actually use those keys + */ + if( item->keycommon > 0 && block->expandedkeys ) + { + item->key = block->expandedkeys + index * PBLKEYLENGTH; + } + + return( 0 ); +} + +/* + * append an item to a block + */ +static int pblItemAppend( +PBLBLOCK_t * block, +unsigned char * predkey, +unsigned int predkeylen, +PBLITEM_t * item +) +{ + unsigned char * ptr; + unsigned int itemsize; + + if( !block->writeable ) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( -1 ); + } + + if( !predkey && block->nentries > 0 ) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( -1 ); + } + + /* + * calculate how many bytes the key of the item has in common + * with the key of the predecessor on the block + */ + if( predkey && ( predkeylen > 0 )) + { + item->keycommon = pbl_memcmplen( predkey, predkeylen, + item->key, item->keylen ); + } + else + { + item->keycommon = 0; + } + + /* + * calculate the size the item needs on the block + */ + itemsize = pblItemSize( block, item ); + + /* + * check if the item fits here, the "+ 2" is for the slot! + */ + if( PBLINDEXBLOCKNFREE( block ) < itemsize + 2 ) + { + pbl_errno = PBL_ERROR_NOFIT; + return( -1 ); + } + + /* + * put item to data part of block + */ + pblItemToBuf( block, block->free, item ); + + /* + * put the slot to the block + */ + ptr = PBLINDEXTOPTR( block, block->nentries ); + pbl_ShortToBuf( ptr, block->free ); + + block->free += itemsize; + block->nentries += 1; + + if( block->expandedkeys ) + { + pblBlockKeysRelease( block ); + } + + return( 0 ); +} + +/* + * delete an item from a block + */ +static int pblItemDelete( PBLBLOCK_t * block, int index ) +{ + PBLITEM_t item; + int ntomove; + unsigned int i; + int offset; + int itemoffset; + unsigned char * ptr; + unsigned int itemsize; + + /* + * read the item to delete + */ + if( pblItemGet( block, index, &item )) + { + return( -1 ); + } + + /* + * calculate the size the item ocupies on the block + */ + itemsize = pblItemSize( block, &item ); + + /* + * calculate the number of items that have to be moved + */ + itemoffset = PBLINDEXTOBUFOFF( block, index ); + ptr = block->data + itemoffset; + ntomove = block->free - ( itemoffset + itemsize ); + if( ntomove < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( ntomove > 0 ) + { + /* + * move the other items to the left + */ + memmove( ptr, ptr + itemsize, ntomove ); + + /* + * the slots who's offsets are to the right of the deleted item + * have to change, because the items where moved + */ + for( i = 0; i < block->nentries; i++ ) + { + offset = PBLINDEXTOBUFOFF( block, i ); + if( offset > itemoffset ) + { + offset -= itemsize; + ptr = PBLINDEXTOPTR( block, i ); + pbl_ShortToBuf( ptr, offset ); + } + } + } + + /* + * blank out the bytes deleted + */ + memset(( block->data + block->free ) - itemsize, 0, itemsize ); + + /* + * there is more free space on the block now + */ + block->free -= itemsize; + + /* + * delete the slot from the slots array + */ + ptr = PBLINDEXTOPTR( block, block->nentries - 1 ); + if( index < (int)block->nentries - 1 ) + { + ntomove = ( block->nentries - 1 ) - index; + memmove( ptr + 2, ptr, ntomove * 2 ); + } + + /* + * blank out the last slot + */ + *ptr++ = 0; + *ptr = 0; + + /* + * there is one less slot on the block + */ + block->nentries -= 1; + + if( block->expandedkeys ) + { + pblBlockKeysRelease( block ); + } + + block->dirty = 1; + return( 0 ); +} + +/* + * insert an item on a block before the item with a given index + */ +static int pblItemInsert( PBLBLOCK_t * block, PBLITEM_t * item, int index ) +{ + int ntomove; + unsigned char * ptr; + unsigned int itemsize; + + /* + * calculate the size the item needs on the block + */ + itemsize = pblItemSize( block, item ); + + /* + * check if the item fits here, the "+ 2" is for the slot! + */ + if( PBLINDEXBLOCKNFREE( block ) < itemsize + 2 ) + { + pbl_errno = PBL_ERROR_NOFIT; + return( -1 ); + } + + /* + * put item to data part of block + */ + pblItemToBuf( block, block->free, item ); + + /* + * move the slots of the items after index + */ + ptr = PBLINDEXTOPTR( block, block->nentries ); + ntomove = block->nentries - index; + if( ntomove > 0 ) + { + memmove( ptr, ptr + 2, 2 * ntomove ); + } + + /* + * put the slot to the slots array + */ + ptr = PBLINDEXTOPTR( block, index ); + pbl_ShortToBuf( ptr, block->free ); + + block->free += itemsize; + block->nentries += 1; + + if( block->expandedkeys ) + { + pblBlockKeysRelease( block ); + } + + block->dirty = 1; + return( 0 ); +} + +/* + * remove an item from a block + */ +static int pblItemRemove( PBLBLOCK_t *block, unsigned int index ) +{ + PBLITEM_t peeritem; + PBLITEM_t previtem; + unsigned char data[ PBLDATALENGTH ]; + unsigned char savekey[ PBLKEYLENGTH ]; + int rc; + int keycommon; + int dodelete = 0; + + if( !block->writeable ) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( -1 ); + } + + /* + * if there is no item with required index + */ + if( index >= block->nentries ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * create the expanded keys of the block + */ + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + + if( index == block->nentries - 1 ) + { + /* + * delete the last item on the block + */ + rc = pblItemDelete( block, index ); + return( rc ); + } + + /* + * read the previous item on the block + */ + if( index > 0 ) + { + if( pblItemGet( block, index - 1, &previtem )) + { + return( -1 ); + } + } + + /* + * read the next item on the block + */ + if( pblItemGet( block, index + 1, &peeritem )) + { + return( -1 ); + } + + if(( index > 0 ) && ( previtem.keylen > 0 )) + { + keycommon = pbl_memcmplen( previtem.key, previtem.keylen, + peeritem.key, peeritem.keylen ); + } + else + { + keycommon = 0; + } + + /* + * if the next item has to change + */ + if( keycommon != peeritem.keycommon ) + { + /* + * delete and reinsert the next item, because its keycommon changed + */ + dodelete = 1; + + /* + * set the new keycommon value for the next item + */ + peeritem.keycommon = keycommon; + + /* + * save the data of the next item + */ + if( peeritem.datalen <= PBLDATALENGTH ) + { + memcpy( data, peeritem.data, peeritem.datalen ); + peeritem.data = data; + } + + /* + * save the key of the next item + */ + memcpy( savekey, peeritem.key, peeritem.keylen ); + peeritem.key = savekey; + + /* + * delete the next item + */ + rc = pblItemDelete( block, index + 1 ); + if( rc ) + { + return( rc ); + } + } + + /* + * delete the index'th item + */ + rc = pblItemDelete( block, index ); + if( rc ) + { + return( rc ); + } + + if( dodelete ) + { + /* + * insert the saved item again + */ + rc = pblItemInsert( block, &peeritem, index ); + } + return( rc ); +} + +/* + * find an item that has a key equal to the search key + * + * - uses a binary search to position to an item on a block + */ +static int pblItemFind( +PBLKFILE_t * kf, +PBLBLOCK_t * block, +PBLITEM_t * item, +int which +) +{ + int found = -1; + int index = 0; + int left = 0; + int right = block->nentries - 1; + int rc = 1; + PBLITEM_t curitem; + + while( left <= right ) + { + index = ( left + right ) / 2; + + if( pblItemGet( block, index, &curitem )) + { + return( -1 ); + } + + rc = pblItemCompare( kf, &curitem, item ); + if( rc == 0 ) + { + switch( which ) + { + case PBLLT: + right = index - 1; + break; + + case PBLLE: + case PBLFI: + found = index; + right = index - 1; + break; + + case PBLEQ: + found = index; + return( found ); + + case PBLLA: + case PBLGE: + found = index; + left = index + 1; + break; + + case PBLGT: + left = index + 1; + break; + } + } + else if ( rc < 0 ) + { + switch( which ) + { + case PBLLT: + case PBLLE: + found = index; + left = index + 1; + break; + + case PBLFI: + case PBLEQ: + case PBLLA: + case PBLGE: + case PBLGT: + left = index + 1; + break; + } + } + else + { + switch( which ) + { + case PBLLT: + case PBLLE: + case PBLFI: + case PBLEQ: + case PBLLA: + right = index - 1; + break; + + case PBLGE: + case PBLGT: + found = index; + right = index - 1; + break; + } + } + } + + if( found < 0 ) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + } + + return( found ); +} + +static int pblItemAdd( PBLKFILE_t * kf, PBLBLOCK_t * block, PBLITEM_t * item ) +{ + PBLITEM_t previtem; + PBLITEM_t peeritem; + int rc; + int index; + unsigned char savekey[ PBLKEYLENGTH ]; + unsigned int savekeylen; + unsigned char data[ PBLDATALENGTH ]; + unsigned int itemsize; + int keycommon; + + if( !block->writeable ) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( -1 ); + } + + if( block->nentries < 1 ) + { + if( pblItemAppend( block, 0, 0, item )) + { + return( -1 ); + } + return( 0 ); + } + + /* + * create the expanded keys of the block + */ + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + + /* + * find the first item that is bigger than the one we insert + */ + index = pblItemFind( kf, block, item, PBLGT ); + if( index < 0 ) + { + if( pbl_errno != PBL_ERROR_NOT_FOUND ) + { + return( -1 ); + } + + /* + * append to the block + */ + pbl_errno = 0; + index = block->nentries; + + if( pblItemGet( block, index - 1, &peeritem )) + { + return( -1 ); + } + + savekeylen = peeritem.keylen; + if( savekeylen > 0 ) + { + pbl_memlcpy( savekey, sizeof( savekey ), peeritem.key, savekeylen ); + } + + if( pblItemAppend( block, savekey, savekeylen, item )) + { + return( -1 ); + } + return( index ); + } + + /* + * read the previous item on the block + */ + if( index > 0 ) + { + if( pblItemGet( block, index - 1, &previtem )) + { + return( -1 ); + } + } + + /* + * calculate the number of bytes the key of the item has in + * common with the key of its predecessor + */ + if(( index > 0 ) && ( previtem.keylen > 0 )) + { + item->keycommon = pbl_memcmplen( previtem.key, previtem.keylen, + item->key, item->keylen ); + } + else + { + item->keycommon = 0; + } + + /* + * calculate the size the item needs on the block + */ + itemsize = pblItemSize( block, item ); + + /* + * check if the item fits here, the "+ 2" is for the slot! + */ + if( PBLINDEXBLOCKNFREE( block ) < itemsize + 2 ) + { + pbl_errno = PBL_ERROR_NOFIT; + return( -1 ); + } + + /* + * read the next item on the block + */ + if( pblItemGet( block, index, &peeritem )) + { + return( -1 ); + } + + /* + * calculate the number of bytes the key of the next item has in + * common with the key of the new item + */ + if( item->keylen > 0 ) + { + keycommon = pbl_memcmplen( item->key, item->keylen, + peeritem.key, peeritem.keylen ); + } + else + { + keycommon = 0; + } + + /* + * if the next item has to change + */ + if( keycommon != peeritem.keycommon ) + { + /* + * set the new keycommon value for the next item + */ + peeritem.keycommon = keycommon; + + /* + * save the data of that item + */ + if( peeritem.datalen <= PBLDATALENGTH ) + { + memcpy( data, peeritem.data, peeritem.datalen ); + peeritem.data = data; + } + + /* + * save the key of the item + */ + memcpy( savekey, peeritem.key, peeritem.keylen ); + peeritem.key = savekey; + + /* + * delete the next item + */ + rc = pblItemDelete( block, index ); + if( rc ) + { + return( rc ); + } + + /* + * insert the saved item again + */ + rc = pblItemInsert( block, &peeritem, index ); + if( rc ) + { + return( rc ); + } + } + + /* + * insert the new item + */ + rc = pblItemInsert( block, item, index ); + if( rc ) + { + return( rc ); + } + + return( index ); +} + +/* + * BLOCK functions + * + * The size of a block in the file is PBLDATASIZE + * + * The layout is as follows: + * + * OFFSET NAME SEMANTICS + * + * 0 LEVEL Level of the block in the tree + * if 0: the block is a leaf node + * if 254: the block is a free block, can be reused + * if 255: the block is a data block, not belonging to + * the tree. + * otherwise: block is an inner node of the tree + * + * 1 - 4 NOFFSET block number of next block of same level, as the root block + * always is the only block of it's level, the block number + * of the last data block is stored here, we use this block + * for appending data if necessary. + * + * 5 - 8 POFFEST file offset of previous block of the same level, + * as the root block always is the only block of it's level, + * the block number of the first free block with level 254 + * is stored on the root block + * + * 9 - 10 NENTRIES number of items stored in the data of the block. + * always 0 for data blocks. + * + * 11 - 12 FREE relative offset of first free byte in the data of the block + * + * 13 - ( PBLDATASIZE - 1 ) data area of the block used for storing items on + * tree blocks ( level 0 - 253 ) or used for storing + * the data of the items on data blocks ( level 255 ). + * + * The root block of the tree is always stored at file offset 0. The first data + * block at file offset PBLDATASIZE. There are at least two blocks in a file + * even if there are no items stored at all. + * + * For records with a datalen of less or equal to PBLDATALENGTH characters + * the data is stored on the level 0 index blocks. For records with + * data longer than PBLDATALENGTH characters the data is stored on data blocks. + * + * This is done in order to keep the height of the tree small and to allow + * data lengths of more than PBLDATASIZE bytes. What we pay for this is that + * the space in the file used for the data of records stored on data blocks + * and that are deleted or updated is lost. + * + * Blocks read from disk are cached in an LRU list, references to blocks + * in that list are kept in a hash table in order to speed up access. + * + * Blocks changed during a transaction are kept in the writeable block + * list. If a cached block that is dirty has to be made writeable a copy + * of the block is created in the writeable list, if the block is not + * dirty the block is moved from the cached list to the writeable list + * without creating a copy. + * + * During a transaction blocks from the writeable list take precedence + * over the copy of the same block from the cached list. + * + * During a rollback all blocks from the writeable list are discarded, + * thus reverting the file to the state before the beginning of the + * transaction. + * + * During a commit all blocks are moved from the writeable list to the + * cached list. + */ + +/* + * The following two procedures are the only ones that 'know' the layout + * of a the data of a block in the file + */ +static void pblDataToBlock( PBLBLOCK_t * block ) +{ + block->data[ 0 ] = block->level; + + pbl_LongToBuf ( &( block->data[ 1 ]), block->nblock ); + pbl_LongToBuf ( &( block->data[ 5 ]), block->pblock ); + pbl_ShortToBuf( &( block->data[ 9 ]), block->nentries ); + pbl_ShortToBuf( &( block->data[ 11 ]), block->free ); +} + +static void pblBlockToData( PBLBLOCK_t * block ) +{ + block->level = block->data[ 0 ]; + + block->nblock = pbl_BufToLong ( &( block->data[ 1 ])); + block->pblock = pbl_BufToLong ( &( block->data[ 5 ])); + block->nentries = pbl_BufToShort( &( block->data[ 9 ])); + block->free = pbl_BufToShort( &( block->data[ 11 ])); +} + +/* + * release all memory blocks of a file + */ +static void pblBlocksRelease( int bf ) +{ + PBLBLOCK_t * block; + + /* + * all blocks that were belonging to the file are marked unused + */ + for( block = blockListHead; block; block = block->next ) + { + if( block->bf == bf ) + { + pblBlockHashRemove( block->blockno, block->bf ); + pblBlockKeysRelease( block ); + block->bf = -1; + block->filesettag = NULL; + } + } + return; +} + +/* + * release the expanded keys buffer of a block + */ +static void pblBlockKeysRelease( PBLBLOCK_t * block ) +{ + PBLBLOCKLINK_t * blink; + + if( block->expandedkeys ) + { + blink = ( PBLBLOCKLINK_t * )block; + + PBL_LIST_UNLINK( linkListHead, linkListTail, blink, next, prev ); + pblnlinks--; + + PBL_FREE( block->expandedkeys ); + + block->expandedkeys = 0; + } +} + +/* + * expand all keys of a block + */ +static int pblBlockKeysExpand( PBLBLOCK_t * block ) +{ + unsigned int i; + PBLITEM_t item; + unsigned char * expandedkeys = 0; + PBLBLOCKLINK_t * blink; + + if( block->expandedkeys ) + { + blink = ( PBLBLOCKLINK_t * )block; + + /* + * make the block link the first in the LRU chain + */ + if( blink != linkListHead ) + { + PBL_LIST_UNLINK( linkListHead, linkListTail, blink, next, prev ); + PBL_LIST_PUSH( linkListHead, linkListTail, blink, next, prev ); + } + return( 0 ); + } + + /* + * get space for the expanded keys of the block + */ + if( block->nentries > 0 ) + { + i = block->nentries * PBLKEYLENGTH; + } + else + { + i = 1; + } + + expandedkeys = pbl_malloc( "pblBlockKeysExpand expandedkeys", i ); + if( !expandedkeys ) + { + return( -1 ); + } + + /* + * run through all items of the block + */ + for( i = 0; i < block->nentries; i++ ) + { + pblItemGet( block, i, &item ); + + if( item.keylen < 1 ) + { + continue; + } + + if( item.keycommon < 1 || i < 1 ) + { + /* + * this item does not have bytes in common with the predecessor + */ + pbl_memlcpy( expandedkeys + i * PBLKEYLENGTH, + PBLKEYLENGTH, item.key, item.keylen ); + } + else + { + /* + * copy the bytes the key has in common with + * the key of the predecessor + */ + pbl_memlcpy( expandedkeys + i * PBLKEYLENGTH, PBLKEYLENGTH, + expandedkeys + ( i - 1 ) * PBLKEYLENGTH, + item.keycommon ); + + if( item.keylen - item.keycommon > 0 ) + { + /* + * copy the bytes that are unique for the key + */ + pbl_memlcpy( expandedkeys + i * PBLKEYLENGTH + item.keycommon, + PBLKEYLENGTH, item.key, + item.keylen - item.keycommon ); + } + } + } + + block->expandedkeys = expandedkeys; + + /* + * release some expanded key structures if there are too many + */ + while( pblnlinks > 8 + ( pblexpandedperfile * pblnfiles )) + { + pblBlockKeysRelease( ( PBLBLOCK_t * )linkListTail ); + } + + /* + * link the block to the list of blocks that have expanded keys + */ + blink = ( PBLBLOCKLINK_t * )block; + PBL_LIST_PUSH( linkListHead, linkListTail, blink, next, prev ); + pblnlinks++; + + return( 0 ); +} + +static int pblBlockWrite( PBLBLOCK_t * block ) +{ + long rc; + + /* + * prepare the block data for writing + */ + pblDataToBlock( block ); + + /* + * write the block to the big file + */ + rc = pbf_blockwrite( block->bf, block->blockno, block->data ); + if( rc < 0 ) + { + block->bf = -1; + block->filesettag = NULL; + pbl_errno = PBL_ERROR_WRITE; + return( -1 ); + } + + return( 0 ); +} + +static int pblBlockFlush( int bf, int release ) +{ + PBLBLOCK_t * block; + PBLBLOCK_t * tmp; + + for( tmp = blockListHead; tmp; ) + { + /* + * move through the list of blocks before handling this one + */ + block = tmp; + tmp = tmp->next; + + if( block->bf != bf ) + { + continue; + } + + /* + * if a file set tag is set for the block we flush + * all blocks having the same tag set + */ + if( block->dirty && block->filesettag ) + { + PBLBLOCK_t * b; + + /* + * run through all blocks on all files in the set and write them + */ + for( b = blockListHead; b; b = b->next ) + { + if( b->dirty && b->bf >= 0 + && ( block->filesettag == b->filesettag )) + { + if( pblBlockWrite( b )) + { + pblBlocksRelease( b->bf ); + break; + } + else + { + b->dirty = 0; + } + } + } + } + + if( block->dirty ) + { + if( pblBlockWrite( block )) + { + /* + * this write always is a rewrite of an existing block + * therefore a write error is a strange condition, + * we unlink all blocks from the file + * most likely the file is inconsistent after that !!!! + */ + pblBlocksRelease( bf ); + return( -1 ); + } + else + { + block->dirty = 0; + } + } + + if( release ) + { + pblBlockHashRemove( block->blockno, block->bf ); + pblBlockKeysRelease( block ); + block->bf = -1; + block->filesettag = NULL; + + /* + * put the block to the end of the LRU list + */ + if( block != blockListTail ) + { + PBL_LIST_UNLINK( blockListHead, blockListTail, + block, next, prev ); + PBL_LIST_APPEND( blockListHead, blockListTail, + block, next, prev ); + } + } + } + return( 0 ); +} + +static PBLBLOCK_t * pblBlockGetVictim( PBLKFILE_t * file ) +{ + int rc; + PBLBLOCK_t * block; + + /* + * if we have not exceeded the number of blocks we can have at most + * or of the last block in the LRU chain is dirty and we are updating + */ + if(( pblnblocks < 8 + ( pblblocksperfile * pblnfiles ) ) + ||( blockListTail && blockListTail->dirty + && blockListTail->bf != -1 && file->writeableListHead )) + { + block = pbl_malloc0( "pblBlockGetVictim BLOCK", sizeof( PBLBLOCK_t )); + if( !block ) + { + return( ( PBLBLOCK_t * ) 0 ); + } + pblnblocks++; + PBL_LIST_PUSH( blockListHead, blockListTail, block, next, prev ); + } + else + { + /* + * we reuse the last block in the LRU chain + */ + if( blockListTail ) + { + if( blockListTail->bf != -1 ) + { + /* + * flush the block to disk if it is dirty + */ + if( blockListTail->dirty ) + { + rc = pblBlockFlush( blockListTail->bf, 0 ); + if( rc ) + { + return( ( PBLBLOCK_t * ) 0 ); + } + } + + /* + * remove the reference to the block from the hash table + */ + pblBlockHashRemove( blockListTail->blockno, blockListTail->bf ); + } + + if(( block = blockListTail )) + { + PBL_LIST_UNLINK( blockListHead, blockListTail, + block, next, prev ); + PBL_LIST_PUSH( blockListHead, blockListTail, + block, next, prev ); + } + } + else + { + pbl_errno = PBL_ERROR_PROGRAM; + return( 0 ); + } + + /* + * make sure the expanded keys of the block are freed + */ + pblBlockKeysRelease( block ); + } + + block->parentblock = -1; + block->parentindex = -1; + block->dirty = 0; + block->bf = -1; + block->filesettag = NULL; + + return( block ); +} + +static PBLBLOCK_t * pblBlockFind( PBLKFILE_t * file, long blockno ) +{ + PBLBLOCK_t * block; + + /* + * check if the block is in the LRU list of writeable blocks + */ + for( block = file->writeableListHead; block; block = block->next ) + { + if(( block->blockno == blockno ) + &&( block->bf == file->bf )) + { + /* + * the block is already there, make it the first of the LRU chain + */ + if( block != file->writeableListHead ) + { + PBL_LIST_UNLINK( file->writeableListHead, + file->writeableListTail, block, next, prev ); + PBL_LIST_PUSH( file->writeableListHead, + file->writeableListTail, block, next, prev ); + } + + return( block ); + } + } + + /* + * check if the block is the head of the LRU list of blocks cached + */ + if( blockListHead + && blockListHead->blockno == blockno + && blockListHead->bf == file->bf ) + { + return( blockListHead ); + } + + /* + * lookup the block in the LRU list of blocks cached + */ + block = pblBlockHashFind( blockno, file->bf ); + if( block ) + { + /* + * the block is there, make it the first of the LRU chain + */ + if( block != blockListHead ) + { + PBL_LIST_UNLINK( blockListHead, blockListTail, block, next, prev ); + PBL_LIST_PUSH( blockListHead, blockListTail, block, next, prev ); + } + + return( block ); + } + + return( 0 ); +} + +static PBLBLOCK_t * pblBlockGet( PBLKFILE_t * file, long blockno ) +{ + PBLBLOCK_t * block; + long rc; + + /* + * check if block is in memory + */ + block = pblBlockFind( file, blockno ); + if( block ) + { + return( block ); + } + + /* + * block is not in memory, we have to load it; get an empty block + */ + block = pblBlockGetVictim( file ); + if( !block ) + { + return( block ); + } + + /* + * read the data from file + */ + rc = pbf_blockread( file->bf, blockno, block->data ); + if( rc < 0 ) + { + return( ( PBLBLOCK_t * ) 0 ); + } + + /* + * block has been read successfully, so it belongs to this file from now on + */ + pblBlockToData( block ); + + block->blockno = blockno; + block->bf = file->bf; + block->filesettag = file->filesettag; + + /* + * insert the reference into the hash table + */ + if( pblBlockHashInsert( block->blockno, block->bf, block ) ) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( 0 ); + } + return( block ); +} + +/* + * get a version of block we can write to to the writeable list of the file + */ +static PBLBLOCK_t * pblBlockGetWriteable( PBLKFILE_t * file, long blockno ) +{ + PBLBLOCK_t * newblock; + PBLBLOCK_t * block; + + /* + * get the block to memory + */ + block = pblBlockGet( file, blockno ); + if( !block || block->writeable ) + { + return( block ); + } + + if( !block->dirty ) + { + /* + * move the block over to the writeable list + */ + pblnblocks--; + PBL_LIST_UNLINK( blockListHead, blockListTail, block, next, prev ); + pblBlockHashRemove( block->blockno, block->bf ); + + block->writeable = 1; + PBL_LIST_PUSH( file->writeableListHead, + file->writeableListTail, block, next, prev ); + + return( block ); + } + + /* + * create a copy of the block in the writeable block list + */ + newblock = pbl_memdup( "pblBlockGetWriteable block", + block, sizeof( *block ) ); + if( !newblock ) + { + return( newblock ); + } + + newblock->writeable = 1; + PBL_LIST_PUSH( file->writeableListHead, file->writeableListTail, + newblock, next, prev ); + + /* + * make sure the expanded keys are only stored once + */ + if( block->expandedkeys ) + { + PBLBLOCKLINK_t * blink; + + blink = ( PBLBLOCKLINK_t * ) block; + PBL_LIST_UNLINK( linkListHead, linkListTail, blink, next, prev ); + + blink = ( PBLBLOCKLINK_t * ) newblock; + PBL_LIST_PUSH( linkListHead, linkListTail, blink, next, prev ); + + block->expandedkeys = 0; + } + + return( newblock ); +} + +static int pblBlockFree( PBLKFILE_t * file, long blockno ) +{ + PBLBLOCK_t * rootblock; + PBLBLOCK_t * block; + PBLBLOCK_t * nblock = 0; + PBLBLOCK_t * pblock = 0; + + /* + * get the root block to memory + */ + rootblock = pblBlockGetWriteable( file, 0 ); + if( !rootblock ) + { + return( -1 ); + } + + /* + * read the block to be freed + */ + block = pblBlockGetWriteable( file, blockno ); + if( !block ) + { + return( -1 ); + } + + /* + * read the previous and next block if they exists + */ + if( block->nblock ) + { + nblock = pblBlockGetWriteable( file, block->nblock ); + if( !nblock ) + { + return( -1 ); + } + } + + if( block->pblock ) + { + pblock = pblBlockGetWriteable( file, block->pblock ); + if( !pblock ) + { + return( -1 ); + } + } + + if( nblock ) + { + nblock->pblock = block->pblock; + nblock->dirty = 1; + } + + if( pblock ) + { + pblock->nblock = block->nblock; + pblock->dirty = 1; + } + + pblBlockKeysRelease( block ); + + /* + * set the values of the free block + */ + block->level = 254; + block->nblock = rootblock->pblock; + + /* + * blocks freed always have their predecessor set to 0 + */ + block->pblock = 0; + block->nentries = 0; + block->free = PBLHEADERSIZE; /* offset of first free byte */ + + memset( block->data, 0, PBLDATASIZE ); + + block->dirty = 1; + + /* + * set the link from the rootblock to the block + */ + rootblock->pblock = blockno; + rootblock->dirty = 1; + + return( 0 ); +} + +static int pblBlockConcat( +PBLKFILE_t * file, +PBLBLOCK_t * block, +PBLBLOCK_t * from, +unsigned char * key, +unsigned int keylen +) +{ + PBLBLOCK_t tmpblock; + unsigned char predkey[ PBLKEYLENGTH ]; + unsigned int predkeylen = 0; + PBLITEM_t item; + int rc; + unsigned int i; + int nentries; + + if( !block->writeable || !from->writeable ) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( -1 ); + } + + /* + * read the last item of left block + */ + nentries = block->nentries; + if( block->nentries > 0 ) + { + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + + pblItemGet( block, block->nentries - 1, &item ); + + predkeylen = item.keylen; + if( predkeylen ) + { + pbl_memlcpy( predkey, sizeof( predkey ), item.key, predkeylen ); + } + } + + /* + * we do not need the expanded keys of the block anymore + */ + pblBlockKeysRelease( block ); + + /* + * create a local copy to concatenate to + */ + tmpblock = *block; + + /* + * expand the keys of the right block + */ + if( pblBlockKeysExpand( from )) + { + return( -1 ); + } + + /* + * copy all items to be merged to the temporary block + */ + for( i = 0; i < from->nentries; i++ ) + { + pblItemGet( from, i, &item ); + + /* + * the first item can have an empty key, if so we use + * key given as parameter + */ + if( i == 0 && keylen > 0 && item.keylen < 1 ) + { + item.key = key; + item.keylen = keylen; + } + rc = pblItemAppend( &tmpblock, predkey, predkeylen, &item ); + if( rc ) + { + if( pbl_errno == PBL_ERROR_NOFIT ) + { + pbl_errno = 0; + return( 0 ); + } + + return( rc ); + } + + predkeylen = item.keylen; + if( predkeylen > 0 ) + { + pbl_memlcpy( predkey, sizeof( predkey ), item.key, predkeylen ); + } + } + + /* + * copy the values back to our original block + */ + block->nentries = tmpblock.nentries; + block->free = tmpblock.free; + memcpy( block->data, tmpblock.data, PBLDATASIZE ); + + block->dirty = 1; + + /* + * change values to the current record if they point to the right block + */ + if( file->blockno == from->blockno ) + { + /* + * set the current record values to the left block + */ + file->blockno = block->blockno; + file->index += nentries; + } + + return( 1 ); +} + +static long pblBlockAppend( +PBLKFILE_t * file, +int level, +long nblock, +long pblock +) +{ + PBLBLOCK_t * rootblock = 0; + PBLBLOCK_t * block = 0; + long freeblockno = 0; + + /* + * if nblock is 1, we are called to create the first block of a file + * no need to try to read any block of the file + */ + if( nblock != 1 && pblock != 1 ) + { + /* + * get the root block to memory + */ + rootblock = pblBlockGetWriteable( file, 0 ); + if( !rootblock ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read block number of first free block of file + */ + freeblockno = rootblock->pblock; + if( freeblockno ) + { + /* + * read the free block + */ + block = pblBlockGetWriteable( file, freeblockno ); + if( block ) + { + if( block->level != 254 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * set the next free block to the rootblock + */ + rootblock->pblock = block->nblock; + if( !rootblock->pblock && block->pblock ) + { + /* + * the block read is a new block, + * set the next block of the root block to a big value + */ + rootblock->pblock = block->pblock; + } + + rootblock->dirty = 1; + } + else + { + /* + * no error, append a new block + */ + pbl_errno = 0; + freeblockno += 1; + } + } + } + + if( !block ) + { + PBLBLOCK_t newblock; + + /* + * init the new block + */ + memset( &newblock, 0, sizeof( newblock )); + + /* + * add a free block + */ + newblock.level = ( char ) 254 & 0xff; + + /* + * new blocks appended have their next block set to 0 + * and their previous block set to the highest free block + * + * blocks freed always set the pblock to 0 + */ + newblock.nblock = 0; + newblock.pblock = freeblockno;; + newblock.free = PBLHEADERSIZE; + + /* + * prepare the new block for writing + */ + pblDataToBlock( &newblock ); + + /* + * append a new block to the file + */ + freeblockno = pbf_blockappend( file->bf, newblock.data ); + if( freeblockno < 0 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + /* + * read the free block + */ + block = pblBlockGetWriteable( file, freeblockno ); + if( !block || block->level != 254 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + if( rootblock ) + { + /* + * set the next free block to the rootblock + */ + rootblock->pblock = block->pblock; + if( !rootblock->pblock ) + { + rootblock->pblock = 1; + } + rootblock->dirty = 1; + } + } + + /* + * init the new block + */ + memset( block->data, 0, PBLDATASIZE ); + + block->level = ( char ) level & 0xff; + block->nentries = 0; + block->nblock = nblock; + block->pblock = pblock; + block->free = PBLHEADERSIZE; + block->dirty = 1; + + return( block->blockno ); +} + +static int pblBlockMerge( +PBLKFILE_t * file, +long parentblockno, +int parentindex, +long blockno +) +{ + int merged = 0; + PBLBLOCK_t * parentblock; + PBLBLOCK_t * block; + PBLBLOCK_t * peerblock; + PBLITEM_t item; + int rc; + unsigned char key[ PBLKEYLENGTH ]; + unsigned int keylen; + + /* + * read the parentblock + */ + parentblock = pblBlockGet( file, parentblockno ); + if( !parentblock ) + { + /* + * no error because the parent block might have been split + */ + pbl_errno = 0; + return( merged ); + } + + /* + * check the parentindex because the parentblock might have been + * split without the child knowing about it + */ + if( parentindex >= (int)parentblock->nentries ) + { + return( merged ); + } + + /* + * read the item pointing to blockno + */ + if( pblItemGet( parentblock, parentindex, &item )) + { + return( -1 ); + } + + /* + * check the pointer to the child, because the parentblock might have been + * split without the child knowing about it + */ + if( blockno != item.datablock ) + { + return( merged ); + } + + /* + * if there is a block to the left + */ + while( parentindex > 0 ) + { + /* + * check the parentindex because the parentblock might have been + * split without the child knowing about it + */ + if( parentindex >= (int)parentblock->nentries ) + { + return( merged ); + } + + /* + * read the item pointing to blockno + */ + if( pblItemGet( parentblock, parentindex, &item )) + { + return( -1 ); + } + + /* + * set the pointer to the child + */ + blockno = item.datablock; + + /* + * read the child block + */ + block = pblBlockGet( file, blockno ); + if( !block ) + { + return( -1 ); + } + + /* + * read the item pointing to the peer + */ + if( pblItemGet( parentblock, parentindex - 1, &item )) + { + return( -1 ); + } + + /* + * read the peerblock + */ + peerblock = pblBlockGet( file, item.datablock ); + if( !peerblock ) + { + return( -1 ); + } + + /* + * see how much empty space we have on the two blocks + */ + rc = PBLINDEXBLOCKNFREE( block ) + PBLINDEXBLOCKNFREE( peerblock ); + if( rc < ( PBLDATASIZE + 6 + PBLKEYLENGTH )) + { + /* + * we do not merge + */ + break; + } + + /* + * read the child block + */ + block = pblBlockGetWriteable( file, blockno ); + if( !block ) + { + return( -1 ); + } + + /* + * read the peerblock + */ + peerblock = pblBlockGetWriteable( file, item.datablock ); + if( !peerblock ) + { + return( -1 ); + } + + /* + * read the first key of the right block to merge + */ + parentblock = pblBlockGetWriteable( file, parentblockno ); + if( !parentblock ) + { + return( -1 ); + } + + /* + * check the parentindex + */ + if( parentindex >= (int)parentblock->nentries ) + { + return( merged ); + } + + if( pblBlockKeysExpand( parentblock )) + { + return( -1 ); + } + + /* + * read the item pointing to blockno + */ + if( pblItemGet( parentblock, parentindex, &item )) + { + return( -1 ); + } + + if( item.keylen < 1 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + keylen = item.keylen; + pbl_memlcpy( key, sizeof( key ), item.key, keylen ); + + /* + * concatenate the two blocks + */ + rc = pblBlockConcat( file, peerblock, block, key, keylen ); + if( rc < 0 ) + { + return( rc ); + } + else if( rc == 0 ) + { + /* + * we could not merge, break the loop + */ + break; + } + + /* + * the two blocks were merged + */ + merged += 1; + + /* + * free the block + */ + rc = pblBlockFree( file, blockno ); + if( rc ) + { + return( rc ); + } + + rc = pblItemRemove( parentblock, parentindex ); + if( rc ) + { + return( rc ); + } + } + + /* + * if there is a block to the left + */ + while( parentindex < (int)parentblock->nentries - 1 ) + { + /* + * read the item pointing to blockno + */ + if( pblItemGet( parentblock, parentindex, &item )) + { + return( -1 ); + } + + /* + * set the pointer to the child + */ + blockno = item.datablock; + + /* + * read the child block + */ + block = pblBlockGet( file, blockno ); + if( !block ) + { + return( -1 ); + } + + /* + * read the item pointing to the peer + */ + if( pblItemGet( parentblock, parentindex + 1, &item )) + { + return( -1 ); + } + + /* + * read the peerblock + */ + peerblock = pblBlockGet( file, item.datablock ); + if( !peerblock ) + { + return( -1 ); + } + + /* + * see how much empty space we have on the two blocks + */ + rc = PBLINDEXBLOCKNFREE( block ) + PBLINDEXBLOCKNFREE( peerblock ); + if( rc < ( PBLDATASIZE + 6 + PBLKEYLENGTH )) + { + /* + * we do not merge + */ + break; + } + + /* + * read the child block + */ + block = pblBlockGetWriteable( file, blockno ); + if( !block ) + { + return( -1 ); + } + + /* + * read the peerblock + */ + blockno = item.datablock; + peerblock = pblBlockGetWriteable( file, blockno ); + if( !peerblock ) + { + return( -1 ); + } + + /* + * read the first key of the right block to merge + */ + parentblock = pblBlockGetWriteable( file, parentblockno ); + if( !parentblock ) + { + return( -1 ); + } + + /* + * check the parentindex + */ + if( parentindex >= (int)parentblock->nentries - 1 ) + { + return( merged ); + } + + if( pblBlockKeysExpand( parentblock )) + { + return( -1 ); + } + + /* + * read the item pointing to blockno + */ + if( pblItemGet( parentblock, parentindex + 1, &item )) + { + return( -1 ); + } + + if( item.keylen < 1 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + keylen = item.keylen; + pbl_memlcpy( key, sizeof( key ), item.key, keylen ); + + /* + * concatenate the two blocks + */ + rc = pblBlockConcat( file, block, peerblock, key, keylen ); + if( rc < 0 ) + { + return( rc ); + } + else if( rc == 0 ) + { + /* + * we could not merge, break the loop + */ + break; + } + + /* + * the two blocks were merged + */ + merged += 1; + + /* + * free the block + */ + rc = pblBlockFree( file, blockno ); + if( rc ) + { + return( rc ); + } + + rc = pblItemRemove( parentblock, parentindex + 1 ); + if( rc ) + { + return( rc ); + } + } + + return( merged ); +} + +/* + * truncate the blocklist to the number of blocks allowed + */ +static int pblBlockListTruncate( void ) +{ + PBLBLOCK_t * block; + int rc; + + /* + * truncate the list of blocks we have in memory + */ + while( pblnblocks >= 8 + ( pblblocksperfile * pblnfiles ) ) + { + block = blockListTail; + if( !block ) + { + pblnblocks = 0; + break; + } + + if( block->bf != -1 ) + { + if( block->dirty ) + { + /* + * if one block of a file is dirty, all blocks are flushed + */ + rc = pblBlockFlush( block->bf, 0 ); + if( rc ) + { + return( rc ); + } + } + + pblBlockHashRemove( block->blockno, block->bf ); + } + + PBL_LIST_UNLINK( blockListHead, blockListTail, block, next, prev ); + pblBlockKeysRelease( block ); + PBL_FREE( block ); + + pblnblocks--; + } + + return( 0 ); +} + +/** + * change the number of cache blocks used per open key file + * + * the default number is 64, a memory block uses about 4096 bytes of heap memory + * + * @return int rc: the number of blocks used after the call + * + * + */ + +int pblKfInit( +int nblocks /* number of blocks used per open file */ +) +{ + pbl_errno = 0; + + if( nblocks < 1 ) + { + return( pblnblocks ); + } + + if( nblocks < 8 ) + { + nblocks = 8; + } + + pblblocksperfile = nblocks; + pblexpandedperfile = pblblocksperfile / 2; + + return( pblblocksperfile ); +} + +/* + * FILE functions + */ +static long pblDataAppend( +PBLKFILE_t * file, +char * data, +long datalen, +long * offset +) +{ + long blockno; + long returnoffset; + long returnblock; + long diff; + long bytesWritten = 0; + int nbytes; + PBLBLOCK_t * rootblock = 0; + PBLBLOCK_t * datablock = 0; + + rootblock = pblBlockGet( file, 0 ); + if( !rootblock ) + { + return( -1 ); + } + + /* + * rootblock->nblock always contains the number of the last datablock + */ + datablock = pblBlockGetWriteable( file, rootblock->nblock ); + if( !datablock ) + { + return( -1 ); + } + + if( datablock->level != 255 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + returnoffset = datablock->free; + returnblock = datablock->blockno; + + while( bytesWritten < datalen ) + { + diff = datalen - bytesWritten; + if( diff > PBLDATABLOCKNFREE( datablock )) + { + nbytes = PBLDATABLOCKNFREE( datablock ); + } + else + { + nbytes = (( int )( diff % PBLDATASIZE)); + } + + if( nbytes > 0 ) + { + memcpy((void *) &(datablock->data[ datablock->free ]), + (void *) data, + nbytes ); + datablock->dirty = 1; + } + + bytesWritten += nbytes; + data += nbytes; + datablock->free += nbytes; + + if( PBLDATABLOCKNFREE( datablock ) < 1 ) + { + /* + * make a new data block + */ + blockno = pblBlockAppend( file, -1, 0, datablock->blockno ); + if( blockno < 0 ) + { + return( -1 ); + } + + datablock->nblock = blockno; + datablock->dirty = 1; + + /* + * get the new datablock to memory + */ + datablock = pblBlockGetWriteable( file, blockno ); + if( !datablock ) + { + return( -1 ); + } + + /* + * set address to rootblock + */ + rootblock = pblBlockGetWriteable( file, 0 ); + if( !rootblock ) + { + return( -1 ); + } + + rootblock->nblock = blockno; + rootblock->dirty = 1; + } + } + + *offset = returnoffset; + + return( returnblock ); +} + +/** + * create a key file with the name specified by path. + * + * a file set tag can be attached to the file, + * if a file having a non NULL file set tag is flushed + * to disk all files having the same file set tag attached + * are flushed as well. + * + *

+ * RESTRICTIONS: + *
- the file to create must not exists. + *
- the current record of the file will not be set + * + * @return pblKeyFile_t * retptr == NULL: an error occured, see pbl_errno + * @return pblKeyFile_t * retptr != NULL: a pointer to a key file descriptor + */ + +pblKeyFile_t * pblKfCreate( +char * path, /** path of file to create */ +void * filesettag /** file set tag, for flushing multiple files consistently */ +) +{ + pblKeyFile_t * k = NULL; + PBLKFILE_t * kf = NULL; + PBLBLOCK_t * rootblock = NULL; + PBLITEM_t item; + int fh; + int bf; + long blockno; + int rc; + + pbl_errno = 0; + + /* + * make sure we have one filehandle for the create, close one file + */ + if( pbf_ft_tail ) + { + pbf_fh_close( pbf_ft_tail->bf, pbf_ft_tail->n ); + } + + /* + * do a exclusive create open, make sure the file does not exist yet + */ + fh = open( path, O_CREAT | O_EXCL | O_BINARY | O_RDWR, S_IREAD | S_IWRITE ); + if( -1 == fh ) + { + pbl_errno = PBL_ERROR_CREATE; + return( 0 ); + } + close( fh ); + + /* + * open the file + */ + bf = pbf_open( path, 1, PBLFILEBLOCKS, PBLDATASIZE ); + if( bf < 0 ) + { + return( 0 ); + } + + /* + * get and init file structure + */ + kf = pbl_malloc0( "pblKfCreate FILE", sizeof( PBLKFILE_t )); + if( !kf ) + { + goto errout; + } + + /* + * we have a key file set the return value + */ + k = ( pblKeyFile_t * )kf; + kf->magic = rcsid; + kf->bf = bf; + kf->update = 1; + kf->filesettag = filesettag; + + /* + * start a transaction on the file + */ + pblKfStartTransaction( k ); + + /* + * make the root block, next offset is first data block + */ + blockno = pblBlockAppend( kf, 0, 1, 1 ); + if( blockno < 0 ) + { + goto errout; + } + + rootblock = pblBlockGet( kf, 0 ); + if( !rootblock ) + { + goto errout; + } + + /* + * make the first data block + */ + blockno = pblBlockAppend( kf, -1, 0, 0 ); + if( blockno != 1 ) + { + goto errout; + } + + /* + * init the first item we insert into each file + */ + item.level = 0; + item.key = ( char * ) 0; + item.keylen = 0; + item.keycommon = 0; + item.datalen = strlen( magic ) + 1; + item.data = magic; + + /* + * append the magic string as first data item + */ + if( item.datalen > PBLDATALENGTH ) + { + item.datablock = pblDataAppend( kf, item.data, + item.datalen, &item.dataoffset ); + if( item.datablock < 1 ) + { + goto errout; + } + item.data = 0; + } + + /* + * insert the first item into the root block + */ + rootblock = pblBlockGetWriteable( kf, 0 ); + if( !rootblock ) + { + goto errout; + } + + rc = pblItemAdd( kf, rootblock, &item ); + if( rc ) + { + goto errout; + } + + /* + * no current record yet + */ + kf->blockno = -1; + kf->index = -1; + + /* + * commit the changes + */ + if( pblKfCommit( k, 0 )) + { + goto errout; + } + + if( pblBlockFlush( kf->bf, 0 )) + { + goto errout; + } + + pblnfiles++; + + return( k ); + +errout: + + if( kf ) + { + if( kf->bf >= 0 ) + { + pblKfCommit( k, 1 ); + } + PBL_FREE( kf ); + } + + if( -1 != bf ) + { + pblBlocksRelease( bf ); + close( fh ); + unlink( path ); + } + + return( 0 ); +} + +/** + * open an existing key file + * + * if update is 0, the file is opened for read access only, + * if update is not 0 the file is opened for reading and writing + * + * a file set tag can be attached to the file, + * if a file having a non NULL file set tag is flushed + * to disk all files having the same file set tag attached + * are flushed as well. + * + *

+ * RESTRICTIONS: + *
- the file must exist already + *
- the current record of the file will not be set + * + * @return pblKeyFile_t * retptr == NULL: an error occured, see pbl_errno + * @return pblKeyFile_t * retptr != NULL: a pointer to a key file descriptor + */ + +pblKeyFile_t * pblKfOpen( +char * path, /** path of file to create */ +int update, /** flag: should file be opened for update? */ +void * filesettag /** file set tag, for flushing multiple files consistently */ +) +{ + PBLKFILE_t * kf; + PBLBLOCK_t * datablock; + int bf; + + pbl_errno = 0; + + bf = pbf_open( path, update, PBLFILEBLOCKS, PBLDATASIZE ); + if( -1 == bf ) + { + return( 0 ); + } + + /* + * get and init file structure + */ + kf = pbl_malloc0( "pblKfOpen FILE", sizeof( PBLKFILE_t )); + if( !kf ) + { + pbf_close( bf ); + return( 0 ); + } + kf->magic = rcsid; + kf->bf = bf; + kf->update = update; + kf->filesettag = filesettag; + kf->blockno = -1; + kf->index = -1; + + /* + * read and check the first datablock + */ + datablock = pblBlockGet( kf, 1 ); + if( !datablock || ( datablock->level != 255 )) + { + pblBlocksRelease( bf ); + pbf_close( bf ); + PBL_FREE( kf ); + pbl_errno = PBL_ERROR_BAD_FILE; + return( 0 ); + } + + pblnfiles++; + + return( ( pblKeyFile_t * ) kf ); +} + +/** + * close a key file + * + * all changes are flushed to disk before, + * all memory allocated for the file is released. + * + * @return int rc == 0: call went ok, file is closed + * @return int rc != 0: some error, see pbl_errno + */ + +int pblKfClose( +pblKeyFile_t * k /** key file to close */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + int rc = 0; + + pbl_errno = 0; + + if( kf->update ) + { + rc = pblBlockFlush( kf->bf, 1 ); + } + else + { + pblBlocksRelease( kf->bf ); + } + + pbf_close( kf->bf ); + PBL_FREE( kf ); + + pblnfiles--; + + if( pblBlockListTruncate()) + { + rc = -1; + } + + return( rc ); +} + +/** + * set an application specific compare function for the keys of a key file + * + * an application specific compare function can be used in order to + * implement special orderings of the values of an index, e.g. + * because of the use of european "umlauts" in names + * + * the default compare function is the c-library memcmp function + * the keycompare function should behave like memcmp + * + * @return void + */ + +void pblKfSetCompareFunction( +pblKeyFile_t * k, /** key file to set compare function for */ +int ( *keycompare ) /** compare function to set */ + ( + void* left, /** "left" buffer for compare */ + size_t llen, /** length of that buffer */ + void* right, /** "right" buffer for compare */ + size_t rlen /** length of that buffer */ + ) +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + + kf->keycompare = keycompare; +} + +/** + * flush a key file + * + * all changes are flushed to disk, + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error, see pbl_errno + */ + +int pblKfFlush( +pblKeyFile_t * k /** key file to flush */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + int rc; + + pbl_errno = 0; + + rc = pblBlockFlush( kf->bf, 0 ); + if( rc ) + { + return( rc ); + } + + rc = pblBlockListTruncate(); + + return( rc ); +} + +/** + * commit or rollback changes done during a transaction. + * + * transactions can be nested, if so the commit + * only happens when the outermost transaction + * calls a commit. + * + * the commit only happens to process space buffer cache, + * call \Ref{pblKfFlush}() after \Ref{pblKfCommit}() if you want to + * flush to kernel space buffer cache. + * + * @return int rc == 0: the commit went ok + * @return int rc > 0: a rollback happened, either because the caller + * requested it or because an inner transaction resulted + * in a rollback + * @return int rc < 0: some error, see pbl_errno + */ + +int pblKfCommit( +pblKeyFile_t * k, /** key file to commit */ +int rollback /** != 0: roll back the changes, == 0: commit the changes */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + PBLBLOCK_t * block; + PBLBLOCK_t * b; + + pbl_errno = 0; + + /* + * if there is no transaction active for the file + */ + if( !rollback && ( kf->transactions < 1 )) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( -1 ); + } + kf->transactions--; + + /* + * if a rollback is requested for this commit + */ + if( rollback ) + { + /* + * remember that at least one rollback is requested for the file + */ + kf->rollback = 1; + } + + /* + * if there is an outer transaction active for the file + */ + if( kf->transactions > 0 ) + { + return( kf->rollback ); + } + + /* + * there is no more transaction active, rollback or commit + */ + if( kf->rollback ) + { + /* + * release all blocks that were changed without putting + * them back into the blocklist buffer cache + */ + while(( block = kf->writeableListTail )) + { + PBL_LIST_UNLINK( kf->writeableListHead, kf->writeableListTail, + block, next, prev ); + pblBlockKeysRelease( block ); + PBL_FREE( block ); + continue; + } + + /* + * reset the transaction and the rollback value + */ + kf->transactions = 0; + kf->rollback = 0; + return( 1 ); + } + + /* + * commit the changed blocks + */ + while(( block = kf->writeableListTail )) + { + /* + * commit all blocks that were changed by rechaining + * them into the blocklist buffer cache + */ + PBL_LIST_UNLINK( kf->writeableListHead, kf->writeableListTail, + block, next, prev ); + + /* + * find a potential copy of the block in the LRU list + */ + b = pblBlockFind( kf, block->blockno ); + if( b ) + { + /* + * delete the copy from the LRU list + */ + PBL_LIST_UNLINK( blockListHead, blockListTail, b, next, prev ); + pblBlockKeysRelease( b ); + PBL_FREE( b ); + } + else + { + /* + * we add a block to the LRU list + */ + pblnblocks++; + } + + /* + * blocks in the buffer cache are not writeable + */ + block->writeable = 0; + PBL_LIST_PUSH( blockListHead, blockListTail, block, next, prev ); + + /* + * insert or update the reference in the hash table + */ + if( pblBlockHashInsert( block->blockno, block->bf, block ) < 0 ) + { + pbl_errno = PBL_ERROR_PROGRAM; + return( 0 ); + } + } + + /* + * reset the transaction and the rollback value + */ + kf->transactions = 0; + kf->rollback = 0; + + return( 0 ); +} + +/** + * start a transaction on a key file + * + * transactions can be nested + * + * @return int rc == 0: the transaction was started successfully + * @return int rc > 0: the transaction was started + * but another transaction has resulted in + * a rollback request on the file already + */ + +int pblKfStartTransaction( +pblKeyFile_t * k /** key file to start transaction on */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + pbl_errno = 0; + + /* + * if there is no transaction active for the file + */ + if( kf->transactions < 1 ) + { + kf->transactions = 1; + kf->rollback = 0; + return( 0 ); + } + kf->transactions++; + + return( kf->rollback ); +} + +/** + * save the position of the current record for later restore + * + * @return int rc == 0: the position was saved + * @return int rc < 0: an error, see pbl_errno + */ +int pblKfSavePosition( +pblKeyFile_t * k /** key file to save position for */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + + pbl_errno = 0; + + /* + * save the block number and the index + */ + kf->saveblockno = kf->blockno; + kf->saveindex = kf->index; + + return( 0 ); +} + +/** + * restore the position of the current record saved by the + * last previous call to \Ref{pblKfSavePosition}(). + * + * @return int rc == 0: the position was restored + * @return int rc < 0: an error, see pbl_errno + */ + +int pblKfRestorePosition( +pblKeyFile_t * k /** key file to restore position for */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + + /* + * restore the block number and the index + */ + kf->blockno = kf->saveblockno; + kf->index = kf->saveindex; + + return( 0 ); +} + +/* + * INSERT functions + */ +static int pblItemSave( PBLITEM_t * item ) +{ + PBLITEM_t * newitem = ( PBLITEM_t * ) 0; + + newitem = pbl_malloc0( "pblItemSave ITEM", sizeof( PBLITEM_t )); + if( !newitem ) + { + return( -1 ); + } + + /* + * save the values of the item + */ + *newitem = *item; + + /* + * save the key + */ + if( newitem->keylen > 0 ) + { + newitem->key = pbl_memdup( "pblItemSave item->key", + item->key, newitem->keylen ); + if( !newitem->key ) + { + PBL_FREE( newitem ); + return( -1 ); + } + } + else + { + newitem->key = 0; + } + + /* + * save the data + */ + if( newitem->datalen < 1 || newitem->datalen > PBLDATALENGTH ) + { + newitem->data = 0; + } + + /* + * push the new item to top of list + */ + PBL_LIST_PUSH( itemListHead, itemListTail, newitem, next, prev ); + + return( 0 ); +} + +static void pblItemRelease( void ) +{ + PBLITEM_t * item; + + if(( item = itemListHead )) + { + PBL_LIST_UNLINK( itemListHead, itemListTail, item, next, prev ); + + if( item->key ) + { + PBL_FREE( item->key ); + } + PBL_FREE( item ); + } +} + +static void pblItemReleaseAll( void ) +{ + while( itemListHead ) + { + pblItemRelease( ); + } +} + +#if 1 + +static int pblSplit( PBLKFILE_t *file, PBLBLOCK_t * block ) +{ + unsigned int index; + PBLITEM_t splititem; + PBLITEM_t item; + PBLBLOCK_t tmpblock; + PBLBLOCK_t *newblock; + PBLBLOCK_t *target; + unsigned char *predkey = ""; + unsigned int predkeylen = 0; + long newblockno; + int rc; + + /* + * create a new block + */ + newblockno = pblBlockAppend( file, block->level, + block->nblock, block->blockno ); + if( newblockno < 0 ) + { + return( -1 ); + } + + /* + * set backward pointer in successor block of block + */ + if( block->nblock ) + { + newblock = pblBlockGetWriteable( file, block->nblock ); + if( !newblock ) + { + return( -1 ); + } + + newblock->pblock = newblockno; + newblock->dirty = 1; + } + + /* + * get the new block to memory + */ + newblock = pblBlockGetWriteable( file, newblockno ); + if( !newblock ) + { + return( -1 ); + } + + /* + * copy the block to split onto the stack + */ + pblBlockKeysRelease( block ); + tmpblock = *block; + + /* + * prepare the block for split + */ + block->nblock = newblockno; + block->nentries = 0; + block->free = PBLHEADERSIZE; + block->dirty = 1; + memset( block->data, 0, PBLDATASIZE ); + + tmpblock.expandedkeys = 0; + if( pblBlockKeysExpand( &tmpblock )) + { + return( -1 ); + } + + /* + * copy the items from tmpblock to our two real blocks + */ + for( target = block, index = 0; index < tmpblock.nentries; index++ ) + { + rc = pblItemGet( &tmpblock, index, &item ); + if( rc ) + { + pblBlockKeysRelease( &tmpblock ); + return( -1 ); + } + + /* + * if first block we copy to is more than half full + */ + if( ( target == block ) + && (( PBLINDEXBLOCKNFREE( block ) < ( PBLDATASIZE / 2 )) + || ( index == tmpblock.nentries - 1 ))) + { + /* + * the first item that goes to the new second block has to be + * saved for later insert into the father block of the new block + */ + splititem = item; + splititem.datalen = 0; + splititem.datablock = newblockno; + splititem.dataoffset = 0; + splititem.level++; + + rc = pblItemSave( &splititem ); + if( rc ) + { + pblBlockKeysRelease( &tmpblock ); + return( -1 ); + } + + /* + * for blocks of level greater than 0 the first item on each block + * has keylength 0 + */ + if( tmpblock.level > 0 ) + { + item.keylen = 0; + } + + /* + * from now on copy to the second block + */ + target = newblock; + predkeylen = 0; + } + + rc = pblItemAppend( target, predkey, predkeylen, &item ); + if( rc < 0 ) + { + pblBlockKeysRelease( &tmpblock ); + return( -1 ); + } + + predkeylen = item.keylen; + if( predkeylen > 0 ) + { + predkey = item.key; + } + else + { + predkey = ""; + } + } + + pblBlockKeysRelease( &tmpblock ); + + /* + * set the parent pointers to the new block + */ + newblock->parentblock = block->parentblock; + newblock->parentindex = block->parentindex + 1; + + return( 0 ); +} + +#else + +static int pblSplit( PBLKFILE_t * file, PBLBLOCK_t * block ) +{ + unsigned int index; + int splitindex = 0; + PBLITEM_t splititem; + PBLITEM_t item; + PBLBLOCK_t *newblock; + PBLBLOCK_t *target; + unsigned char *predkey = ""; + unsigned int predkeylen = 0; + long newblockno; + int rc; + int blockfree = PBLHEADERSIZE; + + /* + * create a new block + */ + newblockno = pblBlockAppend( file, block->level, + block->nblock, block->blockno ); + if( newblockno < 0 ) + { + return( -1 ); + } + + /* + * set backward pointer in successor block of block + */ + if( block->nblock ) + { + newblock = pblBlockGetWriteable( file, block->nblock ); + if( !newblock ) + { + return( -1 ); + } + + newblock->pblock = newblockno; + newblock->dirty = 1; + } + + /* + * get the new block to memory + */ + newblock = pblBlockGetWriteable( file, newblockno ); + if( !newblock ) + { + return( -1 ); + } + + /* + * expand the keys of the block to split + */ + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + + /* + * prepare the block for split + */ + block->nblock = newblockno; + + /* + * copy the items from the block to our new block + */ + for( target = block, index = 0; index < block->nentries; index++ ) + { + rc = pblItemGet( block, index, &item ); + if( rc ) + { + return( -1 ); + } + + if( target == block ) + { + /* + * calculate the size the items need on the block so far + */ + blockfree += pblItemSize( block, &item ); + + /* + * if first block we copy to is more than half full + */ + if( ( blockfree > ( PBLDATASIZE / 2 )) + || ( index == block->nentries - 1 )) + { + /* + * the first item that goes to the new second block has to be + * saved for later insert into the father block of the new block + */ + splitindex = index; + splititem = item; + splititem.datalen = 0; + splititem.datablock = newblockno; + splititem.dataoffset = 0; + splititem.level++; + + rc = pblItemSave( &splititem ); + if( rc ) + { + return( -1 ); + } + + /* + * for blocks of level greater than 0 the first item + * on each block has keylength 0 + */ + if( block->level > 0 ) + { + item.keylen = 0; + } + + /* + * from now on copy to the second block + */ + target = newblock; + predkeylen = 0; + } + } + + /* + * only copy to the new block if the target is right + */ + if( target == newblock ) + { + rc = pblItemAppend( target, predkey, predkeylen, &item ); + if( rc < 0 ) + { + return( -1 ); + } + + /* + * remember the key of the predecessor item + */ + predkeylen = item.keylen; + if( predkeylen > 0 ) + { + predkey = item.key; + } + else + { + predkey = ""; + } + } + } + + /* + * delete the items that were copied from the block + */ + for( index = block->nentries - 1; index >= splitindex; index-- ) + { + rc = pblItemDelete( block, index ); + if( rc ) + { + return( -1 ); + } + } + + /* + * set the parent pointers to the new block + */ + newblock->parentblock = block->parentblock; + newblock->parentindex = block->parentindex + 1; + + return( 0 ); +} + +#endif + +static int pblSplitRoot( PBLKFILE_t *file ) +{ + PBLBLOCK_t * rootblock; + PBLITEM_t item; + PBLBLOCK_t * newblock; + long newblockno; + int rc; + + /* + * get the root block to memory + */ + rootblock = pblBlockGetWriteable( file, 0 ); + if( !rootblock ) + { + return( -1 ); + } + pblBlockKeysRelease( rootblock ); + + /* + * create a new block and get it to memory + */ + newblockno = pblBlockAppend( file, rootblock->level, 0, 0 ); + if( newblockno < 0 ) + { + return( -1 ); + } + + newblock = pblBlockGetWriteable( file, newblockno ); + if( !newblock ) + { + return( -1 ); + } + + /* + * copy some data of the root block to the new block + */ + newblock->nentries = rootblock->nentries; + newblock->free = rootblock->free; + memcpy( newblock->data, rootblock->data, PBLDATASIZE ); + + newblock->dirty = 1; + + /* + * get the root block to memory + */ + rootblock = pblBlockGetWriteable( file, 0 ); + if( !rootblock ) + { + return( -1 ); + } + + /* + * clear the root block + */ + rootblock->level += 1; + rootblock->nentries = 0; + rootblock->free = PBLHEADERSIZE; + rootblock->dirty = 1; + memset( rootblock->data, 0, PBLDATASIZE ); + + newblock = pblBlockGetWriteable( file, newblockno ); + if( !newblock ) + { + return( -1 ); + } + + /* + * copy the first item from new block to the root block + */ + rc = pblItemGet( newblock, 0, &item ); + if( rc ) + { + return( -1 ); + } + + item.level = rootblock->level; + item.keylen = 0; + item.datalen = 0; + item.datablock = newblockno; + item.dataoffset = 0; + + rc = pblItemAppend( rootblock, 0, 0, &item ); + if( rc < 0 ) + { + return( -1 ); + } + + /* + * set the parent pointers to the new block + */ + newblock->parentblock = 0; + newblock->parentindex = 0; + + /* + * split the new block + */ + return( pblSplit( file, newblock )); +} + +/** + * insert a new record with the given key and data into a key file, + * + * multiple records with the same key are allowed, + * if there are already records with the same key the new + * record will be inserted behind all records with the same key, + * + * the current record of the file will be set to the new record + * + *

+ * RESTRICTIONS: + *
- the file must be open for update, + *
- key must point to the key to be inserted, + *
- keylen must be bigger than 0 and smaller than 256, + *
- data must point to the data be inserted, + *
- datalen must not be negative, + *
- if datalen == 0, the pointer data is not evaluated at all + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error occured, see pbl_errno + */ + +int pblKfInsert( +pblKeyFile_t * k, /** key file to insert to */ +unsigned char * key, /** key to insert */ +int keylen, /** length of the key */ +unsigned char * data, /** data to insert */ +long datalen /** length of the data */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + PBLITEM_t item; + PBLITEM_t * insertitem; + PBLBLOCK_t * block; + long blockno; + int index; + int saveerrno; + int rc; + + long parentblock = -1; + int parentindex = -1; + int split = 0; + + pbl_errno = 0; + + /* + * start a transaction on the key file + */ + pblKfStartTransaction( k ); + if( pblBlockListTruncate()) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + if( !kf->update ) + { + pblKfCommit( k, 1 ); + pbl_errno = PBL_ERROR_NOT_ALLOWED; + return( -1 ); + } + + rc = pblParamsCheck( key, keylen, data, datalen ); + if( rc ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * only data that is longer than PBLDATALENGTH + * bytes is written to data blocks + */ + if( datalen > PBLDATALENGTH ) + { + /* + * append the data to the file + */ + item.datablock = pblDataAppend( kf, data, datalen, &item.dataoffset ); + if( item.datablock < 1 ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + item.data = 0; + } + else + { + item.datablock = 0; + item.dataoffset = 0; + item.data = data; + } + + /* + * prepare the data item to be inserted + */ + item.level = 0; + item.keylen = keylen; + item.keycommon = 0; + item.key = key; + item.datalen = datalen; + + /* + * push the item to the insert stack of the file + */ + rc = pblItemSave( &item ); + if( rc ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * insert all items that are on the insert stack + */ + while( itemListHead ) + { + insertitem = itemListHead; + + /* + * we always start the insert at the root block + */ + blockno = 0; + parentblock = -1; + parentindex = -1; + + /* + * handle all levels of the tree + */ + while( !pbl_errno ) + { + block = pblBlockGet( kf, blockno ); + if( !block ) + { + break; + } + + /* + * set the links to the parentblock of the block + */ + block->parentblock = parentblock; + block->parentindex = parentindex; + + /* + * if the item has to be inserted in this level + */ + if( block->level <= insertitem->level ) + { + block = pblBlockGetWriteable( kf, blockno ); + if( !block ) + { + break; + } + + index = pblItemAdd( kf, block, insertitem ); + if( index < 0 ) + { + if( pbl_errno == PBL_ERROR_NOFIT ) + { + pbl_errno = 0; + + /* + * split the root block or a normal block + */ + if( blockno ) + { + rc = pblSplit( kf, block ); + } + else + { + rc = pblSplitRoot( kf ); + } + if( !rc ) + { + split = 1; + } + } + break; + } + + /* + * insert was successful + */ + if( block->level == 0 ) + { + /* + * set values of current record + */ + kf->blockno = block->blockno; + kf->index = index; + } + + /* + * release the item that was inserted + */ + pblItemRelease( ); + + break; + } + + for(;;) + { + block = pblBlockGet( kf, blockno ); + if( !block ) + { + break; + } + + /* + * set the links to the parentblock of the block + */ + block->parentblock = parentblock; + block->parentindex = parentindex; + + if( pblBlockKeysExpand( block )) + { + break; + } + + /* + * item has to be inserted on a lower level, find out where + * + * we either insert into the last subtree, or into the + * greatest smaller subtree + */ + index = pblItemFind( kf, block, insertitem, PBLLA ); + if( index < 0 ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + index = pblItemFind( kf, block, insertitem, PBLLT ); + } + + if( index < 0 ) + { + break; + } + } + + rc = pblItemGet( block, index, &item ); + if( rc ) + { + break; + } + + /* + * see if we can merge blocks before the insert + */ + if( !split ) + { + rc = pblBlockMerge( kf, blockno, + index, item.datablock ); + if( rc > 0 ) + { + continue; + } + else if( rc < 0 ) + { + break; + } + } + + /* + * get the blockno of the relevant child block + */ + blockno = item.datablock; + parentblock = block->blockno; + parentindex = index; + + pbl_errno = 0; + break; + } + } + + /* + * if an error occurred during this insert + */ + if( pbl_errno ) + { + break; + } + } + + saveerrno = pbl_errno; + + pblItemReleaseAll( ); + + if( saveerrno ) + { + pbl_errno = saveerrno; + kf->blockno = -1; + kf->index = -1; + pblKfCommit( k, 1 ); + return( -1 ); + } + + pblKfCommit( k, 0 ); + return( 0 ); +} + +/* + * UPDATE functions + */ +static PBLBLOCK_t * pblPositionCheck( PBLKFILE_t *kf ) +{ + PBLBLOCK_t * block; + int index; + + /* + * check if the current block is set for the file + */ + if( kf->blockno < 0 ) + { + pbl_errno = PBL_ERROR_POSITION; + return( 0 ); + } + + /* + * get the current block to memory + */ + block = pblBlockGet( kf, kf->blockno ); + if( !block ) + { + return( 0 ); + } + index = kf->index; + + /* + * if we are positioned on our pseudo magic item, we set to next item + */ + if(( index == 0 ) && ( !block->pblock || !block->blockno )) + { + index = 1; + } + + /* + * if the index is negative, we actually are set on the last item of + * the predecessor of the current block, or if the there is no predecessor + * on the first item of the current block + */ + while( index < 0 ) + { + /* + * if we are on the first block, we need the second item, because the + * the first item is our pseudo magic item + */ + if( !block->pblock || !block->blockno ) + { + index = 1; + } + else + { + block = pblBlockGet( kf, block->pblock ); + if( !block ) + { + return( 0 ); + } + + if( block->nentries ) + { + index = block->nentries - 1; + } + } + } + + while( ( int )index >= ( int )block->nentries ) + { + /* + * if there is no successor of the current block, we have to stay here + * the rootblock never has a successor ! + */ + if( !block->nblock || !block->blockno ) + { + break; + } + else + { + block = pblBlockGet( kf, block->nblock ); + if( !block ) + { + return( 0 ); + } + + if( block->nentries ) + { + index = 0; + } + } + } + + while( ( int )index >= ( int )block->nentries ) + { + /* + * if the block has entries, we take the last one + */ + if( block->nentries ) + { + index = block->nentries - 1; + } + else if( !block->pblock || !block->blockno ) + { + /* + * this is a structure error, because the first block always has + * at least one item, our pseudo magic item + */ + pbl_errno = PBL_ERROR_BAD_FILE; + kf->blockno = -1; + return( 0 ); + } + else + { + block = pblBlockGet( kf, block->pblock ); + if( !block ) + { + return( 0 ); + } + + if( block->nentries ) + { + index = block->nentries - 1; + } + } + } + + /* + * if we ended up positioning at our pseudo item, the file does not + * have any other items + */ + if(( index == 0 ) && ( !block->pblock || !block->blockno )) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + kf->blockno = -1; + return( 0 ); + } + + kf->blockno = block->blockno; + kf->index = index; + + return( block ); +} + +static long pblDataWrite( +PBLKFILE_t * file, +char * data, +long blockno, +long blockoffset, +long datalen +) +{ + long diff; + long bytesWritten = 0; + int nbytes; + PBLBLOCK_t * datablock = (PBLBLOCK_t *) 0; + + while( bytesWritten < datalen ) + { + datablock = pblBlockGetWriteable( file, blockno ); + if( !datablock ) + { + return( -1 ); + } + + if( datablock->level != 255 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + diff = datalen - bytesWritten; + if( diff > ( PBLDATASIZE - blockoffset ) ) + { + nbytes = PBLDATASIZE - blockoffset; + } + else + { + nbytes = ((int ) ( diff % PBLDATASIZE)); + } + + if( nbytes > 0 ) + { + memcpy((void *) &(datablock->data[ blockoffset ]), + (void *) data, + nbytes ); + datablock->dirty = 1; + + bytesWritten += nbytes; + data += nbytes; + } + + if( bytesWritten < datalen ) + { + /* + * get offset of next block and set blockoffset to beginning of + * data + */ + blockno = datablock->nblock; + blockoffset = PBLHEADERSIZE; + } + } + + return( bytesWritten ); +} + +/** + * delete the current record of the key file. + * + * the current record of the file is set to the next record or + * if the last record is deleted, to the previous record, + * + * if there are no more records in the file after the delete + * the current record is of course unpositioned + * + *

+ * RESTRICTIONS: + *
- the file must be open for update, + *
- no space will be given back to the file system, + *
- if an index block and its successor or its predeccessor + * together use less than half of a block the two blocks are merged + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error occured, see pbl_errno + */ + +int pblKfDelete( +pblKeyFile_t * k /** key file to delete record from */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + long parentblock; + PBLBLOCK_t * block; + int rc; + + pbl_errno = 0; + + /* + * start a transaction on the key file + */ + pblKfStartTransaction( k ); + if( pblBlockListTruncate()) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + if( !kf->update ) + { + pblKfCommit( k, 1 ); + pbl_errno = PBL_ERROR_NOT_ALLOWED; + return( -1 ); + } + + /* + * make sure current record of the file is positioned + */ + block = pblPositionCheck( kf ); + if( !block ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * read the block the current item is on + */ + block = pblBlockGetWriteable( kf, kf->blockno ); + if( !block ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * delete the current item + */ + rc = pblItemRemove( block, kf->index ); + if( rc ) + { + pblKfCommit( k, 1 ); + return( rc ); + } + + /* + * we deleted an item, now see if we can merge some blocks + */ + for(;;) + { + if( block->parentblock < 0 || block->parentindex < 0 ) + { + rc = 0; + break; + } + + /* + * remember the blocknumber of the parent block + */ + parentblock = block->parentblock; + + /* + * see whether some blocks can be merged because of the delete + */ + rc = pblBlockMerge( kf, block->parentblock, + block->parentindex, block->blockno ); + if( rc < 1 ) + { + break; + } + + /* + * the merge deleted an item on the parent block, read that block + */ + block = pblBlockGetWriteable( kf, parentblock ); + if( !block ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + } + + if( rc ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + pblKfCommit( k, 0 ); + return( rc ); +} + +/** + * update the data of the current record + * + * the current record of the file is updated with the new data given + * + * + *

+ * RESTRICTIONS: + *
- the file must be open for update, + *
- if the new datalen of the record is not bigger than the old datalen, + * the data will be updated in place, otherwise the new data of the + * record will be appended to the file, the space previously used for + * the data of the record will not be reused in this case, + *
- data must point to the new data be inserted, + *
- datalen must not be negative, + *
- if datalen == 0, the pointer data is not evaluated at all + * + * @return int rc == 0: call went ok + * @return int rc != 0: some error occured, see pbl_errno + */ + +int pblKfUpdate( +pblKeyFile_t * k, /** key file to delete record from */ +unsigned char * data, /** new data to update with */ +long datalen /** length of the new data */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + PBLITEM_t item; + PBLBLOCK_t * block; + long rc; + unsigned char key[ PBLKEYLENGTH ]; + + pbl_errno = 0; + + /* + * start a transaction on the key file + */ + pblKfStartTransaction( k ); + if( pblBlockListTruncate()) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + if( !kf->update ) + { + pblKfCommit( k, 1 ); + pbl_errno = PBL_ERROR_NOT_ALLOWED; + return( -1 ); + } + + if( pblParamsCheck( (char*)1, 1, data, datalen )) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * make sure current record of the file is positioned + */ + block = pblPositionCheck( kf ); + if( !block ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * read the block the current item is on + */ + block = pblBlockGetWriteable( kf, kf->blockno ); + if( !block ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * read the item + */ + rc = pblItemGet( block, kf->index, &item ); + if( rc ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + if( datalen == item.datalen ) + { + /* + * if the data is to be stored on an index block + */ + if( datalen <= PBLDATALENGTH ) + { + /* + * update in place + */ + if( datalen > 0 ) + { + memcpy( item.data, data, datalen ); + block->dirty = 1; + } + + pblKfCommit( k, 0 ); + return( 0 ); + } + + /* + * update the data in place + */ + rc = pblDataWrite( kf, data, item.datablock, item.dataoffset, datalen ); + if( rc != datalen ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + pblKfCommit( k, 0 ); + return( 0 ); + } + + if( item.keycommon ) + { + if( pblBlockKeysExpand( block )) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + + /* + * read the item to get its real key + */ + rc = pblItemGet( block, kf->index, &item ); + if( rc ) + { + pblKfCommit( k, 1 ); + return( -1 ); + } + } + + /* + * we do a delete and an insert of the record + */ + item.keylen &= 0xff; + pbl_memlcpy( key, sizeof( key ), item.key, item.keylen ); + + rc = pblKfDelete( k ); + if( rc ) + { + pblKfCommit( k, 1 ); + return( rc ); + } + + rc = pblKfInsert( k, key, item.keylen, data, datalen ); + if( rc ) + { + pblKfCommit( k, 1 ); + return( rc ); + } + + pblKfCommit( k, 0 ); + + return( rc ); +} + +/* + * READ functions + */ +/* + * recursive find procedure for records + */ +static long pblFindRec( +PBLKFILE_t * kf, +int mode, +long blockno, +long parentblock, +int parentindex, +PBLITEM_t * item +) +{ + PBLITEM_t curitem; + PBLBLOCK_t * block; + int index; + long rc; + int which; + int direction; + + /* + * get the block to memory + */ + block = pblBlockGet( kf, blockno ); + if( !block ) + { + return( -1 ); + } + + block->parentblock = parentblock; + block->parentindex = parentindex; + + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + + /* + * level 0, terminate the recursion + */ + if( block->level == 0 ) + { + /* + * find the item on the block, first that matches + */ + index = pblItemFind( kf, block, item, mode ); + if( index < 0 ) + { + return( -1 ); + } + + /* + * make sure nobody is finding our pseudo record + */ + if(( index == 0 ) && ( !block->pblock || !block->blockno )) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + return( -1 ); + } + + rc = pblItemGet( block, index, &curitem ); + if( rc ) + { + return( -1 ); + } + + /* + * find was successful set values of current record + */ + kf->blockno = block->blockno; + kf->index = index; + + /* + * we return the datalength of the item + */ + return( curitem.datalen ); + } + + direction = 1; + switch( mode ) + { + case PBLLT: + which = PBLLT; + direction = -1; + break; + + case PBLFI: + case PBLEQ: + which = PBLLT; + break; + + case PBLLA: + case PBLGT: + which = PBLLA; + break; + + default: + pbl_errno = PBL_ERROR_PARAM_MODE; + return( -1 ); + } + + /* + * find the subtree where to continue the find + */ + index = pblItemFind( kf, block, item, which ); + if( index < 0 ) + { + if( which == PBLLA ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + pbl_errno = 0; + index = pblItemFind( kf, block, item, PBLLT ); + } + } + } + + /* + * search in all possible subtrees + */ + for( ; index >= 0 && index < (int)block->nentries; index += direction ) + { + /* + * check if subtree can contain the item + */ + rc = pblItemGet( block, index, &curitem ); + if( rc ) + { + return( -1 ); + } + + rc = pblItemCompare( kf, &curitem, item ); + if(( rc > 0 ) && ( mode != PBLGT )) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + return( -1 ); + } + + /* + * recursive call to find procedure + */ + rc = pblFindRec( kf, mode, curitem.datablock, blockno, index, item ); + if( rc >= 0 ) + { + /* + * find was successful + */ + return( rc ); + } + + /* + * if an error other than PBL_ERROR_NOT_FOUND occured, we give up + */ + if( pbl_errno != PBL_ERROR_NOT_FOUND ) + { + return( -1 ); + } + else + { + pbl_errno = 0; + } + + /* + * get the block to memory because during the recursive call + * it might have become a victim + */ + block = pblBlockGet( kf, blockno ); + if( !block ) + { + return( -1 ); + } + + block->parentblock = parentblock; + block->parentindex = parentindex; + + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + } + + /* + * couldn't find the item, tell the caller + */ + pbl_errno = PBL_ERROR_NOT_FOUND; + return( -1 ); +} + +static long pblDataGet( +PBLKFILE_t * file, +char * data, +long blockno, +long blockoffset, +long datalen +) +{ + long diff; + long bytesRead = 0; + int nbytes; + PBLBLOCK_t * datablock = (PBLBLOCK_t *) 0; + + while( bytesRead < datalen ) + { + datablock = pblBlockGet( file, blockno ); + if( !datablock ) + { + return( -1 ); + } + + if( datablock->level != 255 ) + { + pbl_errno = PBL_ERROR_BAD_FILE; + return( -1 ); + } + + diff = datalen - bytesRead; + if( diff > ( PBLDATASIZE - blockoffset ) ) + { + nbytes = PBLDATASIZE - blockoffset; + } + else + { + nbytes = ((int ) ( diff % PBLDATASIZE)); + } + + if( nbytes > 0 ) + { + memcpy((void *) data, + (void *) &(datablock->data[ blockoffset ]), + nbytes ); + + bytesRead += nbytes; + data += nbytes; + } + + if( bytesRead < datalen ) + { + /* + * get number of next block and set blockoffset to beginning of + * data + */ + blockno = datablock->nblock; + blockoffset = PBLHEADERSIZE; + } + } + + return( bytesRead ); +} + +/** + * find a record in a key file, set the current record + * + * parameter mode specifies which record to find relative + * to the search key specified by skey and skeylen. + * the following values for mode are possible + * + *
PBLEQ - find a record whose key is equal to skey + *
PBLFI - find the first record that is equal + *
PBLLA - find the last record that is equal + *
PBLGE - find the last record that is equal or the smallest + * record that is greater + *
PBLGT - find the smallest record that is greater + *
PBLLE - find the first record that is equal or the biggest + * record that is smaller + *
PBLLT - find the biggest record that is smaller + * + * keep in mind that PBL allows multiple records with the same key. + * + *

+ * RESTRICTIONS: + *
- the out parameter okey must point to a memory area that is + * big enough to hold any possible key, i.e 255 bytes + * + * @return long rc >= 0: + *

    + *
  • call went ok, + * the value returned is the length + * of the data of the record found, + *
  • the length of the key of the record is set in + * the out parameter okeylen, + *
  • the key of the record is copied to okey, + *
  • the current record of the file is set to the + * record found + *
+ * + * @return long rc < 0: + *
    + *
  • some error occured, see pbl_errno + * especially PBL_ERROR_NOT_FOUND, if there is no + * matching record + *
+ */ +long pblKfFind( +pblKeyFile_t * k, /** key file to search in */ +int mode, /** mode to use for search */ +unsigned char * skey, /** key to use for search */ +int skeylen, /** length of search key */ +unsigned char * okey, /** buffer for result key */ +int * okeylen /** length of the result key after return */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + PBLBLOCK_t * block; + PBLITEM_t item; + long rc; + int which; + + pbl_errno = 0; + + rc = pblParamsCheck( skey, skeylen, (char*)0, 0 ); + if( rc ) + { + return( -1 ); + } + + /* + * prepare the data item to be found + */ + memset( &item, 0, sizeof( item )); + item.keylen = skeylen; + item.key = skey; + + if( mode == PBLLE ) + { + which = PBLFI; + } + else if( mode == PBLGE ) + { + which = PBLLA; + } + else + { + which = mode; + } + + /* + * we always start the find at the root block + */ + rc = pblFindRec( kf, which, 0, -1, -1, &item ); + if( rc < 0 ) + { + if( pbl_errno == PBL_ERROR_NOT_FOUND ) + { + if( mode == PBLLE ) + { + rc = pblFindRec( kf, PBLLT, 0, -1, -1, &item ); + } + else if( mode == PBLGE ) + { + rc = pblFindRec( kf, PBLGT, 0, -1, -1, &item ); + } + } + } + + if( rc < 0 ) + { + return( -1 ); + } + + /* + * get the current block to memory + */ + block = pblBlockGet( kf, kf->blockno ); + if( !block ) + { + return( -1 ); + } + + /* + * if we need the key of the record + */ + if( okey ) + { + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + } + + /* + * read the item + */ + rc = pblItemGet( block, kf->index, &item ); + if( rc ) + { + return( -1 ); + } + + /* + * set the out parameters, if a buffer is supplied + */ + if( okey && okeylen ) + { + *okeylen = item.keylen; + pbl_memlcpy( okey, PBLKEYLENGTH, item.key, item.keylen ); + } + + return( item.datalen ); +} + +/** + * read the data of the current record of the file + * + * the caller can restrict the number of bytes read by + * specifying the maximum number of bytes to read by parameter + * datalen, if datalen is 0, all bytes stored for the + * current record are copied to the buffer pointed to by data. + *

+ * RESTRICTIONS: + *
- data must point to an area of memory being big enough to hold + * the bytes copied + *
- datalen must not be negative, it is ignored otherwise + * + * @return int rc == 0: call went ok, rc is the number of bytes copied + * @return int rc != 0: some error occured, see pbl_errno + */ + +long pblKfRead( +pblKeyFile_t * k, /** key file to read from */ +unsigned char * data, /** data to insert */ +long datalen /** length of the data */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + PBLITEM_t item; + PBLBLOCK_t * block; + long rc; + + pbl_errno = 0; + + rc = pblParamsCheck( (char*)1, 1, (char*)data, datalen ); + if( rc ) + { + return( -1 ); + } + + /* + * check position of current record + */ + block = pblPositionCheck( kf ); + if( !block ) + { + return( -1 ); + } + + /* + * read the item + */ + rc = pblItemGet( block, kf->index, &item ); + if( rc ) + { + return( -1 ); + } + + /* + * the caller can restrict the number of bytes read + */ + if( datalen > 0 ) + { + if( datalen > item.datalen ) + { + datalen = item.datalen; + } + } + else + { + datalen = item.datalen; + } + + /* + * if the data is stored on an index block + */ + if( datalen <= PBLDATALENGTH ) + { + memcpy( data, item.data, datalen ); + return( datalen ); + } + + /* + * the data is stored on a data block, read it from the file + */ + rc = pblDataGet( kf, data, item.datablock, item.dataoffset, datalen ); + if( rc != datalen ) + { + return( -1 ); + } + + return( datalen ); +} + +/** + * set current record to a record with a relative position index + * + * this function is only to be used through the macro functions: + * + *
\Ref{pblKfThis}( k, okey, okeylen ) read key of current record + *
\Ref{pblKfNext}( k, okey, okeylen ) read key of next record + *
\Ref{pblKfPrev}( k, okey, okeylen ) read key of previous record + * + * @return long rc >= 0: + *

    + *
  • call went ok, + * the value returned is the length + * of the data of the record found, + *
  • the length of the key of the record is set in + * the out parameter okeylen, + *
  • the key of the record is copied to okey, + *
  • the current record of the file is set to the + * record found + *
+ * + * @return long rc < 0: + *
    + *
  • some error occured, see pbl_errno + *
+ */ + +long pblKfGetRel( +pblKeyFile_t * k, /** key file to position in */ +long relindex, /** index relative to current record */ +char * okey, /** buffer for result key */ +int * okeylen /** length of the result key after return */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + PBLITEM_t item; + PBLBLOCK_t * block; + int index; + long rc; + + pbl_errno = 0; + + /* + * check position of current record + */ + block = pblPositionCheck( kf ); + if( !block ) + { + return( -1 ); + } + + /* + * start searching at current block and current index + */ + index = kf->index; + + /* + * if we want an item that is to the left of the current item + */ + while( !pbl_errno && relindex < 0 ) + { + relindex++; + + /* + * as long as we can go to the left on current block + */ + if( index > 0 ) + { + index--; + continue; + } + + /* + * find a block that has entries + */ + for(;;) + { + /* + * go to previous block + */ + if( !block->pblock || !block->blockno ) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + break; + } + + block = pblBlockGet( kf, block->pblock ); + if( !block ) + { + break; + } + + if( block->nentries ) + { + index = block->nentries - 1; + break; + } + } + } + + /* + * if we want an item that is to the right of the current item + */ + while( !pbl_errno && relindex > 0 ) + { + relindex--; + + /* + * as long as we can go to the right on this block + */ + if(( int )( index + 1 ) < ( int )block->nentries ) + { + index++; + continue; + } + + /* + * find a block that has at least one entry + */ + for(;;) + { + /* + * go to next block, but beware that rootblock has no next + */ + if( !block->nblock || !block->blockno ) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + break; + } + + block = pblBlockGet( kf, block->nblock ); + if( !block ) + { + break; + } + + if( block->nentries ) + { + index = 0; + break; + } + } + } + + /* + * if an error occured we tell the caller + */ + if( pbl_errno ) + { + return( -1 ); + } + + /* + * if we need the key of the record + */ + if( okey ) + { + if( pblBlockKeysExpand( block )) + { + return( -1 ); + } + } + + /* + * read the item + */ + rc = pblItemGet( block, index, &item ); + if( rc ) + { + return( -1 ); + } + + /* + * if the item we are standing on is our first record, we have reached the + * end of file while reading backward + */ + if( item.keylen == 0 ) + { + pbl_errno = PBL_ERROR_NOT_FOUND; + return( -1 ); + } + + /* + * set the out parameters, if a buffer is supplied + */ + if( okey && okeylen ) + { + *okeylen = item.keylen; + pbl_memlcpy( okey, PBLKEYLENGTH, item.key, item.keylen ); + } + + kf->blockno = block->blockno; + kf->index = index; + + return( item.datalen ); +} + +/** + * set current record to a record with an absolute position index + * + * this function is only to be used through the macro functions: + * + *
\Ref{pblKfFirst}( k, okey, okeylen ) read key of first record + *
\Ref{pblKfLast}( k, okey, okeylen ) read key of last record + * + * @return long rc >= 0: + *
    + *
  • call went ok, + * the value returned is the length + * of the data of the record found, + *
  • the length of the key of the record is set in + * the out parameter okeylen, + *
  • the key of the record is copied to okey, + *
  • the current record of the file is set to the + * record found + *
+ * + * @return long rc < 0: + *
    + *
  • some error occured, see pbl_errno + *
+ */ + +long pblKfGetAbs( +pblKeyFile_t * k, /** key file to position in */ +long absindex, /** index of record to positon to */ +char * okey, /** buffer for result key */ +int * okeylen /** length of the result key after return */ +) +{ + PBLKFILE_t * kf = ( PBLKFILE_t * ) k; + PBLITEM_t item; + PBLBLOCK_t * block; + int index; + long rc; + + pbl_errno = 0; + + /* + * start searching at rootblock + */ + block = pblBlockGet( kf, 0 ); + if( !block ) + { + return( -1 ); + } + + /* + * step down through tree to level 0 + */ + while( !pbl_errno && block->level ) + { + if( absindex >= 0 ) + { + index = 0; + } + else + { + index = block->nentries - 1; + } + + rc = pblItemGet( block, index, &item ); + if( rc ) + { + break; + } + + /* + * get the relevant child block + */ + block = pblBlockGet( kf, item.datablock ); + if( !block ) + { + return( -1 ); + } + } + + /* + * if no error yet, we do a relative get + */ + if( !pbl_errno ) + { + /* + * prepare relative get + */ + kf->blockno = block->blockno; + + if( absindex >= 0 ) + { + kf->index = -1; + return( pblKfGetRel( k, absindex, okey, okeylen )); + } + else + { + kf->index = block->nentries; + return( pblKfGetRel( k, absindex + 1, okey, okeylen )); + } + } + + return( -1 ); +} + +/* +------------------------------------------------------------------------------ + FUNCTION: pblKfXXX + + DESCRIPTION: These macros allow to position the current record and + to read the key, the keylen and the datalen of the new + current record + + The following macros exist: + + pblKfFirst: set the current record to the first record of the + file + + pblKfLast: set the current record to the last record of the + file + + pblKfNext: set the current record to the record of the + file after the old current record, of course the + record of the file must be positioned before that + + pblKfPrev: set the current record to the record of the + file before the old current record, of course the + record of the file must be positioned before that + + pblKfThis: this function can be used to read the key, keylen + and datalen of the current record, the current + record is not changed by this + + RESTRICTIONS: the out parameter okey must point to a memory area that is + big enough to hold any possible key, i.e 255 bytes + + RETURNS: long rc >= 0: call went ok, the value returned is the length + of the data of the current record, + the length of the key of the record is set in + the out parameter okeylen, + the key of the record is copied to okey, + + long rc < 0: some error occured, see pbl_errno + PBL_ERROR_NOT_FOUND, there is no matching record + PBL_ERROR_POSITION, current record not set yet +------------------------------------------------------------------------------ +*/ + + +int pblKfBlockPrint( +char * path, /** path of file to create */ +long blockno /** number of block to print */ +) +{ + PBLITEM_t item; + PBLKFILE_t * kf; + PBLBLOCK_t * block; + int bf; + int i; + + pbl_errno = 0; + + printf( "FILE %s, BLOCK %ld\n", path, blockno ); + + bf = pbf_open( path, 0, PBLFILEBLOCKS, PBLDATASIZE ); + if( -1 == bf ) + { + printf( "pbf_open failed, pbl_errno %d\n", pbl_errno ); + return( -1 ); + } + + /* + * get and init file structure + */ + kf = pbl_malloc0( "pblKfBlockPrint FILE", sizeof( PBLKFILE_t )); + if( !kf ) + { + printf( "pbl_malloc0 failed, pbl_errno %d\n", pbl_errno ); + pbf_close( bf ); + return( -1 ); + } + kf->magic = rcsid; + kf->bf = bf; + kf->update = 0; + kf->filesettag = NULL; + kf->blockno = -1; + kf->index = -1; + + pblnfiles++; + + /* + * get the block + */ + block = pblBlockGet( kf, blockno ); + if( !block ) + { + printf( "pblBlockGet failed, pbl_errno %d\n", pbl_errno ); + pblKfClose( ( pblKeyFile_t * ) kf ); + return( -1 ); + } + + if( block->level == 255 ) + { + printf( "datablock\n" ); + pblKfClose( ( pblKeyFile_t * ) kf ); + return( 0 ); + } + + printf( "level %d, pblock %ld, nblock %ld, nentries %d, free %d\n", + block->level, block->pblock, block->nblock, + (int)block->nentries, block->free ); + + if( block->nentries < 1 ) + { + pblKfClose( ( pblKeyFile_t * ) kf ); + return( 0 ); + } + + if( pblBlockKeysExpand( block )) + { + printf( "pblBlockKeysExpand failed, pbl_errno %d\n", pbl_errno ); + pblKfClose( ( pblKeyFile_t * ) kf ); + return( -1 ); + } + + for( i = 0; i < (int)block->nentries; i++ ) + { + char * ptr; + + pblItemGet( block, i, &item ); + + if( item.key ) + { + ptr = item.key; + } + else + { + ptr = "NULL"; + } + + printf( "%03d %d %.*s, common %d, datalen %ld, block %ld, offset %ld\n", + i, item.keylen, + item.keylen, ptr, + item.keycommon, item.datalen, + item.datablock, item.dataoffset ); + } + + pblKfClose( ( pblKeyFile_t * ) kf ); + return( 0 ); +} + diff --git a/src/pbl/pblkfblockprint b/src/pbl/pblkfblockprint new file mode 100755 index 0000000000000000000000000000000000000000..c528e5f1cc41901c2c9df3741efa57f407ee96a9 GIT binary patch literal 110601 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 SsT+ | grep Id | sort -u" shows the source file versions + */ +static char * rcsid = "$Id$"; +static int rcsid_fkt() { return( rcsid ? 0 : rcsid_fkt() ); } + +#include +#include +#include +#include + +#include "pbl.h" + +extern int pblKfBlockPrint( +char * path, /** path of file to create */ +long blockno /** number of block to print */ +); + +int main( int argc, char * argv[] ) +{ + long blockno; + + if( argc != 3 ) + { + fprintf( stderr, "Usage: %s path blockno\n", argv[ 0 ] ); + exit( 1 ); + } + + blockno = atoi( argv[ 2 ] ); + + pblKfBlockPrint( argv[ 1 ], blockno ); + + return( 0 ); +} + diff --git a/src/pbl/pblkfblockprint.dsp b/src/pbl/pblkfblockprint.dsp new file mode 100644 index 0000000..9ec44ae --- /dev/null +++ b/src/pbl/pblkfblockprint.dsp @@ -0,0 +1,93 @@ +# Microsoft Developer Studio Project File - Name="pblkfblockprint" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=pblkfblockprint - Win32 Debug mt 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 "pblkfblockprintdeb.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 "pblkfblockprintdeb.mak" CFG="pblkfblockprint - Win32 Debug mt static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pblkfblockprint - Win32 Debug mt static" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "pblkfblockprint" +# PROP BASE Intermediate_Dir "pblkfblockprint" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "winbuild\debugbin" +# PROP Intermediate_Dir "winbuild\debugtmp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /D "DEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT CPP /YX +# 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 wsock32.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 /machine:I386 +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 wsock32.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 /debug /machine:I386 /out:"winbuild\debugbin\pblkfblockprint.exe" +# Begin Target + +# Name "pblkfblockprint - Win32 Debug mt static" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\pbl.c +# End Source File +# Begin Source File + +SOURCE=.\pblhash.c +# End Source File +# Begin Source File + +SOURCE=.\pblisam.c +# End Source File +# Begin Source File + +SOURCE=.\pblkf.c +# End Source File +# Begin Source File + +SOURCE=.\pblkfblockprint.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\pbl.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/src/pbl/pblkfblockprint.dsw b/src/pbl/pblkfblockprint.dsw new file mode 100755 index 0000000..0b8dbcf --- /dev/null +++ b/src/pbl/pblkfblockprint.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "pblkfblockprint"=.\pblkfblockprint.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/pbl/pblkftst b/src/pbl/pblkftst new file mode 100755 index 0000000000000000000000000000000000000000..88ef8c3c112624c53bd8f27e08e7ae5b686de8ad GIT binary patch literal 130359 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μ0o1z?87d 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 o)Il57@O)BOV?pbIr | grep Id | sort -u" shows the source file versions + */ +static char * rcsid = "$Id$"; +static int rcsid_fkt() { return( rcsid ? 0 : rcsid_fkt() ); } + +#include +#include +#include +#include + +#include "pbl.h" + +static FILE * log; +static FILE * infile; + +static void putChar( int c ) +{ + static int last = 0; + + if( last == '\n' && c == '\n' ) + return; + + last = c; + ( void ) putc( last, log ); +} + +static int getChar( void ) +{ + int c; + c = getc( infile ); + + /* + * a '#' starts a comment for the rest of the line + */ + if( c == '#') + { + while( c != '\n' && c != EOF ) + { + c = getc( infile ); + } + } + + if( c != EOF ) + putChar( c ); + + return( c ); +} + + +static void getWord( char * buffer ) +{ + int c; + + /* + * skip preceeding blanks + */ + c = ' '; + while( c== '\t' || c == ' ' || c == '\n' ) + c = getChar(); + + /* + * read one word + */ + for(;; c = getChar()) + { + if( c == EOF ) + { + exit( 0 ); + } + + if( c== '\t' || c == ' ' || c == '\n' ) + { + *buffer = '\0'; + return; + } + + *buffer++ = c; + } +} + +static int commastrlen( char * s ) +{ + char *ptr = s; + + while( ptr && *ptr && *ptr != ',' ) + { + ptr++; + } + + return( ptr - s ); +} + +static void commatolength( char * s ) +{ + while( s && *s ) + { + if( *s == ',' ) + { + *s = 0xff & commastrlen( s + 1 ); + } + + s++; + } +} + +/** + * test frame for the key file library + * + * This test frame calls the key file library, + * it is an interactive test frame capable of regression tests. + * + * Interactive mode: + *

    + * Call the program pblkftst from a UNIX or DOS shell. + *
    + * The following commands to test the PBL Key File Library are supplied: + *
      + *
      + q       FOR QUIT
      + create  
      + open     
      + close | flush | delete
      + insert   
      + ninsert   
      + find     < LT | LE | FI | EQ | LA | GE | GT >
      + update  
      + ndelete 
      + first | last | next | prev | this | read
      + list    
      + 
      + *
    + *
+ * Interactive mode example: + *
    + * The following short examples demonstrates how to use the interactive + * test frame. Lines starting with a # are printed by the program + * lines starting with other characters are user input. + *
      + *
      +pblkftst
      +
      +##command: 
      +create /tmp/keytest
      +# create filename 
      +# pblKfCreate( /tmp/keytest )
      +# ok!
      +
      +##command: 
      +insert testkey testdata
      +# insert key, data
      +# pblKfInsert( 1, testkey, 8, testdata, 9 )
      +# rc 0, pbl_errno 0, errno 0
      +
      +##command: 
      +first
      +# pblKfFirst( 1 )
      +# datalen 9, key testkey, keylen 8
      +
      +##command: 
      +close
      +# pblKfClose( 1 )
      +# rc 0, pbl_errno 0, errno 0
      +
      +##command: 
      +quit
      +   
      + *
    + *
+ + * Regression mode: + *
    + * Put a sequence of test commands into a test batch file. + *

    + * Example: + *

      + * Open a new file KEY0001.TST and add the following lines + *
      +create /tmp/keytest2
      +insert testkey testdata
      +first
      +close
      +quit
      +
      +
    + * Then run pblkftst KEY0001.TST + * + * The program creates a log file called pblkftst.log when run. + * This log file can be used as regression input file for further + * tests. + *
      +
      +##command:
      +create # create filename
      +/tmp/key0001
      +# pblKfCreate( /tmp/key0001 )
      +# ok!
      +
      +##command:
      +insert # insert key, data
      +testkey testdata
      +# pblKfInsert( 1, testkey, 8, testdata, 9 )
      +# rc 0, pbl_errno 0, errno 0
      +
      +##command:
      +first
      +# pblKfFirst( 1 )
      +# datalen 9, key testkey, keylen 8
      +
      +##command:
      +close
      +# pblKfClose( 1 )
      +# rc 0, pbl_errno 0, errno 0
      +
      +##command:
      +quit
      +
      +
    + * Keep the contents of this file and diff it with the outout of + * the KEY0001.TST testcase you created whenever you change + * the code of the library. + * + * See \Ref{pblISAMFILE_TestFrame} for an example of regression + * tests with a test frame. The regression test cases given with + * \Ref{pblISAMFILE_TestFrame} of course also test the PBL Key File + * library. + *
+ */ + +int pblKEYFILE_TestFrame( int argc, char * argv[] ) +{ + char command[ 2048 ]; + char filename [ 2048 ]; + char buffer [ 2048 ]; + int update; + int ival; + int dowork = 1; + long rc; + int i; + int len; + + pblKeyFile_t * kf = ( pblKeyFile_t *) 0; + + infile = stdin; + if( argc > 1 ) + { + infile = fopen( argv[ 1 ], "r" ); + if( !infile ) + { + fprintf( stderr, "Failed to open %s, %s\n", + argv[ 1 ], strerror( errno )); + exit( -1 ); + } + } + + log = fopen( "./pblkftst.log", "w" ); + if( !log ) + { + fprintf( stderr, "cant open logfile, .\\pblkftst.log\n" ); + exit( 1 ); + } + + while( dowork ) + { + memset( command, 0, sizeof( command )); + memset( filename, 0, sizeof( filename )); + memset( buffer, 0, sizeof( buffer )); + + errno = 0; + + printf( "\n##command: \n" ); + fprintf( log, "\n##command: \n" ); + + getWord( command ); + + if( command[0] == 'q' || command[0] == 'Q' ) + { + dowork = 0; + } + else if( !strcmp( command, "create" )) + { + printf( "# create filename \n" ); + fprintf( log, "# create filename \n" ); + + getWord( filename ); + + printf( "# pblKfCreate( %s )\n", filename ); + fprintf( log, "# pblKfCreate( %s )\n", filename ); + + if( kf ) + ( void ) pblKfClose( kf ); + + kf = pblKfCreate( filename, NULL ); + + if( kf ) + { + printf( "# ok!\n" ); + fprintf( log, "# ok!\n" ); + } + else + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + } + + else if( !strcmp( command, "open" )) + { + printf( "# open filename, update \n" ); + fprintf( log, "# open filename, update \n" ); + getWord( filename ); + getWord( buffer ); + update = atoi( buffer ); + + printf( "# pblKfOpen( %s, %d )\n", filename, update ); + fprintf( log, "# pblKfOpen( %s, %d )\n", filename, update ); + + if( kf ) + ( void ) pblKfClose( kf ); + + kf = pblKfOpen( filename, update, NULL ); + if( kf ) + { + printf( "# ok!\n" ); + fprintf( log, "# ok!\n" ); + } + else + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + } + + else if( !strcmp( command, "close" )) + { + if( !kf ) + continue; + + printf( "# pblKfClose( %d )\n", 1 ); + fprintf( log, "# pblKfClose( %d )\n", 1 ); + + rc = pblKfClose( kf ); + kf = ( pblKeyFile_t * ) 0; + + printf( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + fprintf( log, "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "flush" )) + { + if( !kf ) + continue; + + printf( "# pblKfFlush( %d )\n", 1 ); + fprintf( log, "# pblKfFlush( %d )\n", 1 ); + + rc = pblKfFlush( kf ); + + printf( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + fprintf( log, "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "delete" )) + { + if( !kf ) + continue; + + printf( "# pblKfDelete( %d )\n", 1 ); + fprintf( log, "# pblKfDelete( %d )\n", 1 ); + + rc = pblKfDelete( kf ); + + printf( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + fprintf( log, "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "find" )) + { + if( !kf ) + continue; + + printf( "# find key < LT | LE | FI | EQ | LA | GE | GT >\n" ); + fprintf( log, "# find key < LT | LE | FI | EQ | LA | GE | GT >\n" ); + getWord( buffer ); + getWord( filename ); + if( !strcmp( filename, "GT" )) + { + ival = PBLGT; + } + else if( !strcmp( filename, "FI" )) + { + ival = PBLFI; + } + else if( !strcmp( filename, "LA" )) + { + ival = PBLLA; + } + else if( !strcmp( filename, "GE" )) + { + ival = PBLGE; + } + else if( !strcmp( filename, "LE" )) + { + ival = PBLLE; + } + else if( !strcmp( filename, "LT" )) + { + ival = PBLLT; + } + else + { + strcpy( filename, "EQ" ); + ival = PBLEQ; + } + + len = strlen( buffer ); + + printf( "# pblKfFind( %d, %s, %s, %d )\n", + 1, filename, buffer, len + 1 ); + + fprintf( log, "# pblKfFind( %d, %s, %s, %d )\n", + 1, filename, buffer, len + 1 ); + + rc = pblKfFind( kf, ival, buffer, len + 1, filename, &ival ); + + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, filename, ival); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, filename, ival); + } + } + + else if( !strcmp( command, "insert" )) + { + if( !kf ) + continue; + + printf( "# insert key, data\n" ); + fprintf( log, "# insert key, data\n" ); + getWord( buffer ); + len = strlen( buffer ); + + getWord( filename ); + ival = strlen( filename ); + + printf( "# pblKfInsert( %d, %s, %d, %s, %d )\n", + 1, buffer, len + 1, + filename, ival + 1 ); + + fprintf( log, "# pblKfInsert( %d, %s, %d, %s, %d )\n", + 1, buffer, len + 1, + filename, ival + 1 ); + + rc = pblKfInsert( kf, buffer, len + 1, + filename, (long) ival + 1 ); + + printf( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + fprintf( log, "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "ninsert" )) + { + if( !kf ) + continue; + + printf( "# ninsert n, key, data\n" ); + fprintf( log, "# ninsert n, key, data\n" ); + getWord( command ); + ival = atoi( command ); + getWord( buffer ); + getWord( command ); + + printf( "# ninsert( %d )\n", ival ); + fprintf( log, "# ninsert( %d )\n", ival ); + + for( i = 0; i < ival; i++ ) + { + sprintf( filename, "%s_%d", command, i ); + + len = strlen( filename ); + ival = strlen( buffer ); + rc = pblKfInsert( kf, buffer, ival + 1, + filename, (long) len + 1 ); + + if( rc < 0 ) + { + printf( "# i %d, rc %ld, pbl_errno %d, errno %d\n", + i, rc, pbl_errno, errno ); + fprintf( log, "# i %d, rc %ld, pbl_errno %d, errno %d\n", + i, rc, pbl_errno, errno ); + break; + } + } + printf( "# inserted %d records\n", i ); + fprintf( log, "# inserted %d records\n", i ); + + } + + else if( !strcmp( command, "ndelete" )) + { + if( !kf ) + continue; + + printf( "# ndelete n\n" ); + fprintf( log, "# ndelete n\n" ); + getWord( buffer ); + ival = atoi( buffer ); + + printf( "# ndelete( %d )\n", ival ); + fprintf( log, "# ndelete( %d )\n", ival ); + + for( i = 0; i < ival; i++ ) + { + + rc = pblKfDelete( kf ); + + if( rc < 0 ) + { + printf( "# i %d, rc %ld, pbl_errno %d, errno %d\n", + i, rc, pbl_errno, errno ); + fprintf( log, "# i %d, rc %ld, pbl_errno %d, errno %d\n", + i, rc, pbl_errno, errno ); + break; + } + } + printf( "# deleted %d records\n", i ); + fprintf( log, "# deleted %d records\n", i ); + + } + + else if( !strcmp( command, "update" )) + { + if( !kf ) + continue; + + printf( "# update data\n" ); + fprintf( log, "# update data\n" ); + getWord( buffer ); + len = strlen( buffer ); + + printf( "# pblKfUpdate( %d, %s, %d )\n", + 1, buffer, len + 1 ); + fprintf( log, "# pblKfUpdate( %d, %s, %d )\n", + 1, buffer, len + 1 ); + + rc = pblKfUpdate( kf, buffer, ( long ) len + 1 ); + + printf( "# rc %ld, pbl_errno %d, errno %d\n", rc, pbl_errno, errno ); + fprintf( log, "# rc %ld, pbl_errno %d, errno %d\n", + rc, pbl_errno, errno ); + } + + else if( !strcmp( command, "read" )) + { + if( !kf ) + continue; + + printf( "# pblKfRead( %d )\n", 1 ); + fprintf( log, "# pblKfRead( %d )\n", 1 ); + + rc = pblKfRead( kf, buffer, sizeof( buffer ) ); + + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + else + { + printf( "# datalen %ld, data %s\n", rc, buffer ); + fprintf( log, "# datalen %ld, data %s\n", rc, buffer ); + } + } + + else if( !strcmp( command, "list" )) + { + if( !kf ) + continue; + + printf( "# list n\n" ); + fprintf( log, "# list n\n" ); + getWord( buffer ); + update = atoi( buffer ); + + printf( "# list( %d )\n", update ); + fprintf( log, "# list( %d )\n", update ); + + if( update > 0 ) + { + rc = pblKfThis( kf, buffer, &ival ); + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno); + continue; + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + } + } + for( i = 1; i < update; i++ ) + { + rc = pblKfNext( kf, buffer, &ival ); + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno); + break; + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + } + } + } + + else if( !strcmp( command, "first" )) + { + if( !kf ) + continue; + + printf( "# pblKfFirst( %d )\n", 1 ); + fprintf( log, "# pblKfFirst( %d )\n", 1 ); + + rc = pblKfFirst( kf, buffer, &ival ); + + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + } + } + + else if( !strcmp( command, "next" )) + { + if( !kf ) + continue; + + printf( "# pblKfNext( %d )\n", 1 ); + fprintf( log, "# pblKfNext( %d )\n", 1 ); + + rc = pblKfNext( kf, buffer, &ival ); + + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + } + } + + else if( !strcmp( command, "last" )) + { + if( !kf ) + continue; + + printf( "# pblKfLast( %d )\n", 1 ); + fprintf( log, "# pblKfLast( %d )\n", 1 ); + + rc = pblKfLast( kf, buffer, &ival ); + + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + } + } + + else if( !strcmp( command, "prev" )) + { + if( !kf ) + continue; + + printf( "# pblKfPrev( %d )\n", 1 ); + fprintf( log, "# pblKfPrev( %d )\n", 1 ); + + rc = pblKfPrev( kf, buffer, &ival ); + + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + } + } + + + else if( !strcmp( command, "this" )) + { + if( !kf ) + continue; + + printf( "# pblKfThis( %d )\n", 1 ); + fprintf( log, "# pblKfThis( %d )\n", 1 ); + + rc = pblKfThis( kf, buffer, &ival ); + + if( rc < 0 ) + { + printf( "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + fprintf( log, "# pbl_errno %d, errno %d\n", pbl_errno, errno ); + } + else + { + printf( "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + fprintf( log, "# datalen %ld, key %s, keylen %d\n", + rc, buffer, ival ); + } + } + + else + { + printf( "# q FOR QUIT\n" ); + printf( "# create \n" ); + printf( "# open \n" ); + printf( "# close | flush | delete\n" ); + printf( "# insert \n" ); + printf( "# ninsert \n" ); + printf( "# find < LT | LE | FI | EQ | LA | GE | GT >\n" ); + printf( "# update \n" ); + printf( "# ndelete \n" ); + printf( "# first | last | next | prev | this | read\n" ); + printf( "# list \n" ); + } + } + + return( 0 ); +} + +int main( int argc, char * argv[] ) +{ + return( pblKEYFILE_TestFrame( argc, argv )); +} + diff --git a/src/pbl/pblkftstdeb.dsp b/src/pbl/pblkftstdeb.dsp new file mode 100644 index 0000000..4421550 --- /dev/null +++ b/src/pbl/pblkftstdeb.dsp @@ -0,0 +1,93 @@ +# Microsoft Developer Studio Project File - Name="pblkftst" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=pblkftst - Win32 Debug mt 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 "pblkftstdeb.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 "pblkftstdeb.mak" CFG="pblkftst - Win32 Debug mt static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pblkftst - Win32 Debug mt static" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "pblkftst" +# PROP BASE Intermediate_Dir "pblkftst" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "winbuild\debugbin" +# PROP Intermediate_Dir "winbuild\debugtmp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /D "DEBUG" /D "WIN32" /D "_CONSOLE" /FD /c +# SUBTRACT CPP /YX +# 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 wsock32.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 /machine:I386 +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 wsock32.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 /debug /machine:I386 /out:"winbuild\debugbin\pblkftst.exe" +# Begin Target + +# Name "pblkftst - Win32 Debug mt static" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\pbl.c +# End Source File +# Begin Source File + +SOURCE=.\pblhash.c +# End Source File +# Begin Source File + +SOURCE=.\pblisam.c +# End Source File +# Begin Source File + +SOURCE=.\pblkf.c +# End Source File +# Begin Source File + +SOURCE=.\pblkftst.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\pbl.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/src/pbl/pblkftstdeb.dsw b/src/pbl/pblkftstdeb.dsw new file mode 100755 index 0000000..39223d6 --- /dev/null +++ b/src/pbl/pblkftstdeb.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "pblhttst"=.\pblkftstdeb.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/pbl/pbltest.c b/src/pbl/pbltest.c new file mode 100644 index 0000000..94ec2bd --- /dev/null +++ b/src/pbl/pbltest.c @@ -0,0 +1,124 @@ +/* + pbltest.c - test functions + + Copyright (C) 2002 Peter Graf + + This file is part of PBL - The Program Base Library. + PBL is free software. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For more information on the Program Base Library or Peter Graf, + please see: http://mission.base.com/. + + + $Log$ + Revision 1.1 2004/06/24 21:12:08 sears + Initial revision + + Revision 1.1 2003/12/11 09:10:49 jim + pbl + + Revision 1.2 2002/09/12 20:47:08 peter + added the isam file handling to the library + + Revision 1.1 2002/09/05 13:45:03 peter + Initial revision + + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * make sure "strings | grep Id | sort -u" shows the source file versions + */ +static char* _PBL_id = "$Id$"; +static int _PBL_fct() { return( _PBL_id ? 0 : _PBL_fct() ); } + +#include +#include +#include + +#include "pbl.h" + +/*****************************************************************************/ +/* #defines */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* typedefs */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* globals */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* functions */ +/*****************************************************************************/ + +int main( int argc, char * argv[ ] ) +{ + void * ht; + int rc; + + char * data; + + ht = pblHtCreate(); + + rc = pblHtInsert( ht, "123", 4, "123" ); + rc = pblHtInsert( ht, "124", 4, "124" ); + rc = pblHtInsert( ht, "125", 4, "125" ); + rc = pblHtInsert( ht, "123", 4, "123" ); + rc = pblHtInsert( ht, "123", 3, "123" ); + + data = pblHtLookup( ht, "123", 4 ); + data = pblHtLookup( ht, "123", 3 ); + data = pblHtLookup( ht, "124", 4 ); + data = pblHtLookup( ht, "125", 4 ); + data = pblHtLookup( ht, "126", 4 ); + + for( data = pblHtFirst( ht ); data; data = pblHtNext( ht )) + { + data = pblHtCurrent( ht ); + } + + rc = pblHtRemove( ht, "125", 4 ); + + data = pblHtFirst( ht ); + + rc = pblHtDelete( ht ); + + while( !pblHtRemove( ht, 0, 0 )); + + rc = pblHtInsert( ht, "123", 4, "123" ); + rc = pblHtInsert( ht, "124", 4, "124" ); + rc = pblHtInsert( ht, "125", 4, "125" ); + rc = pblHtInsert( ht, "123", 4, "123" ); + rc = pblHtInsert( ht, "123", 3, "123" ); + + for( data = pblHtFirst( ht ); data; data = pblHtNext( ht )) + { + pblHtRemove( ht, 0, 0 ); + } + + rc = pblHtDelete( ht ); + + return( rc ); +} + diff --git a/src/timing/Makefile.am b/src/timing/Makefile.am new file mode 100644 index 0000000..c3ebd6f --- /dev/null +++ b/src/timing/Makefile.am @@ -0,0 +1,3 @@ +bin_PROGRAMS=getTimeOfDay +AM_CFLAGS= -g -Wall -pedantic + diff --git a/src/timing/README b/src/timing/README new file mode 100644 index 0000000..1d66f1a --- /dev/null +++ b/src/timing/README @@ -0,0 +1,31 @@ +README for timing suite: + +Installation: + +cd timing +gcc getTimeOfDay.c -o getTimeOfDay + +# replace ~/bin with something in your path. + +cp timer.pl getTimeOfDay ~/bin + +Finally, edit your copy of timer.pl to reflect the location of t-distribution.tbl on your system. + +-------------------------------- + +README for graphing suite: + +Look in the timing-test-case for an example. The .def file contains definitions that set the title, and x,y labels of the graph. + +The .dat files are the raw x,y data points (not all x's, y's need be present, or consistent between data sets). + +It should work for an arbitrary number of .dat files. + + +To use the .ps file, you'll have to do this when you compile your latex: + +latex bar.tex +dvips -j0 bar.dvi +ps2pdf bar.ps + + diff --git a/src/timing/getTimeOfDay.c b/src/timing/getTimeOfDay.c new file mode 100644 index 0000000..b5f9fc3 --- /dev/null +++ b/src/timing/getTimeOfDay.c @@ -0,0 +1,55 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include + +int main() { + unsigned long l; + struct timeval t; + + gettimeofday(&t, NULL); + + l = t.tv_sec * 1000 + t.tv_usec / 1000; + + printf("%lu\n", l); + return (0); +} diff --git a/src/timing/plotting-test-case/FOO-Berkeley DB.dat b/src/timing/plotting-test-case/FOO-Berkeley DB.dat new file mode 100644 index 0000000..d464cf2 --- /dev/null +++ b/src/timing/plotting-test-case/FOO-Berkeley DB.dat @@ -0,0 +1,9 @@ +1 1 +2 4 +3 9 +4 16 +5 25 +6 36 +7 49 +9 81 +12 144 diff --git a/src/timing/plotting-test-case/FOO-LLADD.dat b/src/timing/plotting-test-case/FOO-LLADD.dat new file mode 100644 index 0000000..056f4fb --- /dev/null +++ b/src/timing/plotting-test-case/FOO-LLADD.dat @@ -0,0 +1,9 @@ +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +12 12 +18 18 diff --git a/src/timing/plotting-test-case/FOO.def b/src/timing/plotting-test-case/FOO.def new file mode 100644 index 0000000..ee99934 --- /dev/null +++ b/src/timing/plotting-test-case/FOO.def @@ -0,0 +1,3 @@ +Title: Sample Graph +X-Label: Iterations +Y-Label: Seconds diff --git a/src/timing/plotting-test-case/FOO.ps b/src/timing/plotting-test-case/FOO.ps new file mode 100644 index 0000000..4b17af2 --- /dev/null +++ b/src/timing/plotting-test-case/FOO.ps @@ -0,0 +1,380 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%DocumentNeededResources: font CMR10 +%%+ font CMBX10 +%%+ font CMSL10 +%%+ font CMBXSL10 +%%+ font CMSY10 CMBSY10 CMMI10 +%%Title: R Graphics Output +%%Creator: R Software +%%Pages: (atend) +%%BoundingBox: 0 0 702 459 +%%EndComments +%%BeginProlog +/bp { gs gs } def +% begin .ps.prolog +/gs { gsave } def +/gr { grestore } def +/ep { showpage gr gr } def +/m { moveto } def +/l { rlineto } def +/np { newpath } def +/cp { closepath } def +/f { fill } def +/o { stroke } def +/c { newpath 0 360 arc } def +/r { 4 2 roll moveto 1 copy 3 -1 roll exch 0 exch rlineto 0 rlineto -1 mul 0 exch rlineto closepath } def +/p1 { stroke } def +/p2 { gsave bg setrgbcolor fill grestore newpath } def +/p3 { gsave bg setrgbcolor fill grestore stroke } def +/t { 6 -2 roll moveto gsave rotate + ps mul neg 0 2 1 roll rmoveto + 1 index stringwidth pop + mul neg 0 rmoveto show grestore } def +/cl { grestore gsave newpath 3 index 3 index moveto 1 index + 4 -1 roll lineto exch 1 index lineto lineto + closepath clip newpath } def +/rgb { setrgbcolor } def +/s { scalefont setfont } def +/R { /Font1 findfont } def +/B { /Font2 findfont } def +/I { /Font3 findfont } def +/BI { /Font4 findfont } def +/S { /Font5 findfont } def +1 setlinecap 1 setlinejoin +% end .ps.prolog +% begin encoding +/SymbolEncoding [ + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.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 /universal /numbersign /existential /percent /ampersand /suchthat + /parenleft /parenright /asteriskmath /plus /comma /minus /period /slash + /zero /one /two /three /four /five /six /seven + /eight /nine /colon /semicolon /less /equal /greater /question + /congruent /Alpha /Beta /Chi /Delta /Epsilon /Phi /Gamma + /Eta /Iota /theta1 /Kappa /Lambda /Mu /Nu /Omicron + /Pi /Theta /Rho /Sigma /Tau /Upsilon /sigma1 /Omega + /Xi /Psi /Zeta /bracketleft /therefore /bracketright /perpendicular /underscore + /radicalex /alpha /beta /chi /delta /epsilon /phi /gamma + /eta /iota /phi1 /kappa /lambda /mu /nu /omicron + /pi /theta /rho /sigma /tau /upsilon /omega1 /omega + /xi /psi /zeta /braceleft /bar /braceright /similar /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /Euro /Upsilon1 /minute /lessequal /fraction /infinity /florin /club + /diamond /heart /spade /arrowboth /arrowleft /arrowup /arrowright /arrowdown + /degree /plusminus /second /greaterequal /multiply /proportional /partialdiff /bullet + /divide /notequal /equivalence /approxequal /ellipsis /arrowvertex /arrowhorizex /carriagereturn + /aleph /Ifraktur /Rfraktur /weierstrass /circlemultiply /circleplus /emptyset /intersection + /union /propersuperset /reflexsuperset /notsubset /propersubset /reflexsubset /element /notelement + /angle /gradient /registerserif /copyrightserif /trademarkserif /product /radical /dotmath + /logicalnot /logicaland /logicalor /arrowdblboth /arrowdblleft /arrowdblup /arrowdblright /arrowdbldown + /lozenge /angleleft /registersans /copyrightsans /trademarksans /summation /parenlefttp /parenleftex + /parenleftbt /bracketlefttp /bracketleftex /bracketleftbt /bracelefttp /braceleftmid /braceleftbt /braceex + /.notdef /angleright /integral /integraltp /integralex /integralbt /parenrighttp /parenrightex + /parenrightbt /bracketrighttp /bracketrightex /bracketrightbt /bracerighttp /bracerightmid /bracerightbt /.notdef +] def +% end encoding +/mergefonts +{ /targetencoding exch def + /fontarray exch def + fontarray 0 get dup maxlength dict begin + { 1 index /FID ne { def } { pop pop } ifelse } forall + % Create a new dictionary + /CharStrings 256 dict def + % Add a definition of .notdef + fontarray + { /CharStrings get dup /.notdef known + { /.notdef get /result exch def exit } + { pop } ifelse + } forall + CharStrings /.notdef result put + % Add in the other definitions + targetencoding + { /code exch def + % Check that it is not a .notdef + code /.notdef eq + { /.notdef } + { fontarray + { /CharStrings get dup code known + { code get /result exch def /found true def exit } + { pop /found false def } ifelse + } forall + % define character if it was found and accumulate encoding + found { CharStrings code result put code } { /.notdef } ifelse + } ifelse + } forall + % grab new encoding off of stack + 256 array astore /Encoding exch def + % Undefine some local variables + currentdict /fontarray undef + currentdict /targetencoding undef + currentdict /code undef + currentdict /result undef + currentdict /found undef + % Leave new font on the stack + currentdict + end +} def +%%IncludeResource: font CMR10 +%%IncludeResource: font CMSY10 +[ /CMR10 findfont /CMSY10 findfont ] ISOLatin1Encoding mergefonts +/Font1 exch definefont pop +%%IncludeResource: font CMBX10 +%%IncludeResource: font CMBSY10 +[ /CMBX10 findfont /CMBSY10 findfont ] ISOLatin1Encoding mergefonts +/Font2 exch definefont pop +%%IncludeResource: font CMSL10 +[ /CMSL10 findfont /CMSY10 findfont ] ISOLatin1Encoding mergefonts +/Font3 exch definefont pop +%%IncludeResource: font CMBXSL10 +[ /CMBXSL10 findfont /CMBSY10 findfont ] ISOLatin1Encoding mergefonts +/Font4 exch definefont pop +%%IncludeResource: font CMMI10 +[ /CMR10 findfont /CMSY10 findfont /CMMI10 findfont ] SymbolEncoding mergefonts +/Font5 exch definefont pop +%%EndProlog +%%Page: 1 1 +bp +59.04 73.44 671.76 399.96 cl +0 0 0 rgb +0.75 setlinewidth +[] 0 setdash +np +120.31 89.04 m +17.40 3.48 l +o +np +151.60 96.21 m +17.86 5.94 l +o +np +182.81 107.47 m +18.47 8.61 l +o +np +213.98 122.83 m +19.17 11.49 l +o +np +245.13 142.28 m +19.91 14.58 l +o +np +276.29 165.83 m +20.63 17.87 l +o +np +307.29 193.66 m +53.18 56.69 l +o +np +369.59 261.45 m +86.18 120.56 l +o +113.25 87.63 2.70 c p1 +144.77 93.93 2.70 c p1 +176.29 104.43 2.70 c p1 +207.81 119.13 2.70 c p1 +239.33 138.02 2.70 c p1 +270.84 161.12 2.70 c p1 +302.36 188.41 2.70 c p1 +365.40 255.60 2.70 c p1 +459.96 387.87 2.70 c p1 +0.00 0.00 702.00 459.00 cl +0 0 0 rgb +0.75 setlinewidth +[] 0 setdash +np +81.73 73.44 m +472.78 0 l +o +np +81.73 73.44 m +0 -7.20 l +o +np +239.33 73.44 m +0 -7.20 l +o +np +396.92 73.44 m +0 -7.20 l +o +np +554.51 73.44 m +0 -7.20 l +o +/ps 12 def R 12 s +81.73 47.52 (0) .5 0 0 t +239.33 47.52 (5) .5 0 0 t +396.92 47.52 (10) .5 0 0 t +554.51 47.52 (15) .5 0 0 t +np +59.04 85.53 m +0 293.94 l +o +np +59.04 85.53 m +-7.20 0 l +o +np +59.04 127.52 m +-7.20 0 l +o +np +59.04 169.51 m +-7.20 0 l +o +np +59.04 211.51 m +-7.20 0 l +o +np +59.04 253.50 m +-7.20 0 l +o +np +59.04 295.49 m +-7.20 0 l +o +np +59.04 337.48 m +-7.20 0 l +o +np +59.04 379.47 m +-7.20 0 l +o +41.76 85.53 (0) .5 0 90 t +41.76 127.52 (20) .5 0 90 t +41.76 169.51 (40) .5 0 90 t +41.76 211.51 (60) .5 0 90 t +41.76 253.50 (80) .5 0 90 t +41.76 295.49 (100) .5 0 90 t +41.76 337.48 (120) .5 0 90 t +41.76 379.47 (140) .5 0 90 t +np +59.04 73.44 m +612.72 0 l +0 326.52 l +-612.72 0 l +0 -326.52 l +o +0.00 0.00 702.00 459.00 cl +/ps 14 def B 14 s +0 0 0 rgb +365.40 424.68 (Sample Graph) .5 0 0 t +/ps 12 def R 12 s +365.40 18.72 (Iterations) .5 0 0 t +12.96 236.70 (Seconds) .5 0 90 t +59.04 73.44 671.76 399.96 cl +1 0 0 rgb +0.75 setlinewidth +[] 0 setdash +np +120.44 88.11 m +17.15 1.14 l +o +np +151.95 90.21 m +17.15 1.14 l +o +np +183.47 92.31 m +17.15 1.14 l +o +np +214.99 94.41 m +17.15 1.14 l +o +np +246.51 96.51 m +17.15 1.14 l +o +np +278.03 98.61 m +17.15 1.14 l +o +np +309.55 100.71 m +143.22 9.54 l +o +np +467.14 111.21 m +174.74 11.64 l +o +np +113.25 91.83 m +3.64 -6.30 l +-7.27 0 l +3.63 6.30 l +o +np +144.77 93.93 m +3.64 -6.30 l +-7.28 0 l +3.64 6.30 l +o +np +176.29 96.03 m +3.64 -6.30 l +-7.28 0 l +3.64 6.30 l +o +np +207.81 98.13 m +3.63 -6.30 l +-7.27 0 l +3.64 6.30 l +o +np +239.33 100.23 m +3.63 -6.30 l +-7.27 0 l +3.64 6.30 l +o +np +270.84 102.33 m +3.64 -6.30 l +-7.27 0 l +3.63 6.30 l +o +np +302.36 104.43 m +3.64 -6.30 l +-7.27 0 l +3.63 6.30 l +o +np +459.96 114.93 m +3.63 -6.30 l +-7.27 0 l +3.64 6.30 l +o +np +649.07 127.52 m +3.63 -6.29 l +-7.27 0 l +3.64 6.29 l +o +0 0 0 rgb +92.53 373.47 2.70 c p1 +1 0 0 rgb +np +92.53 363.27 m +3.64 -6.30 l +-7.27 0 l +3.63 6.30 l +o +/ps 12 def R 12 s +0 0 0 rgb +108.73 369.37 (Berkeley DB) 0 0 0 t +108.73 354.97 (LLADD) 0 0 0 t +ep +%%Trailer +%%Pages: 1 +%%EOF diff --git a/src/timing/plotting.pl b/src/timing/plotting.pl new file mode 100755 index 0000000..8c3bb9c --- /dev/null +++ b/src/timing/plotting.pl @@ -0,0 +1,162 @@ +#! /usr/bin/perl -w + +use strict; + + +my $R_PREAMBLE = qq{ + postscript("__PLOT_NAME__.ps", width = 9.75, height = 6.375, + horizontal = FALSE, onefile = FALSE, paper = "special", + family = "ComputerModern") + }; + +my $R_READ = qq{ + __NAME__<-read.table("__FILE__",header=F,sep="\\t") + }; + +my $R_FIRST_PLOT = qq{ + plot(__NAME__\$V1, __NAME__\$V2, type="b", + xlim=c(0,max(__NAME_X_LIST__)), + ylim=c(0, max(__NAME_Y_LIST__)), + xlab="__XLAB__", ylab="__YLAB__", + main="__TITLE__", pch=1, col=1) + }; + +my $R_NEXT_PLOT = qq{ + lines(__NAME__\$V1, __NAME__\$V2, type="b", pch=__N__+1, col=__N__+1) + }; + +my $R_LEGEND = qq{ + legend((0 * max(__NAME_X_LIST__)), max(__NAME_Y_LIST__), legend=c(__NAME_LABEL_LIST__), bty="n", pch=c(1:__COUNT__), col=c(1:__COUNT__)) +}; + +my $R_FINISH = qq{ + dev.off() + }; + +sub replaceAll { + my $cmd = shift; + my $arglist_ref = shift; + my %arglist = %{$arglist_ref}; + + foreach my $i (keys %arglist) { + $cmd =~ s/$i/$arglist{$i}/g; + } + return $cmd; +} + +sub getConfig { + my $basename = shift; + my $key = shift; + my $value = `grep ^$key: $basename.def`; + $value =~ s/^$key\:\s+//; + chomp $value; + return $value +} + +sub filesToLabels { + my $array_ref = shift; + + my @array = @{$array_ref}; + + for(my $i = 0; $i < @array; $i++) { + chomp $array[$i]; + $array[$i] =~ s/^[^\-]+\-//; + $array[$i] =~ s/\.dat$//; + } + + my $ret = '"' . join ('", "', @array). '"'; + + return $ret; +} + +sub labelsToVars { + my $i = shift; + + $i =~ s/[^A-Za-z0-9\"\,]//g; + + $i =~ s/\,/, /g; + + return $i; +} + +sub varsToXList { + my $i = shift; + + $i =~ s/\"\,/\$V1\",/g; + $i =~ s/\"$/\$V1\"/; + + $i =~ s/\"//g; + + return $i; +} +sub varsToYList { + my $i = shift; + + $i =~ s/\"\,/\$V2\",/g; + $i =~ s/\"$/\$V2\"/; + $i =~ s/\"//g; + + return $i; +} + +my %vals; + +my $basename = $ARGV[0]; + +my @files = `ls $basename-*.dat`; + +for(my $i =0; $i < @files; $i++) { + chomp $files[$i]; +} + + +$vals{__PLOT_NAME__} = $basename; +$vals{__XLAB__} = getConfig($basename, "X-Label"); +$vals{__YLAB__} = getConfig($basename, "Y-Label"); +$vals{__TITLE__} = getConfig($basename, "Title"); +$vals{__NAME_LABEL_LIST__} = filesToLabels(\@files); + +my $vars = labelsToVars($vals{__NAME_LABEL_LIST__}); + +$vals{__NAME_X_LIST__} = varsToXList($vars); +$vals{__NAME_Y_LIST__} = varsToYList($vars); +$vals{__COUNT__} = @files; + +my @names = split /[\"\,\s]+/, $vars; + +if($names[0] =~ /^\s*$/) { + shift @names; +} + + +$vals{__FILE__} = $files[0]; +$vals{__NAME__} = $names[0]; +$vals{__N__} = 0; + +print replaceAll($R_PREAMBLE, \%vals); +print replaceAll($R_READ, \%vals); + +for(my $n = 1 ; $n < @names; $n++) { + $vals{__FILE__} = $files[$n]; + $vals{__NAME__} = $names[$n]; + print replaceAll($R_READ, \%vals); +} + +$vals{__FILE__} = $files[0]; +$vals{__NAME__} = $names[0]; + + +print replaceAll($R_FIRST_PLOT, \%vals); + +for(my $n = 1 ; $n < @names; $n++) { + $vals{__FILE__} = $files[$n]; + $vals{__NAME__} = $names[$n]; + $vals{__N__} = $n; + + print replaceAll($R_NEXT_PLOT, \%vals); + +} + +print replaceAll($R_LEGEND, \%vals); +print replaceAll($R_FINISH, \%vals); + diff --git a/src/timing/t-distribution.tbl b/src/timing/t-distribution.tbl new file mode 100644 index 0000000..77ca65c --- /dev/null +++ b/src/timing/t-distribution.tbl @@ -0,0 +1,48 @@ +1 3.078 6.314 12.71 31.82 63.66 318.3 637 1 +2 1.886 2.920 4.303 6.965 9.925 22.330 31.6 2 +3 1.638 2.353 3.182 4.541 5.841 10.210 12.92 3 +4 1.533 2.132 2.776 3.747 4.604 7.173 8.610 4 +5 1.476 2.015 2.571 3.365 4.032 5.893 6.869 5 +6 1.440 1.943 2.447 3.143 3.707 5.208 5.959 6 +7 1.415 1.895 2.365 2.998 3.499 4.785 5.408 7 +8 1.397 1.860 2.306 2.896 3.355 4.501 5.041 8 +9 1.383 1.833 2.262 2.821 3.250 4.297 4.781 9 +10 1.372 1.812 2.228 2.764 3.169 4.144 4.587 10 +11 1.363 1.796 2.201 2.718 3.106 4.025 4.437 11 +12 1.356 1.782 2.179 2.681 3.055 3.930 4.318 12 +13 1.350 1.771 2.160 2.650 3.012 3.852 4.221 13 +14 1.345 1.761 2.145 2.624 2.977 3.787 4.140 14 +15 1.341 1.753 2.131 2.602 2.947 3.733 4.073 15 +16 1.337 1.746 2.120 2.583 2.921 3.686 4.015 16 +17 1.333 1.740 2.110 2.567 2.898 3.646 3.965 17 +18 1.330 1.734 2.101 2.552 2.878 3.610 3.922 18 +19 1.328 1.729 2.093 2.539 2.861 3.579 3.883 19 +20 1.325 1.725 2.086 2.528 2.845 3.552 3.850 20 +21 1.323 1.721 2.080 2.518 2.831 3.527 3.819 21 +22 1.321 1.717 2.074 2.508 2.819 3.505 3.792 22 +23 1.319 1.714 2.069 2.500 2.807 3.485 3.768 23 +24 1.318 1.711 2.064 2.492 2.797 3.467 3.745 24 +25 1.316 1.708 2.060 2.485 2.787 3.450 3.725 25 +26 1.315 1.706 2.056 2.479 2.779 3.435 3.707 26 +27 1.314 1.703 2.052 2.473 2.771 3.421 3.690 27 +28 1.313 1.701 2.048 2.467 2.763 3.408 3.674 28 +29 1.311 1.699 2.045 2.462 2.756 3.396 3.659 29 +30 1.310 1.697 2.042 2.457 2.750 3.385 3.646 30 +32 1.309 1.694 2.037 2.449 2.738 3.365 3.622 32 +34 1.307 1.691 2.032 2.441 2.728 3.348 3.601 34 +36 1.306 1.688 2.028 2.434 2.719 3.333 3.582 36 +38 1.304 1.686 2.024 2.429 2.712 3.319 3.566 38 +40 1.303 1.684 2.021 2.423 2.704 3.307 3.551 40 +42 1.302 1.682 2.018 2.418 2.698 3.296 3.538 42 +44 1.301 1.680 2.015 2.414 2.692 3.286 3.526 44 +46 1.300 1.679 2.013 2.410 2.687 3.277 3.515 46 +48 1.299 1.677 2.011 2.407 2.682 3.269 3.505 48 +50 1.299 1.676 2.009 2.403 2.678 3.261 3.496 50 +55 1.297 1.673 2.004 2.396 2.668 3.245 3.476 55 +60 1.296 1.671 2.000 2.390 2.660 3.232 3.460 60 +65 1.295 1.669 1.997 2.385 2.654 3.220 3.447 65 +70 1.294 1.667 1.994 2.381 2.648 3.211 3.435 70 +80 1.292 1.664 1.990 2.374 2.639 3.195 3.416 80 +100 1.290 1.660 1.984 2.364 2.626 3.174 3.390 100 +150 1.287 1.655 1.976 2.351 2.609 3.145 3.357 150 +200 1.286 1.653 1.972 2.345 2.601 3.131 3.340 200 diff --git a/src/timing/timer.pl b/src/timing/timer.pl new file mode 100755 index 0000000..ff904a2 --- /dev/null +++ b/src/timing/timer.pl @@ -0,0 +1,116 @@ +#! /usr/bin/perl -w + +use strict; + + +my $CI80 = 1; +my $CI90 = 2; +my $CI95 = 3; +my $CI98 = 4; +my $CI99 = 5; +my $CI99_8 = 6; +my $CI99_9 = 7; + +### How tight should the CI be? +my $myCI = $CI95; + +my $maxRuns = 20; +my $plusMinus = 0.05; + + +my @ttbl; + +sub parse_t_distribution { + ## Takes the t-distribution.tbl file, and parses it into a nice, fat array. + + open (T, "/home/morph/bin/t-distribution.tbl") || die "No T dist! $!"; + my $i =0; + while(my $line = ) { + my @tok = split /\s+/, $line; + pop @tok; ## Remove trailing n. + + while($i < $tok[0]) { + push @ttbl, \@tok; + $i++; +# print("$i " . join ("-", @tok) . "\n"); + } + } + +} + +sub runit { + my $cmd = shift; + + `rm storefile.txt logfile.txt blob0_file.txt blob1_file.txt; sync`; + + my $start_sec = `getTimeOfDay`; + + + chomp($start_sec); + + system($cmd); + + my $end_sec = `getTimeOfDay`; + + chomp($end_sec); + + my $time = ($end_sec - $start_sec) / 1000.0; + + return $time; + +} + +parse_t_distribution; + + +while (my $cmd = <>) { + + my $sum_x = 0; + my $sum_x_squared = 0; + my $n = 0; + + my $variance = 100000; + my $mean = 0; + + my $x = 0; + my $s = 10; + + + my $max_range = 0; + my $cur_range = 1; + while( 1 ) { + if ($n > 2) { + if($maxRuns < $n) { + last; + } + if($cur_range < $max_range) { + last; + } + } + $x = runit($cmd); + + $n++; + $sum_x += $x; + $sum_x_squared += ($x * $x); + + $variance = ($sum_x_squared/$n) - ($sum_x/$n)*($sum_x/$n); + $mean = $sum_x / $n; + + my $s = sqrt($variance/$n); + + my $sigma = sqrt($variance); + + print("Time: $x s: $s Mean: $mean Stdev: $sigma\n"); + + $cur_range = $s * $ttbl[$n-1][$myCI]; + $max_range = $plusMinus * $mean; + + } + if($cur_range > $max_range) { + printf("CI FAILED. mean was: $mean\t$cmd\n"); + } else { + printf("CI mean was: $mean\t$cmd\n"); + } +} + + diff --git a/src/timing/timer.pl-old b/src/timing/timer.pl-old new file mode 100755 index 0000000..fcb670a --- /dev/null +++ b/src/timing/timer.pl-old @@ -0,0 +1,91 @@ +#! /usr/bin/perl -w + +use strict; + + +my $CI80 = 1; +my $CI90 = 2; +my $CI95 = 3; +my $CI98 = 4; +my $CI99 = 5; +my $CI99_8 = 6; +my $CI99_9 = 7; + +### How tight should the CI be? +my $myCI = $CI95; + +my $maxRuns = 20; +my $plusMinus = 0.05; + + +my @ttbl; + +sub parse_t_distribution { + ## Takes the t-distribution.tbl file, and parses it into a nice, fat array. + + open (T, "~/bin/t-distribution.tbl") || die "No T dist! $!"; + my $i =0; + while(my $line = ) { + my @tok = split /\s+/, $line; + pop @tok; ## Remove trailing n. + + while($i < $tok[0]) { + push @ttbl, \@tok; + $i++; +# print("$i " . join ("-", @tok) . "\n"); + } + } + +} + +sub runit { + my $cmd = shift; + my $start_sec = `getTimeOfDay`; + + chomp($start_sec); + + system($cmd); + + my $end_sec = `getTimeOfDay`; + + chomp($end_sec); + + my $time = $end_sec - $start_sec / 1000.0; + + return $time; + +} + +parse_t_distribution; + + +while (my $cmd = <>) { + + my $sum_x = 0; + my $sum_x_squared = 0; + my $n = 0; + + my $variance = 100000; + my $mean = 1; + + my $x = 0; + my $s = 10; + + while($maxRuns > $n && ($s * $ttbl[$n-1][$myCI] > $plusMinus * $mean)) { + + $x = runit($cmd); + + $n++; + $sum_x += $x; + $sum_x_squared += ($x * $x); + + $variance = ($sum_x_squared/$n) - ($sum_x/$n)*($sum_x/$n); + $mean = $sum_x / $n; + + my $s = sqrt($variance/$n); + + } + +} + + diff --git a/src/timing/timer.pl-olf b/src/timing/timer.pl-olf new file mode 100755 index 0000000..2fd2c88 --- /dev/null +++ b/src/timing/timer.pl-olf @@ -0,0 +1,117 @@ +#! /usr/bin/perl -w + +use strict; + + +my $CI80 = 1; +my $CI90 = 2; +my $CI95 = 3; +my $CI98 = 4; +my $CI99 = 5; +my $CI99_8 = 6; +my $CI99_9 = 7; + +### How tight should the CI be? +my $myCI = $CI95; + +my $maxRuns = 20; +my $plusMinus = 0.05; + + +my @ttbl; + + +sub parse_t_distribution { + ## Takes the t-distribution.tbl file, and parses it into a nice, fat array. + + open (T, "/home/morph/bin/t-distribution.tbl") || die "No T dist! $!"; + my $i =0; + while(my $line = ) { + my @tok = split /\s+/, $line; + pop @tok; ## Remove trailing n. + + while($i < $tok[0]) { + push @ttbl, \@tok; + $i++; +# print("$i " . join ("-", @tok) . "\n"); + } + } + +} + +sub runit { + my $cmd = shift; + + `rm storefile.txt logfile.txt blob0_file.txt blob1_file.txt; sync`; + + my $start_sec = `getTimeOfDay`; + + + chomp($start_sec); + + system($cmd); + + my $end_sec = `getTimeOfDay`; + + chomp($end_sec); + + my $time = ($end_sec - $start_sec) / 1000.0; + + return $time; + +} + +parse_t_distribution; + + +while (my $cmd = <>) { + + my $sum_x = 0; + my $sum_x_squared = 0; + my $n = 0; + + my $variance = 100000; + my $mean = 0; + + my $x = 0; + my $s = 10; + + + my $max_range = 0; + my $cur_range = 1; + while( 1 ) { + if ($n > 2) { + if($maxRuns < $n) { + last; + } + if($cur_range < $max_range) { + last; + } + } + $x = runit($cmd); + + $n++; + $sum_x += $x; + $sum_x_squared += ($x * $x); + + $variance = ($sum_x_squared/$n) - ($sum_x/$n)*($sum_x/$n); + $mean = $sum_x / $n; + + my $s = sqrt($variance/$n); + + my $sigma = sqrt($variance); + + print("Time: $x s: $s Mean: $mean Stdev: $sigma\n"); + + $cur_range = $s * $ttbl[$n-1][$myCI]; + $max_range = $plusMinus * $mean; + + } + if($cur_range > $max_range) { + printf("CI FAILED. mean was: $mean\t$cmd\n"); + } else { + printf("CI mean was: $mean\t$cmd\n"); + } +} + + diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/test/2pc/Makefile.am b/test/2pc/Makefile.am new file mode 100644 index 0000000..c32027f --- /dev/null +++ b/test/2pc/Makefile.am @@ -0,0 +1,4 @@ +LDADD=$(top_builddir)/src/2pc/lib2pc.a $(top_builddir)/src/libdfa/libdfa.a \ + $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a +bin_PROGRAMS=always_commit +AM_CFLAGS= -g -Wall -pedantic -std=gnu99 diff --git a/test/2pc/always_commit.c b/test/2pc/always_commit.c new file mode 100644 index 0000000..6cfe6c3 --- /dev/null +++ b/test/2pc/always_commit.c @@ -0,0 +1,151 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../src/2pc/2pc.h" + +#include +#include + +#define TRUE 1 +#define FALSE 0 + +char** broadcast_lists[2]; +char* star_nodes[] = { "127.0.0.1:10010" }; +char* point_nodes[] = { "127.0.0.1:10011", + "127.0.0.1:10012", + "127.0.0.1:10013", + "127.0.0.1:10014", + "127.0.0.1:10015" }; + +state_name always_prepare(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + return SUBORDINATE_PREPARED_2PC; +} +state_name assert_false(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + assert(0); + return FALSE; +} +state_name print_commit(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + printf("commit xid:%ld\n", stateMachine->machine_id); + return TRUE; +} + +short bc_group_1(DfaSet* dfaSet, Message * m) { + return 1; +} + +int broadcast_list_host_count [] = { 1, 5 }; + +int broadcast_lists_count = 2; + +int main (int argc, char ** argv) { + + short port; + DfaSet * dfaSet; + TwoPCAppState * app_state; + char * localhost; + assert(argc >= 2); + + broadcast_lists[0] = star_nodes; + broadcast_lists[1] = point_nodes; + + app_state = malloc(sizeof(TwoPCAppState)); + + if (!strcmp(argv[1], "c")) { + assert(argc == 2); + port = parse_port(broadcast_lists[0][0]); + app_state->is_coordinator = TRUE; + dfaSet = dfa_malloc(DFA_MACHINE_COUNT, port, broadcast_lists, + broadcast_lists_count, broadcast_list_host_count); + + localhost = broadcast_lists[0][0]; + } else if (!strcmp(argv[1], "s")) { + int replica; + + assert(argc == 3); + replica = atoi(argv[2]); + port = parse_port(broadcast_lists[1][replica]); + app_state->is_coordinator = FALSE; + dfaSet = dfa_malloc(DFA_MACHINE_COUNT * 10, port, broadcast_lists, + broadcast_lists_count, broadcast_list_host_count); + localhost = broadcast_lists[1][replica]; + }else { + Message * m = malloc (sizeof (Message)); + NetworkSetup * ns = malloc(sizeof(NetworkSetup)); + init_network_broadcast(ns, 12345, "127.0.0.1:12345", broadcast_lists, broadcast_lists_count, broadcast_list_host_count); + + m->to_machine_id = atoi(argv[2]); + m->from_machine_id = m->to_machine_id; + m->type = NULL_STATE; + + send_message(ns, m, "bc:0"); + + return 0; + } + + + + if(dfa_reinitialize(dfaSet, localhost, transitions_2pc, transition_count_2pc, states_2pc, state_count_2pc) < 0) { + perror("dfa_reinitialize failed"); + } + + + app_state->init_xact_2pc = NULL; + app_state->veto_or_prepare_2pc = &always_prepare; + app_state->abort_2pc = &assert_false; + app_state->commit_2pc = &print_commit; + app_state->get_broadcast_group = &bc_group_1; + app_state->tally_2pc = NULL; + + dfaSet->app_setup = app_state; + + if(!strcmp(argv[1], "c")) { + + main_loop(dfaSet); + } else if (!strcmp(argv[1], "s")) { + main_loop(dfaSet); + + } + + + printf("transition_count_2pc=%d\n", transition_count_2pc); + printf("transitions[0].initial_state=%d\n", transitions_2pc[0].remote_state); + return 0; +} diff --git a/test/2pc/always_commit_script b/test/2pc/always_commit_script new file mode 100644 index 0000000..42ed454 --- /dev/null +++ b/test/2pc/always_commit_script @@ -0,0 +1,2 @@ +perl -e 'for(my $i =0 ; $i < 10000; $i++) { `./always_commit r $i`; `sleep .01`;}' + diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..403c178 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,11 @@ +SUBDIRS = lladd monotree messages dfa 2pc cht +INCLUDES = @CHECK_CFLAGS@ +if HAVE_CHECK +TESTS = check_check +else +TESTS = +endif +noinst_PROGRAMS = $(TESTS) +check_check_SOURCES = check_check.c +check_check_LDADD = @CHECK_LIBS@ +CLEANFILES = check_check.log diff --git a/test/README.coredumps b/test/README.coredumps new file mode 100644 index 0000000..14ca9ab --- /dev/null +++ b/test/README.coredumps @@ -0,0 +1,5 @@ +To obtain a coredump from a test that crashes, run this command: + +export CK_FORK=no + +This will prevent check from forking on each test, so that you can obtain a normal core dump. diff --git a/test/check_check.c b/test/check_check.c new file mode 100644 index 0000000..a2759d9 --- /dev/null +++ b/test/check_check.c @@ -0,0 +1,96 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include + +#define LOG_NAME "check_check.log" + +/** @test A trivial test case for check_check +*/ +START_TEST(core_succ) +{ + fail_unless(1==1, "core test suite"); +} +END_TEST + +/** + @test A second trivial test case for check_check. +*/ +START_TEST(core_fail) +{ + fail_unless(0==0, "i shouldn't fail anymore"); +} +END_TEST + +/** + @test A second trivial test case for check_check. +*/ +START_TEST(core_last) +{ + fail_unless(0==0, "i shouldn't fail anymore"); +} +END_TEST + +/** + Add suite declarations here +*/ +Suite * check_suite(void) { + Suite *s = suite_create("check"); + /* Begin a new test */ + TCase *tc = tcase_create("core"); + + /* Sub tests are added, one per line, here */ + tcase_add_test(tc, core_succ); + tcase_add_test(tc, core_fail); + /* --------------------------------------------- */ + suite_add_tcase(s, tc); + + tc = tcase_create("second"); + + tcase_add_test(tc, core_last); + + suite_add_tcase(s, tc); + return s; +} + +#include "check_setup.h" diff --git a/test/check_includes.h b/test/check_includes.h new file mode 100644 index 0000000..1d57198 --- /dev/null +++ b/test/check_includes.h @@ -0,0 +1,11 @@ +void setup (void) { + remove("logfile.txt"); + remove("storefile.txt"); + remove("blob0_file.txt"); + remove("blob1_file.txt"); +} + +void teardown(void) { + setup(); +} + diff --git a/test/check_setup.h b/test/check_setup.h new file mode 100644 index 0000000..a5475e8 --- /dev/null +++ b/test/check_setup.h @@ -0,0 +1,56 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** A simple test utility to make sure that check is installed and working. + */ + +int main() { + int nf; + Suite *s = check_suite(); + SRunner *sr = srunner_create(s); + + srunner_set_log(sr, LOG_NAME); + srunner_run_all(sr, CK_NORMAL); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + suite_free(s); + return (nf == 0) ? 0 : 1; +} diff --git a/test/cht/Makefile.am b/test/cht/Makefile.am new file mode 100644 index 0000000..3cbea94 --- /dev/null +++ b/test/cht/Makefile.am @@ -0,0 +1,4 @@ +LDADD=$(top_builddir)/src/apps/cht/libcht.a $(top_builddir)/src/2pc/lib2pc.a $(top_builddir)/src/libdfa/libdfa.a \ + $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a +bin_PROGRAMS=simple cht_server +AM_CFLAGS= -g -Wall -pedantic -std=c99 diff --git a/test/cht/cht_server.c b/test/cht/cht_server.c new file mode 100644 index 0000000..0beb244 --- /dev/null +++ b/test/cht/cht_server.c @@ -0,0 +1,126 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../src/apps/cht/cht.h" +#include + +/** Thanks, jbhtsimple.c!! */ + +#define C "140.254.26.214:10010" +#define CLIENT "140.254.26.223:12345" +#define S0 "140.254.26.249:10010" +#define S1 "140.254.26.250:10010" +#define S2 "140.254.26.247:10010" +#define S3 "140.254.26.226:10010" +/* +#define C "127.0.0.1:10010" +#define CLIENT "127.0.0.1:12345" +#define S0 "127.0.0.1:10011" +#define S1 "127.0.0.1:10012" +#define S2 "127.0.0.1:10013" +#define S3 "127.0.0.1:10014" +*/ + +char** broadcast_lists[100]; +char* star_nodes[] = { C }; +char* point_nodes[] = { S0, S1, S2, S3, }; +char* ointp_nodes[] = { S2, S0, S1, S1, }; +char* intpo_nodes[] = { S1, S2, S0, S0, }; +char* ntpoi_nodes[] = { S3, S0, S1, S2, }; +char* tpoin_nodes[] = { S0, S1, S2, S3, }; + + +int broadcast_list_host_count [] = { 1, 3, 1, 1, 1, 1}; + +int broadcast_lists_count = 6; + + +int main (int argc, char**argv) { + + DfaSet * dfaSet; + + int server_type; + short port; + + char * localhost; + + assert(argc == 8); + + Tinit(); + + + broadcast_lists[0] = star_nodes; + broadcast_lists[1] = point_nodes; + broadcast_lists[2] = point_nodes; + broadcast_lists[3] = ointp_nodes; + broadcast_lists[4] = intpo_nodes; + broadcast_lists[5] = ntpoi_nodes; + broadcast_lists[6] = tpoin_nodes; + + broadcast_lists_count = atoi(argv[3]) + 2; + + broadcast_list_host_count[2] = atoi(argv[4]); + broadcast_list_host_count[3] = atoi(argv[5]); + broadcast_list_host_count[4] = atoi(argv[6]); + broadcast_list_host_count[5] = atoi(argv[7]); + + + if(argv[1][0] == 'c') { + server_type = CHT_COORDINATOR; + } else { + server_type = CHT_SERVER; + } + + if(server_type == CHT_COORDINATOR) { + localhost = broadcast_lists[0][0]; + + } else { + localhost = broadcast_lists[atoi(argv[1])][atoi(argv[2])]; + } + port = parse_port(localhost); + Tinit(); + dfaSet = cHtInit(server_type, localhost, NULL, port, broadcast_lists, broadcast_lists_count, broadcast_list_host_count); + + main_loop(dfaSet); + + return -1; + +} diff --git a/test/cht/simple.c b/test/cht/simple.c new file mode 100644 index 0000000..a440f90 --- /dev/null +++ b/test/cht/simple.c @@ -0,0 +1,168 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../src/apps/cht/cht.h" +#include + +#include + +/** Thanks, jbhtsimple.c!! */ + +char** broadcast_lists[2]; +char* star_nodes[] = { "140.254.26.214:10010" }; +char* point_nodes[] = { "127.0.0.1:10011", + "127.0.0.1:10012", + "127.0.0.1:10013", + "127.0.0.1:10014", + "127.0.0.1:10015" }; + +int broadcast_list_host_count [] = { 1, 5 }; + +int broadcast_lists_count = 1; + + +typedef struct { + int key; + char *value; +} test_pair_t; + +int main (int argc, char**argv) { + + + test_pair_t one; + test_pair_t two; + test_pair_t three; + test_pair_t four; + + test_pair_t one_s = {1 , "one"}; + test_pair_t two_s = {2 , "two"}; + test_pair_t three_s = {3 , "three"}; + test_pair_t four_s = {4 , "four"}; + + int i; + state_machine_id xid; + + DfaSet * dfaSet; + clusterHashTable_t ht; + + + memcpy(&one, &one_s, sizeof(test_pair_t)); + memcpy(&two, &two_s, sizeof(test_pair_t)); + memcpy(&three, &three_s, sizeof(test_pair_t)); + memcpy(&four, &four_s, sizeof(test_pair_t)); + + one.value = strdup(one_s.value); + two.value = strdup(two_s.value); + three.value = strdup(three_s.value); + four.value = strdup(four_s.value); + + assert(argc == 3); + + Tinit(); + + broadcast_lists[0] = star_nodes; + broadcast_lists[1] = point_nodes; + + dfaSet = cHtInit(CHT_CLIENT, argv[2], NULL, atoi(argv[1]), broadcast_lists, broadcast_lists_count, broadcast_list_host_count); + + spawn_main_thread(dfaSet); + + xid = NULL_MACHINE; + /* assert ( cHtGetXid(&xid, dfaSet)); */ + + printf("Got xid: %ld\n", xid); + + printf("cHtCreate\n"); + fflush(NULL); + + + assert( cHtCreate(xid, dfaSet, &ht) ); + + + printf("Got hashtable: %d\n", ht.id); + + printf("cHtInserts\n"); + fflush(NULL); + + if( (!cHtInsert(xid, dfaSet, &ht, &one.key, sizeof(int), one.value, sizeof(char)*4)) || + (!cHtInsert(xid, dfaSet, &ht, &two.key, sizeof(int), two.value, sizeof(char)*4)) || + (!cHtInsert(xid, dfaSet, &ht, &three.key, sizeof(int), three.value, sizeof(char)*6)) || + (!cHtInsert(xid, dfaSet, &ht, &four.key, sizeof(int), four.value, sizeof(char)*5)) + ) { + printf("Insert failed! \n"); + return -1; + } + for(i = 0; i < 99; i++) { + one.key+=4; + two.key+=4; + three.key+=4; + four.key+=4; + if( (!cHtInsert(xid, dfaSet, &ht, &one.key, sizeof(int), one.value, sizeof(char)*4)) || + (!cHtInsert(xid, dfaSet, &ht, &two.key, sizeof(int), two.value, sizeof(char)*4)) || + (!cHtInsert(xid, dfaSet, &ht, &three.key, sizeof(int), three.value, sizeof(char)*6)) || + (!cHtInsert(xid, dfaSet, &ht, &four.key, sizeof(int), four.value, sizeof(char)*5)) + ) { + printf("Insert failed! \n"); + return -1; + } + } + + printf("Last key: %d\n", four.key); + + /* assert ( cHtGetXid(&xid, dfaSet)); */ + + for( i = 1; i <= 400; i++ ) { + char buf[7]; + size_t buflen = 7; + /* int j = (i % 8) + 1;*/ + int j = i; + if(!cHtLookup(xid, dfaSet, &ht, &j, sizeof(int), buf, &buflen)) { printf ("lookup failed!"); } + printf(" looked up !! key %d -> %d: %s %d\n", i, j, buf, buflen); + } + + cHtDelete(xid, dfaSet, &ht); + + return 0; + +} + + + diff --git a/test/dfa/Makefile.am b/test/dfa/Makefile.am new file mode 100644 index 0000000..9b65314 --- /dev/null +++ b/test/dfa/Makefile.am @@ -0,0 +1,3 @@ +LDADD=$(top_builddir)/src/libdfa/libdfa.a $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a +bin_PROGRAMS=ping_pong_dfa fork_bomb star +AM_FLAGS= -g -Wall -pedantic -std=c99 diff --git a/test/dfa/fork_bomb.c b/test/dfa/fork_bomb.c new file mode 100644 index 0000000..03b3aa9 --- /dev/null +++ b/test/dfa/fork_bomb.c @@ -0,0 +1,193 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../libdfa/libdfa.h" +#include +#include +#include +#include +#include +callback_fcn recv_new, recv_ack; + +#define FORKED 1 + + /* + + ->START + | + | + <-| <--- S:S->F1 + FORKED START:nil->S ----> + | + | <--- S:F1->nil + | START:nil->S ----> + ----- + --- + - + + TODO: Need api to let me say: + + Abort timeout is 5 sec. + Infininte retry timout. + + What does infinite retry timeout mean for recovery? + + Should it be supported by libdfa? + + */ + +int main (int argc, char** argv) { + DfaSet * dfaSet = calloc(1, sizeof(DfaSet)); + /* callback_fcn* callbacks[MAX_MESSAGE_COUNT]; */ + + Transition * transitions = malloc (sizeof(Transition) * 3); + + State * states = malloc(sizeof(State) * MAX_STATE_COUNT); + /* StateMachine initial_sm1_stack; */ + StateMachine * initial_sm1; + int transition_count; + + /* dfaSet->monoTree.buffer = calloc(DFA_MACHINE_COUNT, sizeof(StateMachine)); + dfa_initialize_new (dfaSet, 10001, DFA_MACHINE_COUNT); */ + /* dfaSet->monoTree.buffer = calloc(100, sizeof(StateMachine)); */ + dfa_initialize_new (dfaSet, 10001, 1000); + + /* initial_sm1 = allocMachine(&(dfaSet->monoTree)); */ + assert(NULL != (initial_sm1 = allocSmash(dfaSet->smash))); + + initial_sm1->message.from_machine_id = initial_sm1->machine_id; + initial_sm1->message.to_machine_id = NULL_MACHINE; + initial_sm1->message.type = NULL_STATE; + /* What to do here ???? + initial_sm1->message.machine_id = initial_sm2->machine_id; + initial_sm2->message.machine_id = initial_sm1->machine_id; + */ + + printf("sm1 %ld\n", initial_sm1->machine_id); + + initial_sm1->current_state = START_STATE; + + initial_sm1->last_transition = (time_t)0; + + strcpy(initial_sm1->message_recipient, "127.0.0.1:10001"); + + setSmash(dfaSet->smash, initial_sm1->machine_id); + + states[0].name = FORKED; + states[0].retry_fcn = NULL; + states[0].abort_fcn = NULL; + + transitions[0].remote_state = NULL_STATE; + transitions[0].pre_state = NULL_STATE; + transitions[0].post_state = START_STATE; + transitions[0].fcn_ptr = &recv_new; + transitions[0].force = 0; + + transitions[1].remote_state = START_STATE; + transitions[1].pre_state = START_STATE; + transitions[1].post_state = FORKED; + transitions[1].fcn_ptr = &recv_ack; + transitions[1].force = 0; + + transitions[2].remote_state = START_STATE; + transitions[2].pre_state = FORKED; + transitions[2].post_state = NULL_STATE; + transitions[2].fcn_ptr = &recv_ack; + transitions[2].force = 0; + + /* Needed for bootstrap... */ + + transitions[3].remote_state = START_STATE; + transitions[3].pre_state = NULL_STATE; + transitions[3].post_state = START_STATE; + transitions[3].fcn_ptr = &recv_new; + transitions[3].force = 0; + + transition_count = 4; + + if(dfa_reinitialize(dfaSet, "127.0.0.1:10001", transitions, transition_count, states, 1) < 0) { + printf("Error. Exiting.\n"); + } + + main_loop(dfaSet); + + + return 0; +} + +void send_new_fork_request(DfaSet * dfaSet, StateMachine * stateMachine, char * from) { + + Message new_m; + + new_m.from_machine_id = stateMachine->machine_id; + new_m.to_machine_id = NULL_MACHINE; + new_m.type = NULL_STATE; + + send_message(&(dfaSet->networkSetup), &(new_m), from); +} + +state_name recv_new(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + if(stateMachine == NULL) { + printf("Got a request for a new thread from %s, machine %ld\n", from, m->from_machine_id); + } else { + printf("%d: Machine %ld got a request for a new thread from %s, machine %ld\n", stateMachine->current_state, stateMachine->machine_id, + from, m->from_machine_id); + send_new_fork_request(dfaSet, stateMachine, from); + } + + + return 1; +} + +state_name recv_ack(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + if(stateMachine != NULL) { + printf("%d: Machine %ld heard back from child: from %s : machine %ld\n", stateMachine->current_state, stateMachine->machine_id, + from, m->from_machine_id); + send_new_fork_request(dfaSet, stateMachine, from); + return 1; + } else { + printf("Dropping ack for machine that doesn't exist.\n"); + return 0; + } + + +} + diff --git a/test/dfa/ping_pong_dfa.c b/test/dfa/ping_pong_dfa.c new file mode 100644 index 0000000..8b5919e --- /dev/null +++ b/test/dfa/ping_pong_dfa.c @@ -0,0 +1,162 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../libdfa/libdfa.h" +#include +#include +#include +#include +#include +callback_fcn recv_ping, recv_pong; + +#define PING1 3 +#define PING2 4 +#define PONG1 1 +#define PONG2 2 +int main (int argc, char** argv) { + DfaSet * dfaSet = calloc(1, sizeof(DfaSet)); + /* callback_fcn* callbacks[MAX_MESSAGE_COUNT]; */ + + Transition * transitions = malloc (sizeof(Transition) * 4); + + State * states = malloc(sizeof(State) * MAX_STATE_COUNT); + StateMachine * initial_sm1; + StateMachine * initial_sm2; + int i; + + /*dfaSet->monoTree.buffer = calloc(DFA_MACHINE_COUNT, sizeof(StateMachine)); */ + dfa_initialize_new (dfaSet, 10000, DFA_MACHINE_COUNT); + for(i = 0; i < DFA_MACHINE_COUNT/4; i++) { + /* StateMachine initial_sm1_stack; + StateMachine initial_sm2_stack;*/ + + /* initial_sm1 = allocMachine(&(dfaSet->monoTree)); + initial_sm2 = allocMachine(&(dfaSet->monoTree)); */ + + initial_sm1 = allocSmash(dfaSet->smash); + initial_sm2 = allocSmash(dfaSet->smash); + + + initial_sm1->message.from_machine_id = initial_sm1->machine_id; + initial_sm1->message.to_machine_id = initial_sm2->machine_id; + initial_sm2->message.from_machine_id = initial_sm2->machine_id; + initial_sm2->message.to_machine_id = initial_sm1->machine_id; + + printf("sm1 %ld, sm2 %ld\n", initial_sm1->machine_id, initial_sm2->machine_id); + + initial_sm1->current_state = PING1; + initial_sm2->current_state = PONG1; + + initial_sm1->last_transition = (time_t)0; + initial_sm2->last_transition = (time_t)0; + + strcpy(initial_sm1->message_recipient, "127.0.0.1:10000"); + strcpy(initial_sm2->message_recipient, "127.0.0.1:10000"); + } + + states[0].name = PING1; + states[0].retry_fcn = NULL; + states[0].abort_fcn = NULL; + + states[1].name = PING2; + states[1].retry_fcn = NULL; + states[1].abort_fcn = NULL; + + states[2].name = PONG1; + states[2].retry_fcn = NULL; + states[2].abort_fcn = NULL; + + states[3].name = PONG2; + states[3].retry_fcn = NULL; + states[3].abort_fcn = NULL; + + transitions[0].remote_state = PONG1; + transitions[0].pre_state = PING1; + transitions[0].post_state= PING2; + transitions[0].fcn_ptr = &recv_ping; + transitions[0].force = 1; + + transitions[1].remote_state = PONG2; + transitions[1].pre_state = PING2; + transitions[1].post_state= PING1; + transitions[1].fcn_ptr = &recv_ping; + transitions[1].force = 1; + + transitions[2].remote_state = PING1; + transitions[2].pre_state = PONG2; + transitions[2].post_state= PONG1; + transitions[2].fcn_ptr = &recv_pong; + transitions[2].force = 1; + + transitions[3].remote_state = PING2; + transitions[3].pre_state = PONG1; + transitions[3].post_state= PONG2; + transitions[3].fcn_ptr = &recv_pong; + transitions[3].force = 1; + + if(dfa_reinitialize(dfaSet, "127.0.0.1:10000", transitions, 4, states, 4) < 0) { + printf("Error. Exiting.\n"); + } + + main_loop(dfaSet); + /* Can't get here. */ + return 0; +} + +state_name recv_ping(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + if(stateMachine != NULL) { + printf("%ld(%d): Got a ping from %s Machine %ld\n", stateMachine->machine_id, stateMachine->current_state, from, m->from_machine_id); + return 1; + } else { + printf("Got message from %s for non-existant machine.\n", from); + return 0; + } +} + +state_name recv_pong(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + if(stateMachine != NULL) { + printf("%ld(%d): Got a pong from %s Machine %ld\n", stateMachine->machine_id, stateMachine->current_state, from, m->from_machine_id); + return 1; + } else { + printf("Got message from %s for non-existant machine.\n", from); + return 0; + } +} diff --git a/test/dfa/star.c b/test/dfa/star.c new file mode 100644 index 0000000..8700e7d --- /dev/null +++ b/test/dfa/star.c @@ -0,0 +1,160 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../libdfa/libdfa.h" +#include "../../src/libdfa/callbacks.h" +#include "stdlib.h" +#include "string.h" +#include "stdio.h" +#include "assert.h" + +#define TRUE 1 +#define FALSE 0 + +char** broadcast_lists[2]; +char* star_nodes[] = { "127.0.0.1:10010" }; +char* point_nodes[] = { "127.0.0.1:10011", + "127.0.0.1:10012", + "127.0.0.1:10013", + "127.0.0.1:10014", + "127.0.0.1:10015" }; + + + + +int broadcast_list_host_count [] = { 1, 5 }; + +int broadcast_lists_count = 2; + +/* States */ + +#define HUB_START 101 + +#define POINT_START 201 + +callback_fcn tally_star, respond_once_star; + +State states_star[MAX_STATE_COUNT] = { + { HUB_START, NULL, NULL }, + { POINT_START, NULL, NULL }, + +}; + +Transition transitions_star[] = { + + {POINT_START, HUB_START, NULL_STATE, tally_star, FALSE}, + {HUB_START, NULL_STATE, POINT_START, respond_once_star, FALSE}, + +}; + +/*state_machine_id init_hub(DfaSet * dfaSet) { + StateMachine * initial_sm; + + initial_sm = allocMachine(&(dfaSet->monoTree)); + initial_sm->current_state = HUB_START; + initial_sm->message.from_machine_id = initial_sm->machine_id; + initial_sm->message.to_machine_id = NULL_MACHINE; + initial_sm->message.type = HUB_START; + + strcpy(initial_sm->message_recipient, "bc:1"); + return initial_sm->machine_id; + } + +void init_point(DfaSet * dfaSet, int node_number) { + +} */ + +int main (int argc, char ** argv) { + int list_number; + int node_number; + + + DfaSet * dfaSet; + short port; + + broadcast_lists[0] = star_nodes; + broadcast_lists[1] = point_nodes; + + assert(argc == 3); + + list_number = atoi(argv[1]); + node_number = atoi(argv[2]); + + assert(list_number < broadcast_lists_count); + assert(node_number < broadcast_list_host_count[list_number]); + + port = parse_port(broadcast_lists[list_number][node_number]); + + dfaSet = dfa_malloc(DFA_MACHINE_COUNT, port, broadcast_lists, + broadcast_lists_count, broadcast_list_host_count); + + if(list_number == 0) { + int ret; + + dfa_reinitialize(dfaSet, broadcast_lists[list_number][node_number], transitions_star, 2, states_star, 2); + + spawn_main_thread(dfaSet); + + ret =(int) request(dfaSet, HUB_START, "bc:1", NULL_MACHINE, NULL); + + printf("run_request_returned: %x\n", ret); + + } else { + + /* init_point(dfaSet, node_number); */ + + if(dfa_reinitialize(dfaSet, broadcast_lists[list_number][node_number], transitions_star, 2, states_star, 2) < 0) { + printf("Error. Exiting.\n"); + } + main_loop(dfaSet); + } + + return 0; +} + +state_name respond_once_star(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + respond_once(&((DfaSet*)dfaSet)->networkSetup, POINT_START, m, from); + return 0; +} + +state_name tally_star(void * dfaSet, StateMachine * stateMachine, Message * m, char * from) { + return tally(broadcast_lists[1], broadcast_list_host_count[1], (char*)(&(stateMachine->app_state)), from); +} diff --git a/test/lladd-old/Makefile b/test/lladd-old/Makefile new file mode 100644 index 0000000..9db1e27 --- /dev/null +++ b/test/lladd-old/Makefile @@ -0,0 +1,197 @@ +# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = ../.. + +prefix = /usr/local +exec_prefix = ${prefix} + +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 +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/hello +pkglibdir = $(libdir)/hello +pkgincludedir = $(includedir)/hello + +top_builddir = ../.. + +ACLOCAL = aclocal-1.4 +AUTOCONF = autoconf +AUTOMAKE = automake-1.4 +AUTOHEADER = autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL} +transform = s,x,x, + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = +host_triplet = i686-pc-linux-gnu +AR = ar +AS = @AS@ +CC = gcc +CHECK_CFLAGS = +CHECK_LIBS = -lcheck +CPP = gcc -E +CXX = g++ +CXXCPP = g++ -E +DLLTOOL = @DLLTOOL@ +ECHO = echo +EGREP = grep -E +EXEEXT = +F77 = g77 +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +HAVE_LIB = @HAVE_LIB@ +LIB = @LIB@ +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LN_S = ln -s +LTLIB = @LTLIB@ +MAKEINFO = makeinfo +OBJDUMP = @OBJDUMP@ +OBJEXT = o +PACKAGE = hello +RANLIB = ranlib +RC = @RC@ +STRIP = strip +VERSION = 0.1 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../[config.h] +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lladd-old/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = test/lladd-old + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu test/lladd-old/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/lladd-old/Makefile.am b/test/lladd-old/Makefile.am new file mode 100644 index 0000000..e69de29 diff --git a/test/lladd-old/TAbort.c b/test/lladd-old/TAbort.c new file mode 100644 index 0000000..b9d281a --- /dev/null +++ b/test/lladd-old/TAbort.c @@ -0,0 +1,94 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing with various strings + * *******************************/ +#include "test.h" +#include "rand_str.h" + +/*#define VERBOSE 0*/ + +int test(int argc, char **argv) { + + recordid rec; + int xid; + + int num_xactions; + int num_inserts_per_xaction; + char *string; + int i, j; + + if (argc != 3) { + printf("usage: %s +#include "test.h" + +#define VERBOSE 1 +#define SEED 5095 + +int test(int argc, char **argv) { + recordid rec; + int num_trials; + /* counters */ + int i; + + char *out_buffer = (char *)malloc(sizeof(char) * 300); + + if (argc != 2) { + printf("usage: %s \n", argv[0]); + exit(-1); + } + + num_trials = atoi(argv[1]); + srand(SEED); + + rec.page = 0; + + for (i = 0; i < num_trials; i++) { + rec.slot = i; + + Tread(0, rec, out_buffer); + + if (VERBOSE) { + printf("read [%s]\n", out_buffer); + } + + } + + return 0; +} diff --git a/test/lladd-old/TInsert.c b/test/lladd-old/TInsert.c new file mode 100644 index 0000000..f8f0998 --- /dev/null +++ b/test/lladd-old/TInsert.c @@ -0,0 +1,128 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing with various strings + * *******************************/ +#include +#include "test.h" + +#define VERBOSE 0 +#define SEED 5095 + +int test(int argc, char **argv) { + int xid; + recordid rec; + int num_trials; + /* counters */ + int i; + char c; + + /* used for making the random strings*/ + double r; + int start, end; + + /* used to make a long string */ + char first_printable_ascii = ' '; + char last_printable_ascii = '~'; + int ascii_length = (int)(last_printable_ascii - first_printable_ascii); + char *ASCII = (char *)malloc(sizeof(char) * ascii_length); + + /* an array of strings */ + char *string; + + /* if (argc != 2) { + printf("usage: %s argc=%d, %d\n", argv[0], argc, argc_orig); + exit(-1); + } */ + + InitiateRecovery(); + + /* create the long string from which random strings will be made */ + for (c = 0; c < ascii_length; c++) { + ASCII[(int)c] = first_printable_ascii + c; + } + if (argc != 2) { + printf("usage: %s \n", argv[0]); + exit(-1); + } + + num_trials = atoi(argv[1]); + srand(SEED); + + for (i = 0; i < num_trials; i++) { + start = 0; + end = 0; + while (start == end) { + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* returns [0, 1)*/ + r = r*ascii_length; + start = (int)r; /* an int in the rand [0, ascii_length) */ + + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* re turns [0, 1)*/ + r = r*ascii_length; + end = (int)r; /* an int in the rand [0, ascii_length) */ + } + if (end < start) { + int swap = start; + start = end; + end = swap; + } + + string = (char *)malloc(sizeof(char) * (end - start) + 1); + strncpy(string, ASCII + start, end-start); + string[end-start] = '\0'; /* make the string null terminated */ + xid = Tbegin(); + rec = Talloc(xid, sizeof(char)*(strlen(string) +1)); + if (VERBOSE) { + printf("%d, %s\n", i, string); + printf("rid is (%d, %d)\n", rec.page, rec.slot); + } + + Tset(xid, rec, string); + free (string); + Tcommit(xid); + + } + + return 0; +} diff --git a/test/lladd-old/TInsertSequential.c b/test/lladd-old/TInsertSequential.c new file mode 100644 index 0000000..9dd792d --- /dev/null +++ b/test/lladd-old/TInsertSequential.c @@ -0,0 +1,93 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing with various strings + * *******************************/ +#include "test.h" +#include "rand_str.h" + +/*#define VERBOSE 0*/ + +int test(int argc, char **argv) { + + recordid rec; + int xid; + + int num_xactions; + int num_inserts_per_xaction; + char *string; + int i, j; + + if (argc != 3) { + printf("usage: %s +/*#define VERBOSE 0*/ + +void nextRID(recordid *rp); +int test(int argc, char **argv) { + + recordid rec; + int xid; +char *buff; + + int num_xactions; + int num_inserts_per_xaction; + int i, j, k; + if (argc != 3) { + printf("usage: %s page = 0; + rp->slot = slot; + if (RIDS[page] == slot) { + page++; + slot = 0; + }else { + slot++; + } +} diff --git a/test/lladd-old/abort-speed.c b/test/lladd-old/abort-speed.c new file mode 100644 index 0000000..bf021fd --- /dev/null +++ b/test/lladd-old/abort-speed.c @@ -0,0 +1,101 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * how fast can we abort? does it depend on anything? + * *******************************/ + +#include +#include + +#include "test.h" + +#define TESTS 500 + +int test() +{ + struct timeval start, end, total; + recordid rids[TESTS]; + long commited[TESTS]; + long aborted[TESTS]; + long temp; + int i, j, xid = Tbegin(); + + for( i = 0; i < TESTS; i++ ) { + rids[i] = Talloc(xid, sizeof(long)); + commited[i] = random(); + aborted[i] = random(); + Tset(xid, rids[i], &commited[i]); + } + + gettimeofday(&start, NULL); + Tcommit(xid); + gettimeofday(&end, NULL); + timersub(&end, &start, &total); + printf("commit %u: %ld.%ld\n", TESTS, total.tv_sec, total.tv_usec); + + for( j = 0; j < 10; j++ ) { + + xid = Tbegin(); + + for( i = 0; i < TESTS*j; i++ ) { + Tset(xid, rids[random() % TESTS], &aborted[i%TESTS]); + } + + gettimeofday(&start, NULL); + Tabort(xid); + gettimeofday(&end, NULL); + timersub(&end, &start, &total); + printf("abort %u: %ld.%ld\n", TESTS*j, total.tv_sec, total.tv_usec); + + xid = Tbegin(); + for( i = 0; i < TESTS; i++ ) { + Tread( xid, rids[i], &temp ); + if( temp != commited[i] ) + return -1; + } + Tabort(xid); + } + + return 0; +} diff --git a/test/lladd-old/abort.c b/test/lladd-old/abort.c new file mode 100644 index 0000000..b039dd9 --- /dev/null +++ b/test/lladd-old/abort.c @@ -0,0 +1,116 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * aborting and committing transactions + * *******************************/ + +#include "test.h" + +int test() { + int xid_0; + int writeVal_0; + int readVal_0; + recordid rec_0; + + int xid_1; + int writeVal_1; + int readVal_1; + recordid rec_1; + + printf("\nRunning test4\n"); + + + + writeVal_0 = 314159265; + writeVal_1 = 271828183; + + xid_0 = Tbegin(); + xid_1 = Tbegin(); + + rec_0 = Talloc(xid_0, sizeof(int)); + rec_1 = Talloc(xid_1, sizeof(int)); + + Tset(xid_0, rec_0, &writeVal_0); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_0, rec_0.page, rec_0.slot, writeVal_0); + + Tset(xid_1, rec_1, &writeVal_1); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_1, rec_1.page, rec_1.slot, writeVal_1); + + Tread(xid_0, rec_0, &readVal_0); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, readVal_0); + + Tread(xid_1, rec_1, &readVal_1); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_1, rec_1.page, rec_1.slot, readVal_1); + + if(1) { + Tabort(xid_0); + printf("xid %d aborted\n", xid_0); + + Tcommit(xid_1); + printf("xid %d committed\n", xid_1); + } else { + + Tcommit(xid_0); + printf("xid %d committed\n", xid_0); + + Tabort(xid_1); + printf("xid %d aborted\n", xid_1); + } + + xid_0 = Tbegin(); + xid_1 = Tbegin(); + Tread(xid_0, rec_0, &readVal_0); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, readVal_0); + + Tread(xid_1, rec_1, &readVal_1); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_1, rec_1.page, rec_1.slot, readVal_1); + + Tcommit(xid_0); + Tcommit(xid_1); + + + + printf("\n"); + return 0; +} diff --git a/test/lladd-old/commit-speed.c b/test/lladd-old/commit-speed.c new file mode 100644 index 0000000..5ea5bb5 --- /dev/null +++ b/test/lladd-old/commit-speed.c @@ -0,0 +1,92 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * how fast can we abort? does it depend on anything? + * *******************************/ + +#include +#include + +#include "test.h" + +#define TESTS 500 + +int test() +{ + struct timeval start, end, total; + recordid rids[TESTS]; + long commited[TESTS]; + long aborted[TESTS]; + int i, j, xid = Tbegin(); + + for( i = 0; i < TESTS; i++ ) { + rids[i] = Talloc(xid, sizeof(long)); + commited[i] = random(); + aborted[i] = random(); + Tset(xid, rids[i], &commited[i]); + } + + gettimeofday(&start, NULL); + Tcommit(xid); + gettimeofday(&end, NULL); + timersub(&end, &start, &total); + printf("commit %u: %ld.%ld\n", TESTS, total.tv_sec, total.tv_usec); + + for( j = 0; j < 10; j++ ) { + + xid = Tbegin(); + + for( i = 0; i < TESTS*j; i++ ) { + Tset(xid, rids[random() % TESTS], &aborted[i%TESTS]); + } + + gettimeofday(&start, NULL); + Tcommit(xid); + gettimeofday(&end, NULL); + timersub(&end, &start, &total); + printf("commit %u: %ld.%ld\n", TESTS*j, total.tv_sec, total.tv_usec); + } + + return 0; +} diff --git a/test/lladd-old/db41/dbAbort.c b/test/lladd-old/db41/dbAbort.c new file mode 100644 index 0000000..67e645c --- /dev/null +++ b/test/lladd-old/db41/dbAbort.c @@ -0,0 +1,225 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include +#include +#include +#include +#include "../rand_str.h" + +#define DATABASE "access.db" +#define ENV_DIRECTORY "TXNAPP" + +/* #define VERBOSE 0 */ + + +int db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups); +void env_open(DB_ENV **dbenvp); +void env_dir_create(); + + +int main(int argc, char **argv) { + DB *dbp; + DB_ENV *dbenv; + DBT key, data; + db_recno_t recno; + DB_TXN *xid; + + int num_xactions; + int num_inserts_per_xaction; + char *string; + int i, j; + + + + if (argc != 3) { + printf("usage: %s \n", argv[0]); + exit(-1); + } + + num_xactions = atoi(argv[1]); + num_inserts_per_xaction = atoi(argv[2]); + + env_dir_create(); + env_open(&dbenv); + rand_str_init(); + + if (db_open(dbenv, &dbp, DATABASE, 0)) { + return (1); + } + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + recno = 1; + for (i = 1; i <= num_xactions; i++ ) { + + dbenv->txn_begin(dbenv, NULL, &xid, 0); + + for (j = 0; j < num_inserts_per_xaction; j++) { + + string = rand_str(); + + key.size = sizeof(recno); + key.data = &recno; + data.size = strlen(string) + 1; // + 1 for the null terminator + data.data = string; + +/* + if(VERBOSE) { + printf("%s\n", string); + } +*/ + dbp->put(dbp, xid, &key, &data, 0); + recno++; + /* Its unclear from BDB docs whether we should free string */ + } + + xid->abort(xid); + } + + + return 0; +} + + +int 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"); + return (1); + } + + + /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + return (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, NULL, name, NULL, DB_RECNO, + DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->open: %s", name); + return (1); + } + + + *dbp = db; + return (0); +} + + +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"); + dbenv->set_errfile(dbenv, stderr); + + + /* + * 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) { + (void)dbenv->close(dbenv, 0); + fprintf(stderr, "dbenv->open: %s: %s\n", + ENV_DIRECTORY, db_strerror(ret)); + exit (1); + } + + + *dbenvp = dbenv; +} + + +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); + } +} + diff --git a/test/lladd-old/db41/dbGet.c b/test/lladd-old/db41/dbGet.c new file mode 100644 index 0000000..3124e9b --- /dev/null +++ b/test/lladd-old/db41/dbGet.c @@ -0,0 +1,233 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include "../../pbl/jbhash.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define DATABASE "access.db" +#define ENV_DIRECTORY "TXNAPP" + +#define VERBOSE 0 +#define SEED 5095 +int db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups); + +void env_open(DB_ENV **dbenvp); + +void env_dir_create(); + + +int main(int argc, char **argv) { + DB *dbp; + DB_ENV *dbenv; + DBT key, data; + db_recno_t recno; + + int num_trials; + + if (argc != 2) { + printf("usage: %s \n", argv[0]); + exit(-1); + } + + + env_dir_create(); + env_open(&dbenv); + if (db_open(dbenv, &dbp, DATABASE, 0)) + return (1); + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + db_open(dbenv, &dbp, DATABASE, 0); + + + + num_trials = atoi(argv[1]); + for (recno = 1; (int)recno <= num_trials; recno++) { + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.size = sizeof(recno); + + + key.data = &recno; + data.flags = DB_DBT_MALLOC; + dbp->get(dbp, NULL, &key, &data, 0); + if (VERBOSE) { + printf("get got %s\n", (char *)data.data); + } + + } + + + + + return 0; + +} + + +int 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"); + return (1); + } + + + /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + return (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, NULL, name, NULL, DB_BTREE, + DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->open: %s", name); + return (1); + } + + + *dbp = db; + return (0); +} + + +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"); + dbenv->set_errfile(dbenv, stderr); + + + /* + * 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) { + (void)dbenv->close(dbenv, 0); + fprintf(stderr, "dbenv->open: %s: %s\n", + ENV_DIRECTORY, db_strerror(ret)); + exit (1); + } + + + *dbenvp = dbenv; +} + + +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); + } +} + + +/* +for (recno = 1; (int)recno <= num_trials; recno++) { + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.size = sizeof(recno); + + + key.data = &recno; + data.flags = DB_DBT_MALLOC; + dbp->get(dbp, NULL, &key, &data, 0); + + printf("get got %s\n", data.data); + + } + +*/ diff --git a/test/lladd-old/db41/dbInsert.c b/test/lladd-old/db41/dbInsert.c new file mode 100644 index 0000000..1f8b362 --- /dev/null +++ b/test/lladd-old/db41/dbInsert.c @@ -0,0 +1,251 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include "../../pbl/jbhash.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define DATABASE "access.db" +#define ENV_DIRECTORY "TXNAPP" + +#define VERBOSE 0 +#define SEED 5095 +int db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups); + +void env_open(DB_ENV **dbenvp); + +void env_dir_create(); + + +int main(int argc, char **argv) { + DB *dbp; + DB_ENV *dbenv; + DB_TXN *xid; + DBT key, data; + db_recno_t recno; + + int num_trials; + int ret; + char c; + + + double r; + int start, end; + + char first_printable_ascii = ' '; + char last_printable_ascii = '~'; + int ascii_length = (int)(last_printable_ascii - first_printable_ascii); + char *ASCII = (char *)malloc(sizeof(char) * ascii_length); + char *string; + + for (c = 0; c < ascii_length; c++) { + ASCII[(int)c] = first_printable_ascii + c; + } + + if (argc != 2) { + printf("usage: %s \n", argv[0]); + exit(-1); + } + + + env_dir_create(); + env_open(&dbenv); + if (db_open(dbenv, &dbp, DATABASE, 0)) + return (1); + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + num_trials = atoi(argv[1]); + for (recno = 1; (int)recno <= num_trials; recno++) { + start = 0; + end = 0; + while (start == end) { + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* returns [0, 1)*/ + r = r*ascii_length; + start = (int)r; /* an int in the rand [0, ascii_length) */ + + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* re turns [0, 1)*/ + r = r*ascii_length; + end = (int)r; /* an int in the rand [0, ascii_length) */ + } + if (end < start) { + int swap = start; + start = end; + end = swap; + } + + string = (char *)malloc(sizeof(char) * (end - start) + 1); + strncpy(string, ASCII + start, end-start); + string[end-start] = '\0'; /* make the string null terminated */ + + dbenv->txn_begin(dbenv, NULL, &xid, 0); + key.size = sizeof(recno); + key.data = &recno; + data.size = strlen(string) + 1; // + 1 for the null terminator + data.data = string; + switch (ret = dbp->put(dbp, xid, &key, &data, 0)) { + case 0: + xid->commit(xid, 0); + break; + default: + dbp->err(dbp, ret, "DB->put"); + xid->abort(xid); + break; + } + + + } + + + return 0; + +} + + +int 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"); + return (1); + } + + + /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + return (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, NULL, name, NULL, DB_BTREE, + DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->open: %s", name); + return (1); + } + + + *dbp = db; + return (0); +} + + +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"); + dbenv->set_errfile(dbenv, stderr); + + + /* + * 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) { + (void)dbenv->close(dbenv, 0); + fprintf(stderr, "dbenv->open: %s: %s\n", + ENV_DIRECTORY, db_strerror(ret)); + exit (1); + } + + + *dbenvp = dbenv; +} + + +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); + } +} + diff --git a/test/lladd-old/db41/dbInsertSequential.c b/test/lladd-old/db41/dbInsertSequential.c new file mode 100644 index 0000000..2614488 --- /dev/null +++ b/test/lladd-old/db41/dbInsertSequential.c @@ -0,0 +1,225 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include +#include +#include +#include +#include "../rand_str.h" + +#define DATABASE "access.db" +#define ENV_DIRECTORY "TXNAPP" + +/* #define VERBOSE 0 */ + + +int db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups); +void env_open(DB_ENV **dbenvp); +void env_dir_create(); + + +int main(int argc, char **argv) { + DB *dbp; + DB_ENV *dbenv; + DBT key, data; + db_recno_t recno; + DB_TXN *xid; + + int num_xactions; + int num_inserts_per_xaction; + char *string; + int i, j; + + + + if (argc != 3) { + printf("usage: %s \n", argv[0]); + exit(-1); + } + + num_xactions = atoi(argv[1]); + num_inserts_per_xaction = atoi(argv[2]); + + env_dir_create(); + env_open(&dbenv); + rand_str_init(); + + if (db_open(dbenv, &dbp, DATABASE, 0)) { + return (1); + } + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + recno = 1; + for (i = 1; i <= num_xactions; i++ ) { + + dbenv->txn_begin(dbenv, NULL, &xid, 0); + + for (j = 0; j < num_inserts_per_xaction; j++) { + + string = rand_str(); + + key.size = sizeof(recno); + key.data = &recno; + data.size = strlen(string) + 1; // + 1 for the null terminator + data.data = string; + +/* + if(VERBOSE) { + printf("%s\n", string); + } +*/ + dbp->put(dbp, xid, &key, &data, 0); + recno++; + /* Its unclear from BDB docs whether we should free string */ + } + + xid->commit(xid, 0); + } + + + return 0; +} + + +int 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"); + return (1); + } + + + /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + return (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, NULL, name, NULL, DB_RECNO, + DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->open: %s", name); + return (1); + } + + + *dbp = db; + return (0); +} + + +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"); + dbenv->set_errfile(dbenv, stderr); + + + /* + * 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) { + (void)dbenv->close(dbenv, 0); + fprintf(stderr, "dbenv->open: %s: %s\n", + ENV_DIRECTORY, db_strerror(ret)); + exit (1); + } + + + *dbenvp = dbenv; +} + + +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); + } +} + diff --git a/test/lladd-old/db41/dbUpdate.c b/test/lladd-old/db41/dbUpdate.c new file mode 100644 index 0000000..9629ca1 --- /dev/null +++ b/test/lladd-old/db41/dbUpdate.c @@ -0,0 +1,227 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/* + * NOTE: this test assumes that the database has num_xactions * num_inserts_per_xaction + * strings in the database, whose keys are the sequence 1, 2, 3, ... + */ + + +#include +#include +#include +#include +#include +#include + +#define DATABASE "access.db" +#define ENV_DIRECTORY "TXNAPP" + +/* #define VERBOSE 0 */ + + +int db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups); +void env_open(DB_ENV **dbenvp); +void env_dir_create(); + + +int main(int argc, char **argv) { + DB *dbp; + DB_ENV *dbenv; + DBT key, data; + db_recno_t recno; + DB_TXN *xid; + + int num_xactions; + int num_inserts_per_xaction; + int i, j, k; + char *string; + + if (argc != 3) { + printf("usage: %s \n", argv[0]); + exit(-1); + } + + num_xactions = atoi(argv[1]); + num_inserts_per_xaction = atoi(argv[2]); + + env_dir_create(); + env_open(&dbenv); + + if (db_open(dbenv, &dbp, DATABASE, 0)) { + return (1); + } + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + recno = 1; + for (i = 1; i <= num_xactions; i++) { + + dbenv->txn_begin(dbenv, NULL, &xid, 0); + + for (j = 0; j < num_inserts_per_xaction; j++) { + key.size = sizeof(recno); + key.data = &recno; + data.flags = DB_DBT_MALLOC; + dbp->get(dbp, xid, &key, &data, DB_RMW); + free(data.data); + + string = (char *) malloc(sizeof(char)*data.size); + + for (k = 0; k < data.size - 1; k++) { + string[k] = 'a'; + } + string[k] = '\0'; + data.data = string; + dbp->put(dbp, xid, &key, &data, 0); + + recno++; + /* Its unclear from BDB docs whether we should free string */ + } + + xid->commit(xid, 0); + } + + + return 0; +} + + +int 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"); + return (1); + } + + + /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + return (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, NULL, name, NULL, DB_RECNO, + DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + (void)db->close(db, 0); + dbenv->err(dbenv, ret, "db->open: %s", name); + return (1); + } + + + *dbp = db; + return (0); +} + + +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"); + dbenv->set_errfile(dbenv, stderr); + + + /* + * 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) { + (void)dbenv->close(dbenv, 0); + fprintf(stderr, "dbenv->open: %s: %s\n", + ENV_DIRECTORY, db_strerror(ret)); + exit (1); + } + + + *dbenvp = dbenv; +} + + +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); + } +} + diff --git a/test/lladd-old/db41/jbhashmany.c b/test/lladd-old/db41/jbhashmany.c new file mode 100644 index 0000000..9d5fdb6 --- /dev/null +++ b/test/lladd-old/db41/jbhashmany.c @@ -0,0 +1,199 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include "../../pbl/jbhash.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DATABASE "access.db" +#define ENV_DIRECTORY "TXNAPP" + + +void env_dir_create(void); +void env_open(DB_ENV **); + + + + +int main() { + DB *dbp; + DB_ENV *dbenv; + DB_TXN *xid; + DBT key, data; + const unsigned int INSERT_NUM = 100; + char value[22]; /* should be log INSERT_NUM */ + int ret, i, t_ret; + + env_dir_create(); + env_open(&dbenv); + + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + fprintf(stderr, "db_create: %s\n", db_strerror(ret)); + exit (1); + } + + dbenv->txn_begin(dbenv, NULL, &xid, 0); + if ((ret = dbp->open(dbp, + xid, 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.size = sizeof(int); + key.data = malloc(sizeof(int)); + data.data = value; + + for( i = 0; i < INSERT_NUM; i++ ) { + *((int*)key.data) = i; + data.size = sizeof(char)*strlen(data.data); + sprintf(value, "value: %u\n", i); + dbp->put(dbp, xid, &key, &data, 0); + } + + xid->commit(xid, 0); + dbenv->txn_begin(dbenv, NULL, &xid, 0); + + for( i = 0; i < INSERT_NUM; i++ ) { + *((int*)key.data) = i; + dbp->get(dbp, xid, &key, &data, 0); + printf("db: %u: key retrieved: data was %s.\n", *((int*)key.data), (char *)data.data); + } + + xid->abort(xid); + +err: if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) + ret = t_ret; + + + 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"); + dbenv->set_errfile(dbenv, stderr); + + + + + /* + * 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 , + S_IRUSR | S_IWUSR)) != 0) { + (void)dbenv->close(dbenv, 0); + fprintf(stderr, "dbenv->open: %s: %s\n", + ENV_DIRECTORY, db_strerror(ret)); + exit (1); + } + + + + + *dbenvp = dbenv; +} diff --git a/test/lladd-old/db41/jbhashsimple.c b/test/lladd-old/db41/jbhashsimple.c new file mode 100644 index 0000000..8b115fb --- /dev/null +++ b/test/lladd-old/db41/jbhashsimple.c @@ -0,0 +1,127 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include +#include +#include + + + +#define DATABASE "access.db" + + + + +int main() { + DB *dbp; + DBT key1, dat1, key2, dat2, key3, dat3, key4, dat4; + int ret, i, 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, + NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s", DATABASE); + goto err; + } + + + + + memset(&key1, 0, sizeof(key1)); + memset(&dat1, 0, sizeof(dat1)); + memset(&key2, 0, sizeof(key1)); + memset(&dat2, 0, sizeof(dat1)); + memset(&key3, 0, sizeof(key1)); + memset(&dat3, 0, sizeof(dat1)); + memset(&key4, 0, sizeof(key1)); + memset(&dat4, 0, sizeof(dat1)); + + key1.size = key2.size = key3.size = key4.size = sizeof(int); + key1.data = malloc(sizeof(int)); + key2.data = malloc(sizeof(int)); + key3.data = malloc(sizeof(int)); + key4.data = malloc(sizeof(int)); + + *((int*)key1.data) = 1; dat1.data = "one"; dat1.size = 4; + *((int*)key2.data) = 2; dat2.data = "two"; dat2.size = 4; + *((int*)key3.data) = 3; dat3.data = "three"; dat3.size = 6; + *((int*)key4.data) = 4; dat4.data = "four"; dat4.size = 5; + + if( ret = ( + dbp->put(dbp, NULL, &key1, &dat1, 0) || + dbp->put(dbp, NULL, &key2, &dat2, 0) || + dbp->put(dbp, NULL, &key3, &dat3, 0) || + dbp->put(dbp, NULL, &key4, &dat4, 0) )) + { + dbp->err(dbp, ret, "DB->put"); + goto err; + } else { + printf("db: keys stored.\n"); + } + + + for( i = 1; i <= 4; i++ ) { + *((int*)key1.data) = i; + + if ((ret = dbp->get(dbp, NULL, &key1, &dat1, 0)) == 0) + printf("db: %u: key retrieved: data was %s.\n", *((int*)key1.data), (char *)dat1.data); + else { + dbp->err(dbp, ret, "DB->get"); + goto err; + } + } + +err: if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) + ret = t_ret; + + + + + return 0; + +} diff --git a/test/lladd-old/inc_dec.c b/test/lladd-old/inc_dec.c new file mode 100644 index 0000000..b3be5ec --- /dev/null +++ b/test/lladd-old/inc_dec.c @@ -0,0 +1,155 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing other user functions + * *******************************/ + +#include "test.h" + +int test() { + int i; + int xid, writeVal, readVal; + recordid rec; + + printf("\nRunning test1\n"); + + + writeVal = 10; + + xid = Tbegin(); + + rec = Talloc(xid, sizeof(int)); + + Tset(xid, rec, &writeVal); + Tread(xid, rec, &readVal); + + printf("value set is %d, value read is %d\n", writeVal, readVal); + + Tcommit(xid); + + xid = Tbegin(); + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tincrement(xid, rec); + printf("calling Tincrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tincrement(xid, rec); + printf("calling Tincrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tabort(xid); + printf("aborting\n"); + xid = Tbegin(); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tincrement(xid, rec); + printf("calling Tincrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tdecrement(xid, rec); + printf("calling Tdecrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + Tdecrement(xid, rec); + printf("calling Tdecrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + Tdecrement(xid, rec); + printf("calling Tdecrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + for (i = 0; i < 10; i++) { + Tdecrement(xid, rec); + printf("calling Tdecrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + } + + Tcommit(xid); + printf("committing\n"); + xid = Tbegin(); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tdecrement(xid, rec); + printf("calling Tdecrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tincrement(xid, rec); + printf("calling Tincrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tdecrement(xid, rec); + printf("calling Tdecrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + + + + printf("\n"); + return 0; + +} diff --git a/test/lladd-old/interleaved.c b/test/lladd-old/interleaved.c new file mode 100644 index 0000000..3e18c7f --- /dev/null +++ b/test/lladd-old/interleaved.c @@ -0,0 +1,101 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * interleaved transactions + * *******************************/ + +#include "test.h" + +int test() { + int xid_0; + int writeVal_0; + int readVal_0; + recordid rec_0; + + int xid_1; + int writeVal_1; + int readVal_1; + recordid rec_1; + + printf("\nRunning test4\n"); + + + + writeVal_0 = 314159265; + writeVal_1 = 271828183; + + xid_0 = Tbegin(); + xid_1 = Tbegin(); + + rec_0 = Talloc(xid_0, sizeof(int)); + rec_1 = Talloc(xid_1, sizeof(int)); + + Tset(xid_0, rec_0, &writeVal_0); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_0, rec_0.page, rec_0.slot, writeVal_0); + + Tset(xid_1, rec_1, &writeVal_1); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_1, rec_1.page, rec_1.slot, writeVal_1); + + Tread(xid_0, rec_0, &readVal_0); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, readVal_0); + + Tread(xid_1, rec_1, &readVal_1); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_1, rec_1.page, rec_1.slot, readVal_1); + + Tcommit(xid_0); + printf("xid %d committed\n", xid_0); + + Tcommit(xid_1); + printf("xid %d committed\n", xid_1); + + Tread(xid_0, rec_0, &readVal_0); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, readVal_0); + + Tread(xid_1, rec_1, &readVal_1); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_1, rec_1.page, rec_1.slot, readVal_1); + + + printf("\n"); + return 0; +} diff --git a/test/lladd-old/jbhashdisk.c b/test/lladd-old/jbhashdisk.c new file mode 100644 index 0000000..f4e73f0 --- /dev/null +++ b/test/lladd-old/jbhashdisk.c @@ -0,0 +1,84 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/** + * Test of persistant hash with many entries + */ + +#include + +#include "test.h" +#include "../pbl/jbhash.h" + +typedef struct { + int key; + char *value; +} test_pair_t; + +int test() { + + unsigned int i, xid; + const unsigned int INSERT_NUM = 10000; /* should be > JB_HASHTABLE_SIZE */ + char value[22]; /* should be log(INSERT_NUM)+8 */ + jbHashTable_t *ht; + + xid = Tbegin(); + ht = jbHtCreate(xid, 1000); + + for( i = 0; i < INSERT_NUM; i++ ) { + sprintf(value, "value: %u\n", i); + jbHtInsert(xid, ht, &i, sizeof(int), value, sizeof(char)*strlen(value)); + } + + Tcommit(xid); + xid = Tbegin(); + + for( i = 0; i < INSERT_NUM; i++ ) { + jbHtLookup(xid, ht, &i, sizeof(int), value); + printf("%s", value); + } + + jbHtDelete(xid, ht); + + Tabort(xid); + + return 0; +} diff --git a/test/lladd-old/jbhashmany.c b/test/lladd-old/jbhashmany.c new file mode 100644 index 0000000..b7fc568 --- /dev/null +++ b/test/lladd-old/jbhashmany.c @@ -0,0 +1,84 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#include "test.h" +#include "../pbl/jbhash.h" + +typedef struct { + int key; + char *value; +} test_pair_t; + +/** + * Test of jb persistant hash with many entries + */ + +int test() { + + unsigned int i, xid; + const unsigned int INSERT_NUM = 10000; /* should be > JB_HASHTABLE_SIZE */ + char value[22]; /* should be log(INSERT_NUM)+8 */ + jbHashTable_t *ht; + + xid = Tbegin(); + ht = jbHtCreate(xid, 4399); + + for( i = 0; i < INSERT_NUM; i++ ) { + sprintf(value, "value: %u\n", i); + jbHtInsert(xid, ht, &i, sizeof(int), value, sizeof(char)*strlen(value)); + } + + Tcommit(xid); + xid = Tbegin(); + + for( i = 0; i < INSERT_NUM; i++ ) { + jbHtLookup(xid, ht, &i, sizeof(int), value); + /* * printf("%s", value); */ + } + + jbHtDelete(xid, ht); + + Tabort(xid); + + return 0; +} diff --git a/test/lladd-old/jbht-speed.c b/test/lladd-old/jbht-speed.c new file mode 100644 index 0000000..581b553 --- /dev/null +++ b/test/lladd-old/jbht-speed.c @@ -0,0 +1,95 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include + +#include "test.h" +#include "../pbl/jbhash.h" + +typedef struct { + int key; + char *value; +} test_pair_t; + +/** + * Test of persistant hash with many entries + */ + +int test() { + + struct timeval start, end, total; + unsigned int i, xid; + const unsigned int INSERT_NUM = 10000; /* should be .75*JB_HASHTABLE_SIZE */ + char value[22]; /* should be log(INSERT_NUM)+8 */ + jbHashTable_t *ht; + + xid = Tbegin(); + ht = jbHtCreate(xid, 4399); + + gettimeofday(&start, NULL); + for( i = 0; i < INSERT_NUM; i++ ) { + sprintf(value, "value: %u\n", i); + jbHtInsert(xid, ht, &i, sizeof(int), value, sizeof(char)*strlen(value)); + } + gettimeofday(&end, NULL); + timersub(&end, &start, &total); + printf("insert %u: %lds %ldus\n", INSERT_NUM, total.tv_sec, total.tv_usec); + + Tcommit(xid); + xid = Tbegin(); + + gettimeofday(&start, NULL); + for( i = 0; i < INSERT_NUM; i++ ) { + jbHtLookup(xid, ht, &i, sizeof(int), value); + /*printf("%s", value);*/ + } + gettimeofday(&end, NULL); + timersub(&end, &start, &total); + printf("lookup %u: %lds %ldus\n", INSERT_NUM, total.tv_sec, total.tv_usec); + + jbHtDelete(xid, ht); + + Tabort(xid); + + return 0; +} diff --git a/test/lladd-old/jbhtsimple.c b/test/lladd-old/jbhtsimple.c new file mode 100644 index 0000000..ec22829 --- /dev/null +++ b/test/lladd-old/jbhtsimple.c @@ -0,0 +1,89 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#include "test.h" +#include "../pbl/jbhash.h" + +typedef struct { + int key; + char *value; +} test_pair_t; + +/** + * Simple test of persistant hash table + */ + +int test() { + + test_pair_t one = { 1, "one" }; + test_pair_t two = { 2, "two" }; + test_pair_t three = { 3, "three" }; + test_pair_t four = { 4, "four" }; + + int i; + int xid = Tbegin(); + + jbHashTable_t *ht = jbHtCreate(xid, 79); + if( jbHtInsert(xid, ht, &one.key, sizeof(int), one.value, sizeof(char)*4) || + jbHtInsert(xid, ht, &two.key, sizeof(int), two.value, sizeof(char)*4) || + jbHtInsert(xid, ht, &three.key, sizeof(int), three.value, sizeof(char)*6) || + jbHtInsert(xid, ht, &four.key, sizeof(int), four.value, sizeof(char)*5) + ) { + return -1; + } + + Tcommit(xid); + xid = Tbegin(); + + for( i = 1; i <= 4; i++ ) { + char buf[7]; + jbHtLookup(xid, ht, &i, sizeof(int), buf); + printf("key %u: %s\n", i, buf); + } + + jbHtDelete(xid, ht); + + Tcommit(xid); + + return 0; +} diff --git a/test/lladd-old/lhmany.c b/test/lladd-old/lhmany.c new file mode 100644 index 0000000..d087ada --- /dev/null +++ b/test/lladd-old/lhmany.c @@ -0,0 +1,85 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include + +#include "test.h" +#include + +typedef struct { + int key; + char *value; +} test_pair_t; + +/** + * Test of logical logging, persistant hash with many entries + */ + +int test(int argc, char **argv) { + + unsigned int i, xid; + const unsigned int INSERT_NUM = 10000; /* should be > JB_HASHTABLE_SIZE */ + char value[22]; /* should be log(INSERT_NUM)+8 */ + lladdHash_t *ht; + + xid = Tbegin(); + ht = lHtCreate(xid, 4399); + + for( i = 0; i < INSERT_NUM; i++ ) { + sprintf(value, "value: %u\n", i); + /* printf(".."); fflush(NULL); */ + lHtInsert(xid, ht, &i, sizeof(int), value, sizeof(char)*strlen(value)); + } + + Tcommit(xid); + xid = Tbegin(); + + for( i = 0; i < INSERT_NUM; i++ ) { + int ret = lHtLookup(xid, ht, &i, sizeof(int), value); + printf("%d %d -> %s", ret, i, value); + } + + lHtDelete(xid, ht); + + Tabort(xid); + + return 0; +} diff --git a/test/lladd-old/lhpackingfactor.c b/test/lladd-old/lhpackingfactor.c new file mode 100644 index 0000000..bfc00f8 --- /dev/null +++ b/test/lladd-old/lhpackingfactor.c @@ -0,0 +1,98 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include "test.h" +#include + +typedef struct { + int key; + char *value; +} test_pair_t; + +/** + * Test of logical logging persistant hash with various packing + * factors. It is designed to be run by a script to determine the + * optimum packing factor for the hash. Due to unnecessary overhead + * with large sets of buckets, this number is currently quite high (~ + * 10 entries per hash bucket, where 9 of those entries are overflow + * entries.) + */ + +int test(int argc, char **argv) { + int j; + for(j = 0; j < 1000; j++) { + + unsigned int i, xid; + unsigned int INSERT_NUM; + char value[22]; /* should be log(INSERT_NUM)+8 */ + lladdHash_t *ht; + + assert(argc==2); + + INSERT_NUM = 255; /* should be > JB_HASHTABLE_SIZE */ + int size = atoi(argv[1]); + xid = Tbegin(); + ht = lHtCreate(xid, size); + + for( i = 0; i < INSERT_NUM; i++ ) { + sprintf(value, "value: %u\n", i); + /* printf(".."); fflush(NULL); */ + lHtInsert(xid, ht, &i, sizeof(int), value, sizeof(char)*strlen(value)); + } + + Tcommit(xid); + xid = Tbegin(); + for( i = 0; i < INSERT_NUM; i++ ) { + int ret = lHtLookup(xid, ht, &i, sizeof(int), value); + if(ret == -1) { + return 1; + } + /* printf("%d %d -> %s", ret, i, value); */ + } + + lHtDelete(xid, ht); + + Tabort(xid); + } + return 0; +} diff --git a/test/lladd-old/lhpackingfactor.script b/test/lladd-old/lhpackingfactor.script new file mode 100644 index 0000000..efd1ef0 --- /dev/null +++ b/test/lladd-old/lhpackingfactor.script @@ -0,0 +1,9 @@ +./lhpackingfactor.test 53 +./lhpackingfactor.test 101 +./lhpackingfactor.test 503 +./lhpackingfactor.test 1009 +./lhpackingfactor.test 5003 +./lhpackingfactor.test 10007 +./lhpackingfactor.test 49999 +./lhpackingfactor.test 100003 + diff --git a/test/lladd-old/lladdHashTest.c b/test/lladd-old/lladdHashTest.c new file mode 100644 index 0000000..bd4ea8b --- /dev/null +++ b/test/lladd-old/lladdHashTest.c @@ -0,0 +1,179 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include +#include "test.h" +#include + +int test(int argc, char **argv) { + int j; + int after_39 = 0; + int xid = Tbegin(); + + lladdHash_t * ht = lHtCreate(xid, 700); + + for(j = 0; j < 1000; j++) { + lHtInsert(xid, ht, &j, sizeof(int), &j, sizeof(int)); + } + + Tcommit(xid); + + // Test successful lookup + committed inserts. + + xid = Tbegin(); + + for(j = 0; j < 1000; j++) { + int k = - 100; + assert(!lHtLookup(xid, ht, &j, sizeof(int), &k)); + assert(j==k); + } + + Tcommit(xid); + + // Test failed lookups. + + xid = Tbegin(); + + for(j = 1000; j < 2000; j++) { + int k = - 100; + assert(lHtLookup(xid, ht, &j, sizeof(int), &k) == -1); + } + + Tcommit(xid); + + // Test aborted inserts + + xid = Tbegin(); + + for(j = 10000; j < 11000; j++) { + lHtInsert(xid, ht, &j, sizeof(int), &j, sizeof(int)); + } + + for(j = 10000; j < 11000; j++) { + int k = - 100; + assert(!lHtLookup(xid, ht, &j, sizeof(int), &k)); + assert(k==j); + } + + Tabort(xid); + + xid = Tbegin(); + + for(j = 10000; j < 11000; j++) { + int k = - 100; + assert(-1 == lHtLookup(xid, ht, &j, sizeof(int), &k)); + } + + Tcommit(xid); + + // Test aborted removes. + + xid = Tbegin(); + for(j = 0; j < 1000; j+=10) { + int k = -100; + assert(!lHtRemove(xid, ht, &j, sizeof(int), &k, sizeof(int))); + + assert(j==k); + + } + + Tabort(xid); + + xid = Tbegin(); + + for(j = 0; j < 1000; j+=10) { + int k = -100; + assert(!lHtRemove(xid, ht, &j, sizeof(int), &k, sizeof(int))); + + assert(j==k); + + } + + Tcommit(xid); + + + for(j = 0; j < 1000; j+=10) { + int k = -100; + xid = Tbegin(); + + assert(-1 == lHtRemove(xid, ht, &j, sizeof(int), &k, sizeof(int))); + + Tcommit(xid); + + } + + + + /* ------------- Now, test the iterator. ------------------- */ + + xid = Tbegin(); + + lHtFirst(xid, ht, &j); + + for(j = 0; j < 2000; j++) { + int k; + if(-1 == lHtNext(xid, ht, &k)) { after_39++; break; } + assert((k >= 10000 && k < 11000) || + (k % 10 && k > 0 && k < 1000)); + + if(after_39 || k == 39) after_39++; + } + + assert(j == 899); + Tcommit(xid); + + j = 39; + + assert(-1 != lHtPosition(xid, ht, &j, sizeof(int))); + + j =0; + + while(lHtNext(xid, ht, NULL) != -1) { + j++; + } + + assert(j == after_39); + + return 0; + +} diff --git a/test/lladd-old/logvals.c b/test/lladd-old/logvals.c new file mode 100644 index 0000000..d5d99c1 --- /dev/null +++ b/test/lladd-old/logvals.c @@ -0,0 +1,142 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * long values + * *******************************/ + +#include "test.h" + +int test() { + int xid_0; + int writeVal_0; + int readVal_0; + recordid rec_0; + + int xid_1; + int writeVal_1; + int readVal_1; + recordid rec_1; + + int temp_in, temp_out; + + printf("\nRunning test4\n"); + + + + writeVal_0 = 314159265; + writeVal_1 = 271828183; + + xid_0 = Tbegin(); + xid_1 = Tbegin(); + + rec_0 = Talloc(xid_0, sizeof(int)); + rec_1 = Talloc(xid_1, sizeof(int)); + + Tset(xid_0, rec_0, &writeVal_0); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_0, rec_0.page, rec_0.slot, writeVal_0); + + Tset(xid_1, rec_1, &writeVal_1); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_1, rec_1.page, rec_1.slot, writeVal_1); + + Tread(xid_0, rec_0, &readVal_0); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, readVal_0); + + Tread(xid_1, rec_1, &readVal_1); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_1, rec_1.page, rec_1.slot, readVal_1); + + temp_in = 11111; + Tset(xid_0, rec_0, &temp_in); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_0, rec_0.page, rec_0.slot, temp_in); + Tread(xid_0, rec_0, &temp_out); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, temp_out); + + temp_in = 222222; + Tset(xid_0, rec_0, &temp_in); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_0, rec_0.page, rec_0.slot, temp_in); + Tread(xid_0, rec_0, &temp_out); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, temp_out); + + temp_in = 333333; + Tset(xid_0, rec_0, &temp_in); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_0, rec_0.page, rec_0.slot, temp_in); + Tread(xid_0, rec_0, &temp_out); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, temp_out); + + Tset(xid_0, rec_0, &writeVal_0); + printf("xid %d set rid (%d, %d) to value [%d]\n", xid_0, rec_0.page, rec_0.slot, writeVal_0); + Tread(xid_0, rec_0, &readVal_0); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, readVal_0); + + + if(0) { + Tabort(xid_0); + printf("xid %d aborted\n", xid_0); + + Tcommit(xid_1); + printf("xid %d committed\n", xid_1); + } else { + + Tcommit(xid_0); + printf("xid %d committed\n", xid_0); + + Tabort(xid_1); + printf("xid %d aborted\n", xid_1); + } + + xid_0 = Tbegin(); + xid_1 = Tbegin(); + Tread(xid_0, rec_0, &readVal_0); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_0, rec_0.page, rec_0.slot, readVal_0); + + Tread(xid_1, rec_1, &readVal_1); + printf("xid %d read from rid (%d, %d) the value [%d]\n", xid_1, rec_1.page, rec_1.slot, readVal_1); + + Tcommit(xid_0); + Tcommit(xid_1); + + + + printf("\n"); + return 0; +} diff --git a/test/lladd-old/loop.c b/test/lladd-old/loop.c new file mode 100644 index 0000000..dcfa4ce --- /dev/null +++ b/test/lladd-old/loop.c @@ -0,0 +1,73 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * test by looping + * *******************************/ + +#include "test.h" + +int test() { + + int xid, writeVal, readVal, i; + recordid rec; + + printf("\nRunning test8\n"); + + writeVal = 10; + + xid = Tbegin(); + + rec = Talloc(xid, sizeof(int)); + + for (i = 0; i < 1000000; i++) { + Tset(xid, rec, &writeVal); + Tread(xid, rec, &readVal); + } + + + Tabort(xid); + + printf("\n"); + return 0; +} diff --git a/test/lladd-old/nontrans.c b/test/lladd-old/nontrans.c new file mode 100644 index 0000000..b06d343 --- /dev/null +++ b/test/lladd-old/nontrans.c @@ -0,0 +1,67 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * doesn't use transactions + * *******************************/ + +#include "test.h" + +int test() { + + int writeVal, i; + int *wptr= (int *)malloc(sizeof(int)); + int *rptr= (int *)malloc(sizeof(int)); + printf("\nRunning test8\n"); + + writeVal = 10; + + + for (i = 0; i < 1000000; i++) { + memset(wptr, writeVal, sizeof(int)); + memcpy(rptr, wptr, sizeof(int)); + } + + printf("\n"); + return 0; +} diff --git a/test/lladd-old/prepare_1.c b/test/lladd-old/prepare_1.c new file mode 100644 index 0000000..28ae3f9 --- /dev/null +++ b/test/lladd-old/prepare_1.c @@ -0,0 +1,101 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing other user functions + * *******************************/ + +#include "test.h" + +int test() { + int i; + int xid, writeVal, readVal; + recordid rec; + + printf("\nRunning prepare test phase 1\n"); + + + writeVal = 10; + + xid = Tbegin(); + + rec = Talloc(xid, sizeof(int)); + + Tset(xid, rec, &writeVal); + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tcommit(xid); + + xid = Tbegin(); + + + Tincrement(xid, rec); + printf("calling Tincrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tincrement(xid, rec); + printf("calling Tincrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + + printf("Preparing\n"); + printf("Xid = %d, Recordid = { %d, %d, %d }\n", xid, rec.page, rec.slot, rec.size); + Tprepare(xid, rec, readVal); + + Tincrement(xid, rec); + printf("calling Tincrement\n"); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + printf("Exiting\n"); + + exit(0); + return 0; + +} diff --git a/test/lladd-old/prepare_2.c b/test/lladd-old/prepare_2.c new file mode 100644 index 0000000..3f7cea9 --- /dev/null +++ b/test/lladd-old/prepare_2.c @@ -0,0 +1,80 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing other user functions + * *******************************/ + +#include "test.h" + +int test() { + int i; + int writeVal, readVal; + + /** These need to be reset manually. */ + int xid = 2; + recordid rec = { 0,0,sizeof(int) }; + + + InitiateRecovery(); + + printf("\nRunning prepare testing commit.\n"); + + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tcommit(xid); + + xid = Tbegin(); + + printf("xid = %d\n", xid); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tabort(xid); + + exit(-1); + +} diff --git a/test/lladd-old/prepare_3.c b/test/lladd-old/prepare_3.c new file mode 100644 index 0000000..8ab876a --- /dev/null +++ b/test/lladd-old/prepare_3.c @@ -0,0 +1,77 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing other user functions + * *******************************/ + +#include "test.h" + +int test() { + int i; + int writeVal, readVal; + + /** These need to be reset manually. */ + int xid = 2; + recordid rec = { 0,0,sizeof(int) }; + + InitiateRecovery(); + printf("\nRunning prepare testing commit.\n"); + + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + printf("Aborting\n"); + + Tabort(xid); + + xid = Tbegin(); + + Tread(xid, rec, &readVal); + printf("value read is %d\n", readVal); + + Tabort(xid); + return 0; + +} diff --git a/test/lladd-old/rand_str.c b/test/lladd-old/rand_str.c new file mode 100644 index 0000000..15c3399 --- /dev/null +++ b/test/lladd-old/rand_str.c @@ -0,0 +1,91 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include + +#define SEED 0 + +char *LONG_STRING; +int LONG_STRING_LENGTH; + +void rand_str_init() { + char c; + + char first_printable_ascii = ' '; + char last_printable_ascii = '~'; + LONG_STRING_LENGTH = (int)(last_printable_ascii - first_printable_ascii); + LONG_STRING = (char *)malloc(sizeof(char) * LONG_STRING_LENGTH); + + for (c = 0; c < LONG_STRING_LENGTH; c++) { + LONG_STRING[(int)c] = first_printable_ascii + c; + } + + srand(SEED); +} + +char *rand_str() { + char *string; + double r; + + int start = 0; + int end = 0; + while (start == end) { + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* returns [0, 1)*/ + r = r*LONG_STRING_LENGTH; + start = (int)r; /* an int in the rand [0, length) */ + + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* re turns [0, 1)*/ + r = r*LONG_STRING_LENGTH; + end = (int)r; /* an int in the rand [0, length) */ + } + if (end < start) { + int swap = start; + start = end; + end = swap; + } + + string = (char *)malloc(sizeof(char) * (end - start) + 1); + strncpy(string, LONG_STRING + start, end-start); + string[end-start] = '\0'; /* make the string null terminated */ + return string; +} diff --git a/test/lladd-old/rand_str.h b/test/lladd-old/rand_str.h new file mode 100644 index 0000000..6a3318b --- /dev/null +++ b/test/lladd-old/rand_str.h @@ -0,0 +1,43 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +void rand_str_init(void); +char *rand_str(); diff --git a/test/lladd-old/recover.c b/test/lladd-old/recover.c new file mode 100644 index 0000000..28b6f2e --- /dev/null +++ b/test/lladd-old/recover.c @@ -0,0 +1,54 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * recover from a crash + * *******************************/ + +#include "../../src/lladd/recovery.h" +#include "test.h" + +int test() { + InitiateRecovery(); + return 0; +} diff --git a/test/lladd-old/strings.c b/test/lladd-old/strings.c new file mode 100644 index 0000000..25daf7a --- /dev/null +++ b/test/lladd-old/strings.c @@ -0,0 +1,129 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * testing with various strings + * *******************************/ +#include +#include "test.h" + +#define VERBOSE 0 +#define SEED 5095 + +int test() { + int xid; + int NUM_TRIALS=100; + recordid rec; + + /* counters */ + int i; + char c; + + /* used for making the random strings*/ + double r; + int start, end; + + /* used to make a long string */ + char first_printable_ascii = ' '; + char last_printable_ascii = '~'; + int ascii_length = (int)(last_printable_ascii - first_printable_ascii); + char *ASCII = (char *)malloc(sizeof(char) * ascii_length); + + /* an array of strings */ + char **strings = (char **)malloc(sizeof(char*) * NUM_TRIALS); + + /* output buffer */ + char *out_buffer = (char *)malloc(sizeof(char) * ascii_length); + + + srand(SEED); + + /* create the long string from which random strings will be made */ + for (c = 0; c < ascii_length; c++) { + ASCII[(int)c] = first_printable_ascii + c; + } + + for (i = 0; i < NUM_TRIALS; i++) { + + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* returns [0, 1)*/ + r = r*ascii_length; + start = (int)r; /* an int in the rand [0, ascii_length) */ + + r = ((double)rand()/(double)((double)RAND_MAX+1)); /* returns [0, 1)*/ + r = r*ascii_length; + end = (int)r; /* an int in the rand [0, ascii_length) */ + + if (start == end) { + i--; + continue; + } + + if (end < start) { + int swap = start; + start = end; + end = swap; + } + + + strings[i] = (char *)malloc(sizeof(char) * (end - start) + 1); + strncpy(strings[i], ASCII + start, end-start); + strings[i][end-start-1] = '\0'; /* make the string null terminated */ + + } + + for (i = 0; i < NUM_TRIALS; i++) { + xid = Tbegin(); + rec = Talloc(xid, sizeof(char)*(strlen(strings[i]) +1)); + Tset(xid, rec, strings[i]); + + Tread(xid, rec, out_buffer); + + if (VERBOSE) { + printf("xid %d set rid (%d, %d) to [%s], and read [%s]\n", xid, rec.page, rec.slot, strings[i], out_buffer); + } + assert(strcmp(strings[i], out_buffer) == 0); + Tcommit(xid); + } + + return 0; +} diff --git a/test/lladd-old/test.c b/test/lladd-old/test.c new file mode 100644 index 0000000..ccc2cfa --- /dev/null +++ b/test/lladd-old/test.c @@ -0,0 +1,60 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/******************************************* + * $Id$ + * + * Testing driver + * ****************************************/ + +#include "test.h" + +int main(int argc, char **argv) { + int ret; + + Tinit(); + + ret = test(argc, argv); + + Tdeinit(); + + return ret; +} diff --git a/test/lladd-old/test.h b/test/lladd-old/test.h new file mode 100644 index 0000000..a729ffb --- /dev/null +++ b/test/lladd-old/test.h @@ -0,0 +1,52 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************************** + * $Id$ + * + * dummy header file for tests + * ********************************************/ +#include +#include +#include +#include + +int test(); diff --git a/test/lladd-old/test0.c b/test/lladd-old/test0.c new file mode 100644 index 0000000..bf1c6fb --- /dev/null +++ b/test/lladd-old/test0.c @@ -0,0 +1,52 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/**************************** + * $Id$ + * + * glassbox testing of pages + * *************************/ + +#include "test.h" + +int test(int argc, char **argv) { + return pageTest(); +} diff --git a/test/lladd-old/test1.c b/test/lladd-old/test1.c new file mode 100644 index 0000000..dabbc4b --- /dev/null +++ b/test/lladd-old/test1.c @@ -0,0 +1,99 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/******************************** + * $Id$ + * + * simple reading, writing + * ******************************/ + +/** + * This test creates one transaction that does one int write + * and one write per record for NUM_TRIALS records + */ + + +#include "test.h" + +#define NUM_TRIALS 10 +#define VERBOSE 1 + + +int test(int argc, char **argv) { + int xid; + int writeVals[NUM_TRIALS]; + int readVals[NUM_TRIALS]; + recordid recs[NUM_TRIALS]; + + int i; + int failed = 0; + + printf("\nRunning %s\n", __FILE__); + + xid = Tbegin(); + + for (i = 0; i < NUM_TRIALS; i++) { + writeVals[i] = rand(); + + recs[i] = Talloc(xid, sizeof(int)); + + Tset(xid, recs[i], &writeVals[i]); + } + + Tcommit(xid); + xid = Tbegin(); + + for (i = 0; i < NUM_TRIALS; i++) { + Tread(xid, recs[i], &readVals[i]); + + if (VERBOSE) + printf("value set is %d, value read is %d\n", writeVals[i], readVals[i]); + + if (writeVals[i] != readVals[i]) + failed = 1; + } + + Tcommit(xid); + + printf("%s\n\n", failed ? "****FAILED****" : "PASSED"); + + return failed; +} diff --git a/test/lladd-old/test2.c b/test/lladd-old/test2.c new file mode 100644 index 0000000..7256e92 --- /dev/null +++ b/test/lladd-old/test2.c @@ -0,0 +1,99 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/******************************** + * $Id$ + * + * simple reading, writing + * ******************************/ + +/** + * This test creates one transaction that does one int write + * and one write per record for NUM_TRIALS records + */ + + +#include "test.h" + +#define NUM_TRIALS 10 +#define VERBOSE 1 + + +int test(int argc, char **argv) { + int xid; + int writeVals[NUM_TRIALS]; + int readVals[NUM_TRIALS]; + recordid recs[NUM_TRIALS]; + + int i; + int failed = 0; + + printf("\nRunning %s\n", __FILE__); + + + for (i = 0; i < NUM_TRIALS; i++) { + xid = Tbegin(); + writeVals[i] = rand(); + + recs[i] = Talloc(xid, sizeof(int)); + + Tset(xid, recs[i], &writeVals[i]); + Tcommit(xid); + } + + xid = Tbegin(); + + for (i = 0; i < NUM_TRIALS; i++) { + Tread(xid, recs[i], &readVals[i]); + + if (VERBOSE) + printf("value set is %d, value read is %d\n", writeVals[i], readVals[i]); + + if (writeVals[i] != readVals[i]) + failed = 1; + } + + Tcommit(xid); + + printf("%s\n\n", failed ? "****FAILED****" : "PASSED"); + + return failed; +} diff --git a/test/lladd-old/test3.c b/test/lladd-old/test3.c new file mode 100644 index 0000000..51cdd20 --- /dev/null +++ b/test/lladd-old/test3.c @@ -0,0 +1,126 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/******************************** + * $Id$ + * + * ******************************/ + +/** + * This test creates one transaction that does one int write + * and one write per record for NUM_TRIALS records + */ + + +#include "test.h" + +#define NUM_TRIALS 10 +#define VERBOSE 1 + + +int test(int argc, char **argv) { + int xids[NUM_TRIALS]; + int initVals[NUM_TRIALS]; + int writeVals[NUM_TRIALS]; + int readVals[NUM_TRIALS]; + int commits[NUM_TRIALS]; + int i; + recordid recs[NUM_TRIALS]; + int failed = 0; + + printf("\nRunning %s\n", __FILE__); + + for (i = 0; i < NUM_TRIALS; i++) { + xids[i] = Tbegin(); + initVals[i] = rand(); + recs[i] = Talloc(xids[i], sizeof(int)); + Tset(xids[i], recs[i], &initVals[i]); + Tcommit(xids[i]); + } + + + + for (i = 0; i < NUM_TRIALS; i++) { + xids[i] = Tbegin(); + commits[i] = 0; + writeVals[i] = rand(); + } + + for (i = 0; i < NUM_TRIALS; i++) { + Tset(xids[i], recs[i], &writeVals[i]); + } + + for (i = 0; i < NUM_TRIALS; i++) { + if (rand() % 2) { + Tcommit(xids[i]); + commits[i] = 1; + } else { + Tabort(xids[i]); + } + } + + for (i = 0; i < NUM_TRIALS; i++) { + Tread(xids[i], recs[i], &readVals[i]); + } + + + for (i = 0; i < NUM_TRIALS; i++) { + if (VERBOSE) { + if (commits[i]) + printf("xid %d commited value %d, and read %d\n", xids[i], writeVals[i], readVals[i]); + else + printf("xid %d aborted while setting value %d, and read %d and should've read %d\n", xids[i], writeVals[i], readVals[i], initVals[i]); + + } + + if (commits[i]) { + if (writeVals[i] != readVals[i]) + failed = 1; + } else { + if (initVals[i] != readVals[i]) + failed = 1; + } +} + + printf("%s\n\n", failed ? "****FAILED****" : "PASSED"); + + return failed; +} diff --git a/test/lladd-old/twentyfour.c b/test/lladd-old/twentyfour.c new file mode 100644 index 0000000..98d4695 --- /dev/null +++ b/test/lladd-old/twentyfour.c @@ -0,0 +1,87 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * if you run this test 23 times, it seems to work fine. On the 24th time, you + * need to allocate a new page, and it crashes; + * *******************************/ + +#include "test.h" + +int test() { + int xid; + char *handle_in = "jkit"; + char *name_in = "Jimmy Kittiyachavalit"; + int phone_in = 8821417; + + char *handle_out = (char *)malloc(strlen(handle_in)+1); + char *name_out = (char *)malloc(strlen(name_in)+1); + int phone_out; + + recordid r_name, r_handle, r_phone; + + xid = Tbegin(); + + r_handle = Talloc(xid, strlen(handle_in)+1); + r_name = Talloc(xid, strlen(name_in)+1); + r_phone = Talloc(xid, sizeof(int)); + + Tset(xid, r_handle, handle_in); + printf("set handle to [%s]\n", handle_in); + Tset(xid, r_name, name_in); + printf("set name to [%s]\n", name_in); + Tset(xid, r_phone, &phone_in); + printf("set name to [%d]\n", phone_in); + + Tread(xid, r_handle, handle_out); + printf("read handle is [%s]\n", handle_out); + Tread(xid, r_name, name_out); + printf("read name is [%s]\n", name_out); + Tread(xid, r_phone, &phone_out); + printf("read name is [%d]\n", phone_out); + + + Tcommit(xid); + + return 0; +} diff --git a/test/lladd-old/twentyfour2.c b/test/lladd-old/twentyfour2.c new file mode 100644 index 0000000..c0bc3bb --- /dev/null +++ b/test/lladd-old/twentyfour2.c @@ -0,0 +1,127 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +/********************************* + * $Id$ + * + * if you run this test 23 times, its fine, but on the 24 time, shit happens + * *******************************/ + +#include "test.h" + +int test() { + int xid; + char *handle_in = "jkit"; + char *name_in = "Jimmy Kittiyachavalit"; + int phone_in = 8821417; + + char *handle_out = (char *)malloc(strlen(handle_in)+1); + char *name_out = (char *)malloc(strlen(name_in)+1); + int phone_out; + + recordid r_name, r_handle, r_phone; + + xid = Tbegin(); + + r_handle = Talloc(xid, strlen(handle_in)+1); + r_name = Talloc(xid, strlen(name_in)+1); + r_phone = Talloc(xid, sizeof(int)); + + Tset(xid, r_handle, handle_in); + printf("set handle to [%s]\n", handle_in); + Tset(xid, r_name, name_in); + printf("set name to [%s]\n", name_in); + Tset(xid, r_phone, &phone_in); + printf("set name to [%d]\n", phone_in); + + Tread(xid, r_handle, handle_out); + printf("read handle is [%s]\n", handle_out); + Tread(xid, r_name, name_out); + printf("read name is [%s]\n", name_out); + Tread(xid, r_phone, &phone_out); + printf("read name is [%d]\n", phone_out); + + + Tcommit(xid); + + + + xid = Tbegin(); + handle_in = "tikj"; + name_in = "tilavahcayittik ymmij"; + phone_in = 3142116; + handle_out = (char *)malloc(strlen(handle_in)+1); + name_out = (char *)malloc(strlen(name_in)+1); + phone_out = 0; + Tset(xid, r_handle, handle_in); + printf("set handle to [%s]\n", handle_in); + Tset(xid, r_name, name_in); + printf("set name to [%s]\n", name_in); + Tset(xid, r_phone, &phone_in); + printf("set name to [%d]\n", phone_in); + + Tread(xid, r_handle, handle_out); + printf("read handle is [%s]\n", handle_out); + Tread(xid, r_name, name_out); + printf("read name is [%s]\n", name_out); + Tread(xid, r_phone, &phone_out); + printf("read name is [%d]\n", phone_out); + + printf("aborted the transaction\n"); + + Tabort(xid); + + xid = Tbegin(); + handle_out = (char *)malloc(strlen(handle_in)+1); + name_out = (char *)malloc(strlen(name_in)+1); + phone_out = 0; + Tread(xid, r_handle, handle_out); + printf("read handle is [%s]\n", handle_out); + Tread(xid, r_name, name_out); + printf("read name is [%s]\n", name_out); + Tread(xid, r_phone, &phone_out); + printf("read name is [%d]\n", phone_out); + + + Tcommit(xid); + + return 0; +} diff --git a/test/lladd/Makefile.am b/test/lladd/Makefile.am new file mode 100644 index 0000000..fb085ff --- /dev/null +++ b/test/lladd/Makefile.am @@ -0,0 +1,11 @@ +INCLUDES = @CHECK_CFLAGS@ +if HAVE_CHECK +## Had to disable check_lht because lht needs to be rewritten. +TESTS = check_logEntry check_logWriter check_operations check_transactional2 check_recovery +else +TESTS = +endif +noinst_PROGRAMS = $(TESTS) +LDADD = @CHECK_LIBS@ $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a +CLEANFILES = check_lht.log check_logEntry.log storefile.txt logfile.txt blob0_file.txt blob1_file.txt +AM_CFLAGS= -g -Wall -pedantic -std=gnu99 \ No newline at end of file diff --git a/test/lladd/check_lht.c b/test/lladd/check_lht.c new file mode 100644 index 0000000..f008d30 --- /dev/null +++ b/test/lladd/check_lht.c @@ -0,0 +1,383 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +/*#include */ + +#include + +#define LOG_NAME "check_lht.log" + +/** Insert 1000 values into a hashtable. (For testing) */ +static void test_lht_insert1000(int xid, lladdHash_t * ht) { + int j; + for(j =0 ; j < 1000; j++) { + lHtInsert(xid, ht, &j, sizeof(int), &j, sizeof(int)); + } +} + +/** Lookup 1000 vales from the hashtable (For testing) */ +static void test_lht_lookup1000(int xid, lladdHash_t * ht, int shouldBeThere) { + int j, k; + char * message = shouldBeThere ? "Couldn't lookup value" : "Found value that shouldn't exist"; + int expected_return = shouldBeThere ? 0 : -1; + + for(j = 0; j < 1000; j++) { + int actual_return; + + k = 10000000; + + actual_return = lHtLookup(xid, ht, &j, sizeof(int), &k); + /* assert(expected_return == actual_return); */ + fail_unless(expected_return == actual_return, message); + if(shouldBeThere) { + fail_unless(j == k, "Got incorrect value from lookup"); + } + } +} + + +/** Lookup 1000 vales from the hashtable (For testing) */ +void test_lht_remove1000(int xid, lladdHash_t * ht, int shouldBeThere) { + int j, k; + char * message = shouldBeThere ? "Couldn't remove value" : "Removed value that shouldn't exist"; + int expected_return = shouldBeThere ? 0 : -1; + + for(j = 0; j < 1000; j++) { + + fail_unless(expected_return == lHtRemove(xid, ht, &j, sizeof(int), &k, sizeof(int)), message); + if(shouldBeThere) { + fail_unless(j == k, "Got incorrect value from remove"); + } + } +} + +/** Iterate until the hash table reports no more entries, then return + the count. Also, make sure that key == value (assuming they're ints) */ +static int test_lht_iterateCounter(int xid, lladdHash_t * ht) { + int j = 0; + int key, value; + /* int first = 1; */ + int ret; + for(ret = lHtCurrent(xid, ht, &value); ret != -1; ret = lHtNext(xid, ht, &value)) { + int inner_ret = lHtCurrentKey(xid, ht, &key); + fail_unless(-1 != inner_ret, "A"); + fail_unless(key == value, "B"); + + if(! (j % 10)) { + /* Run current and current key once more, just in case. */ + ret = lHtCurrent(xid, ht, &value); + inner_ret = lHtCurrentKey(xid, ht, &key); + + fail_unless(-1 != ret, "C"); + fail_unless(-1 != inner_ret, "D"); + fail_unless(key == value, "E"); + } + + j++; + } + return j; +} + + + +/** Iterate until the hash table returns the desired value, and return the number of hits encountered. */ +static int test_lht_iterateCountUntil(int xid, lladdHash_t * ht, const int guard) { + int j = 0; + int key, value; + /* int first = 1; */ + int ret; + for(ret = lHtCurrent(xid, ht, &value); ret != -1 && value != guard; ret = lHtNext(xid, ht, &value)) { + int inner_ret = lHtCurrentKey(xid, ht, &key); + fail_unless(-1 != inner_ret, "A"); + fail_unless(key == value, "B"); + + if(! (j % 10)) { + /* Run current and current key once more, just in case. */ + ret = lHtCurrent(xid, ht, &value); + inner_ret = lHtCurrentKey(xid, ht, &key); + + fail_unless(-1 != ret, "C"); + fail_unless(-1 != inner_ret, "D"); + fail_unless(key == value, "E"); + } + + j++; + } + + fail_unless(ret != -1, "Iterator didn't find value."); + fail_unless(guard == value, "Test case bug??"); + + return j; +} + + + +/** @test + Check lHtInsert for transactions that commit +*/ +START_TEST(lht_insert_commit) +{ + int xid; + lladdHash_t * ht; + + Tinit(); + xid = Tbegin(); + + ht = lHtCreate(xid, 700); + + test_lht_insert1000(xid, ht); + test_lht_lookup1000(xid, ht, 1); + + Tcommit(xid); + xid = Tbegin(); + + test_lht_lookup1000(xid, ht, 1); + + Tcommit(xid); + Tdeinit(); +} +END_TEST + +/** @test + Check lHtInsert for transactions that abort +*/ +START_TEST(lht_insert_abort) +{ + int xid; + lladdHash_t * ht; + Tinit(); + xid = Tbegin(); + ht = lHtCreate(xid, 700); + + test_lht_insert1000(xid, ht); + test_lht_lookup1000(xid, ht, 1); + + Tabort(xid); + xid = Tbegin(); + + /* printf("G\n"); */ + + test_lht_lookup1000(xid, ht, 0); + /* printf("H\n"); */ + + Tcommit(xid); + Tdeinit(); +} +END_TEST + +/** @test + Check lHtRemove for transactions that commit +*/ +START_TEST(lht_remove_commit) +{ + int xid; + lladdHash_t * ht; + + Tinit(); + xid = Tbegin(); + + ht = lHtCreate(xid, 700); + + test_lht_insert1000(xid, ht); + /* printf("A\n"); fflush(NULL); */ + test_lht_lookup1000(xid, ht, 1); + + Tcommit(xid); + xid = Tbegin(); + + test_lht_lookup1000(xid, ht, 1); + test_lht_remove1000(xid, ht, 1); + /* printf("B\n"); fflush(NULL); */ + test_lht_lookup1000(xid, ht, 0); + test_lht_lookup1000(xid, ht, 0); + + Tcommit(xid); + xid = Tbegin(); + + /* printf("C\n"); fflush(NULL); */ + test_lht_lookup1000(xid, ht, 0); + + /* printf("D\n"); */ + + Tcommit(xid); + Tdeinit(); +} +END_TEST + +/** @test + Check lHtRemove for transactions that abort +*/ +START_TEST(lht_remove_abort) +{ + int xid; + lladdHash_t * ht; + Tinit(); + xid = Tbegin(); + + ht = lHtCreate(xid, 700); + + test_lht_insert1000(xid, ht); + test_lht_lookup1000(xid, ht, 1); + + Tcommit(xid); + xid = Tbegin(); + + test_lht_lookup1000(xid, ht, 1); + test_lht_remove1000(xid, ht, 1); + /* printf("E\n"); */ + test_lht_lookup1000(xid, ht, 0); + /* printf("F\n"); */ + + Tabort(xid); + xid = Tbegin(); + + /* printf("FA\n"); */ + test_lht_lookup1000(xid, ht, 1); + /* printf("FB\n"); fflush(NULL); */ + + Tcommit(xid); + Tdeinit(); +} +END_TEST + +/** + @test Tests lladd hash's iterator (but not the lHtPosition function) +*/ +START_TEST(iterator_vanilla) +{ + int xid, hits, j; + lladdHash_t * ht; + + Tinit(); + xid = Tbegin(); + + ht = lHtCreate(xid, 700); + + test_lht_insert1000(xid, ht); + + lHtFirst(xid, ht, &j); + + hits = test_lht_iterateCounter(xid, ht); + + fail_unless(hits == 1000, "Wrong number of items returned by vanilla iterator."); + + Tcommit(xid); + + lHtFirst(xid, ht, &j); + + hits = test_lht_iterateCounter(xid, ht); + + fail_unless(hits == 1000, "Iterator returned wrong number of hits after commit."); + + Tdeinit(); +} +END_TEST + +/** + @test Tests lladd hash's position function. +*/ +START_TEST(iterator_position) +{ + int xid, hits, next_hits, j; + const int thirty_nine = 39; + lladdHash_t * ht; + Tinit(); + xid = Tbegin(); + + ht = lHtCreate(xid, 700); + + test_lht_insert1000(xid, ht); + + lHtFirst(xid, ht, &j); + + hits = test_lht_iterateCountUntil(xid, ht, 39); + + lHtCurrent(xid, ht, &j); + + /* printf("Iterator at: %d\n", j); */ + next_hits = test_lht_iterateCounter(xid, ht); + + fail_unless((hits+next_hits) == 1000, "Wrong number of items returned by iterator setup."); + + Tcommit(xid); + + lHtPosition(xid, ht, &thirty_nine, sizeof(int)); + + lHtCurrent(xid, ht, &j); + + /* printf("Iterator at: %d\n", j); */ + hits = test_lht_iterateCounter(xid, ht); + /* printf("hits = %d, next_hits = %d\n", hits, next_hits); */ + + fail_unless(hits == next_hits, "Iterator returned wrong number of hits after position."); + + Tdeinit(); +} +END_TEST + +/** + Add suite declarations here +*/ +Suite * check_suite(void) { + Suite *s = suite_create("lladd_hash"); + /* Begin a new test */ + TCase *tc = tcase_create("insert_remove_lookup"); + + /* Sub tests are added, one per line, here */ + tcase_add_test(tc, lht_insert_commit); + tcase_add_test(tc, lht_insert_abort); + tcase_add_test(tc, lht_remove_commit); + tcase_add_test(tc, lht_remove_abort); + /* --------------------------------------------- */ + suite_add_tcase(s, tc); + + tc = tcase_create("iterator"); + + tcase_add_test(tc, iterator_vanilla); + tcase_add_test(tc, iterator_position); + + suite_add_tcase(s, tc); + return s; +} + +#include "../check_setup.h" diff --git a/test/lladd/check_logEntry.c b/test/lladd/check_logEntry.c new file mode 100644 index 0000000..a4f4398 --- /dev/null +++ b/test/lladd/check_logEntry.c @@ -0,0 +1,192 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include +#include + +#include +#include + +#include "../check_includes.h" + +#define LOG_NAME "check_logEntry.log" + +START_TEST(rawLogEntryAlloc) +{ + LogEntry * log = allocCommonLogEntry(200, 1, 4); + fail_unless(log->LSN == -1, NULL); + fail_unless(log->prevLSN == 200, NULL); + fail_unless(log->xid == 1,NULL); + fail_unless(log->type == 4,NULL); + fail_unless(sizeofLogEntry(log) == sizeof(struct __raw_log_entry),NULL); + free(log); +} +END_TEST + +START_TEST(clrLogEntryAlloc) +{ + recordid rid = { 3, 4, 5 }; + LogEntry * log = allocCLRLogEntry(200, 1, 7, rid, 8); + fail_unless(log->LSN == -1, NULL); + fail_unless(log->prevLSN == 200, NULL); + fail_unless(log->xid == 1, NULL); + fail_unless(log->type == CLRLOG, NULL); + fail_unless(sizeofLogEntry(log) == sizeof(struct __raw_log_entry) + sizeof(CLRLogEntry), NULL); + + fail_unless(log->contents.clr.thisUpdateLSN == 7, NULL); + fail_unless(log->contents.clr.rid.page == 3, NULL); + fail_unless(log->contents.clr.rid.slot == 4, NULL); + fail_unless(log->contents.clr.rid.size == 5, NULL); + fail_unless(log->contents.clr.undoNextLSN == 8, NULL); + + free(log); + +} +END_TEST + +/** @test + + Quick test of allocUpdateLogEntry + + @todo It would be nice if this test used actual operatations table instead of making up values.*/ + +START_TEST(updateLogEntryAlloc) +{ + + int * preImageCpy; + int preImage[] = {10000, 20000, 30000}; + char args[] = {'a', 'b', 'c'}; + recordid rid = { 3 , 4, sizeof(int)*3 }; + + LogEntry * log; + + Tinit(); /* Needed because it sets up the operations table. */ + log = allocUpdateLogEntry(200, 1, OPERATION_SET, + rid, + (const byte*)args, 3*sizeof(char), (const byte*)preImage); + fail_unless(log->LSN == -1, NULL); + fail_unless(log->prevLSN == 200, NULL); + fail_unless(log->xid == 1, NULL); + fail_unless(log->type == UPDATELOG, NULL); + + fail_unless(log->contents.update.funcID == OPERATION_SET, NULL); + /* fail_unless(log->contents.update.invertible == 0, NULL); */ + fail_unless(log->contents.update.rid.page == 3, NULL); + fail_unless(log->contents.update.rid.slot == 4, NULL); + fail_unless(log->contents.update.rid.size == 3*sizeof(int), NULL); + fail_unless(log->contents.update.argSize == 3*sizeof(char), NULL); + + fail_unless(getUpdateArgs(log) != NULL, NULL); + fail_unless(args[0] == ((char*)getUpdateArgs(log))[0], NULL); + fail_unless(args[1] == ((char*)getUpdateArgs(log))[1], NULL); + fail_unless(args[2] == ((char*)getUpdateArgs(log))[2], NULL); + preImageCpy = (int*)getUpdatePreImage(log); + fail_unless(preImageCpy != NULL, NULL); + + fail_unless(preImage[0] == preImageCpy[0], NULL); + fail_unless(preImage[1] == preImageCpy[1], NULL); + fail_unless(preImage[2] == preImageCpy[2], NULL); + + fail_unless(sizeofLogEntry(log) == (sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry) + 3 * (sizeof(int)+sizeof(char))), NULL); + free(log); + Tdeinit(); +} +END_TEST + + +START_TEST(updateLogEntryAllocNoExtras) +{ + int * preImageCpy; + int preImage[] = {10000, 20000, 30000}; + char args[] = {'a', 'b', 'c'}; + recordid rid = { 3 , 4, sizeof(int)*3 }; + + LogEntry * log = allocUpdateLogEntry(200, 1, OPERATION_LHINSERT, + rid, + (byte*)args, 0, (byte*)preImage); + fail_unless(log->LSN == -1, NULL); + fail_unless(log->prevLSN == 200, NULL); + fail_unless(log->xid == 1, NULL); + fail_unless(log->type == UPDATELOG, NULL); + + fail_unless(log->contents.update.funcID == OPERATION_LHINSERT, NULL); + /* fail_unless(log->contents.update.invertible == 1, NULL); */ + fail_unless(log->contents.update.rid.page == 3, NULL); + fail_unless(log->contents.update.rid.slot == 4, NULL); + fail_unless(log->contents.update.rid.size == 3*sizeof(int), NULL); + fail_unless(log->contents.update.argSize == 0, NULL); + + fail_unless(getUpdateArgs(log) == NULL, NULL); + preImageCpy = (int*)getUpdatePreImage(log); + fail_unless(preImageCpy == NULL, NULL); + + fail_unless(sizeofLogEntry(log) == (sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry) + 0 * (sizeof(int)+sizeof(char))), NULL); + free(log); +} +END_TEST + + + + +Suite * check_suite(void) { + Suite *s = suite_create("logEntry"); + /* Begin a new test */ + TCase *tc = tcase_create("allocate"); + + /* Sub tests are added, one per line, here */ + + tcase_add_test(tc, rawLogEntryAlloc); + tcase_add_test(tc, clrLogEntryAlloc); + tcase_add_test(tc, updateLogEntryAlloc); + tcase_add_test(tc, updateLogEntryAllocNoExtras); + + + /* --------------------------------------------- */ + + tcase_add_checked_fixture(tc, setup, teardown); + + suite_add_tcase(s, tc); + return s; +} + +#include "../check_setup.h" diff --git a/test/lladd/check_logWriter.c b/test/lladd/check_logWriter.c new file mode 100644 index 0000000..bcf9a7b --- /dev/null +++ b/test/lladd/check_logWriter.c @@ -0,0 +1,186 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include + +#include +#include +#include + +#define LOG_NAME "check_logWriter.log" + +static void setup_log() { + int i; + lsn_t prevLSN = -1; + int xid = 100; + deleteLogWriter(); + openLogWriter(); + + for(i = 0 ; i < 1000; i++) { + LogEntry * e = allocCommonLogEntry(prevLSN, xid, XBEGIN); + LogEntry * f; + recordid rid; + byte * args = (byte*)"Test 123."; + size_t args_size = 10; /* Including null */ + unsigned long preImage = 42; + + rid.page = 0; + rid.slot = 0; + rid.size = sizeof(unsigned long); + + writeLogEntry(e); + prevLSN = e->LSN; + + f = readLSNEntry(prevLSN); + fail_unless(sizeofLogEntry(e) == sizeofLogEntry(f), "Log entry changed size!!"); + fail_unless(0 == memcmp(e,f,sizeofLogEntry(e)), "Log entries did not agree!!"); + + free (e); + free (f); + + e = allocUpdateLogEntry(prevLSN, xid, 1, rid, args, args_size, (byte*) &preImage); + writeLogEntry(e); + prevLSN = e->prevLSN; + f = allocCLRLogEntry(100, 1, 200, rid, prevLSN); + + prevLSN = f->prevLSN; + + writeLogEntry(f); + free (e); + free (f); + } +} +/** + @test + + Quick test of log writer and log handler. Not very extensive. + Just writes out 3000 log entries, checks that 1000 of them make + sense, and then closes, opens and iterates over the resulting log + file to make sure that it contains 3000 entries, and none of its + builtin assertions fail. + + In particular, logWriter checks to make sure that each log entry's + size matches the size that it recorded before the logEntry. Also, + when checking the 1000 of 3000 entries, this test uses + readLSNEntry, which tests the logWriter's ability to succesfully + manipulate LSN's. + + @todo Test logHandle more thoroughly. (Still need to test the guard mechanism.) + +*/ +START_TEST(logWriterTest) +{ + LogEntry * e; + LogHandle h; + int i = 0; + setup_log(); + syncLog(); + closeLogWriter(); + + openLogWriter(); + + + h = getLogHandle(); + /* readLSNEntry(sizeof(lsn_t)); */ + + while((e = nextInLog(&h))) { + i++; + } + + + fail_unless(i = 3000, "Wrong number of log entries!"); + + deleteLogWriter(); + + +} +END_TEST + +/** + @test + Checks for a bug ecountered during devlopment. What happens when + previousInTransaction is called immediately after the handle is + allocated? */ + +START_TEST(logHandleColdReverseIterator) { + LogEntry * e; + LogHandle lh = getLogHandle(); + int i = 0; + setup_log(); + + + while(((e = nextInLog(&lh)) && (i < 100)) ) { + i++; + } + + i = 0; + lh = getLogHandle(e->LSN); + + while((e = previousInTransaction(&lh))) { + i++; + } + /* printf("i = %d\n", i); */ + fail_unless( i == 1 , NULL); /* The 1 is because we immediately hit a clr that goes to the beginning of the log... */ + + deleteLogWriter(); + +} +END_TEST + +Suite * check_suite(void) { + Suite *s = suite_create("logWriter"); + /* Begin a new test */ + TCase *tc = tcase_create("writeNew"); + + /* Sub tests are added, one per line, here */ + + tcase_add_test(tc, logWriterTest); + tcase_add_test(tc, logHandleColdReverseIterator); + + /* --------------------------------------------- */ + + suite_add_tcase(s, tc); + return s; +} + +#include "../check_setup.h" diff --git a/test/lladd/check_operations.c b/test/lladd/check_operations.c new file mode 100644 index 0000000..7de71ea --- /dev/null +++ b/test/lladd/check_operations.c @@ -0,0 +1,168 @@ +/*--- This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include + +#include +#include + +#include "../check_includes.h" + +#define LOG_NAME "check_operations.log" +/** + Assuming that the Tset() operation is implemented correctly, checks + that doUpdate, redoUpdate and undoUpdate are working correctly, for + operations that use physical logging. +*/ +START_TEST(operation_physical_do_undo) { + int xid = 1; + recordid rid; + lsn_t lsn = 0; + int buf; + int arg; + LogEntry * setToTwo; + + Tinit(); + + rid = ralloc(xid, sizeof(int)); + buf = 1; + arg = 2; + setToTwo = allocUpdateLogEntry(-1, xid, OPERATION_SET, rid, (void*)&arg, sizeof(int), (void*)&buf); + + /* Do, undo and redo operation without updating the LSN field of the page. */ + + writeLSN(lsn, rid.page); + writeRecord(xid, rid, &buf); + + setToTwo->LSN = 1; + + doUpdate(setToTwo); + + readRecord(xid, rid, &buf); + + fail_unless(buf == 2, NULL); + + undoUpdate(setToTwo); /* Should fail, LSN wasn't updated. */ + + readRecord(xid, rid, &buf); + + fail_unless(buf == 2, NULL); + + redoUpdate(setToTwo); + + + readRecord(xid, rid, &buf); + + fail_unless(buf == 2, NULL); + + writeLSN(3,rid.page); + + /* Now, simulate scenarios from normal operation: + do the operation, and update the LSN, (update happens) + then undo, and update the LSN again. (undo happens) + attempt a redo, don't update lsn (nothing happens) + + Lower the LSN + attempt redo (redo succeeds) + + */ + + lsn = 0; + buf = 1; + + writeLSN(lsn, rid.page); + writeRecord(xid, rid, &buf); + + setToTwo->LSN = 1; + + doUpdate(setToTwo); + writeLSN(setToTwo->LSN, rid.page); + + readRecord(xid, rid, &buf); + + fail_unless(buf == 2, NULL); + + undoUpdate(setToTwo); /* Succeeds */ + + readRecord(xid, rid, &buf); + + fail_unless(buf == 1, NULL); + + redoUpdate(setToTwo); /* Fails */ + + readRecord(xid, rid, &buf); + + fail_unless(buf == 1, NULL); + + writeLSN(0,rid.page); + + redoUpdate(setToTwo); /* Succeeds */ + + readRecord(xid, rid, &buf); + + fail_unless(buf == 2, NULL); + + Tdeinit(); +} +END_TEST + + +/** + Add suite declarations here +*/ +Suite * check_suite(void) { + Suite *s = suite_create("operations"); + /* Begin a new test */ + TCase *tc = tcase_create("operations_simple"); + + /* Sub tests are added, one per line, here */ + tcase_add_test(tc, operation_physical_do_undo); + + /* --------------------------------------------- */ + tcase_add_checked_fixture(tc, setup, teardown); + suite_add_tcase(s, tc); + + + return s; +} + +#include "../check_setup.h" diff --git a/test/lladd/check_recovery.c b/test/lladd/check_recovery.c new file mode 100644 index 0000000..249ef9e --- /dev/null +++ b/test/lladd/check_recovery.c @@ -0,0 +1,509 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +/*#include */ + +#include +#include +#include "../check_includes.h" + +#define LOG_NAME "check_recovery.log" + +/** + @test + Simple test: Insert some stuff. Commit. Call Tdeinit(). Call + Tinit() (Which initiates recovery), and see if the stuff we + inserted is still there. + + Only performs idempotent operations (Tset). +*/ +START_TEST (recovery_idempotent) { + int xid; + int j; + int k; + recordid rid; + Tinit(); + xid = Tbegin(); + + rid = Talloc(xid, sizeof(int)); + + j = 1; + + Tset(xid, rid, &j); + + Tcommit(xid); + + xid = Tbegin(); + + Tread(xid, rid, &k); + + fail_unless(j == k, "Get/Set broken?"); + + Tcommit(xid); + + Tdeinit(); + + Tinit(); /* Runs recovery.. */ + + k = 12312; + + xid = Tbegin(); + + Tread(xid, rid, &k); + + fail_unless(j == k, "Recovery messed something up!"); + + Tcommit(xid); + + Tdeinit(); + +} +END_TEST + +/** + @test + Simple test: Alloc a record, commit. Call Tincrement on it, and + remember its value and commit. Then, call Tdeinit() and Tinit() + (Which initiates recovery), and see if the value changes. +*/ +START_TEST (recovery_exactlyOnce) { + + int xid; + int j; + int k; + recordid rid; + Tinit(); + xid = Tbegin(); + + rid = Talloc(xid, sizeof(int)); + + Tincrement(xid, rid); + + Tread(xid, rid, &j); + + Tcommit(xid); + + xid = Tbegin(); + + Tread(xid, rid, &k); + + fail_unless(j == k, "Get/Set broken?"); + + Tcommit(xid); + + Tdeinit(); + + Tinit(); /* Runs recovery.. */ + + k = 12312; + + xid = Tbegin(); + + Tread(xid, rid, &k); + + fail_unless(j == k, "Recovery messed something up!"); + + Tcommit(xid); + + Tdeinit(); + + + +} +END_TEST + + +/** + @test + Makes sure that aborted idempotent operations are correctly undone. +*/ +START_TEST (recovery_idempotentAbort) { + + int xid; + int j; + int k; + recordid rid; + Tinit(); + xid = Tbegin(); + + rid = Talloc(xid, sizeof(int)); + j = 1; + Tset(xid, rid, &j); + + Tread(xid, rid, &j); + + Tcommit(xid); + + xid = Tbegin(); + + Tread(xid, rid, &k); + + fail_unless(j == k, "Get/Set broken?"); + + Tcommit(xid); + xid = Tbegin(); + k = 2; + Tset(xid, rid, &k); + k = 4; + Tread(xid, rid, &k); + fail_unless(k == 2, NULL); + Tabort(xid); + + xid = Tbegin(); + k = 4; + Tread(xid, rid, &k); + + Tabort(xid); + + fail_unless(j == k, "Didn't abort!"); + + Tdeinit(); + + Tinit(); /* Runs recovery.. */ + + k = 12312; + + xid = Tbegin(); + + Tread(xid, rid, &k); + + fail_unless(j == k, "Recovery messed something up!"); + + Tcommit(xid); + + Tdeinit(); + +} +END_TEST + + +/** + @test + Makes sure that aborted idempotent operations are correctly undone. +*/ +START_TEST (recovery_exactlyOnceAbort) { + + int xid; + int j; + int k; + recordid rid; + Tinit(); + xid = Tbegin(); + + rid = Talloc(xid, sizeof(int)); + j = 1; + Tincrement(xid, rid); + + Tread(xid, rid, &j); + + Tcommit(xid); + + xid = Tbegin(); + + Tincrement(xid, rid); + Tread(xid, rid, &k); + fail_unless(j == k-1, NULL); + Tabort(xid); + xid = Tbegin(); + Tread(xid, rid, &k); + fail_unless(j == k, "didn't abort?"); + Tcommit(xid); + + Tdeinit(); + Tinit(); + + xid = Tbegin(); + + Tread(xid, rid, &k); + fail_unless(j == k, "Recovery didn't abort correctly"); + Tcommit(xid); + Tdeinit(); + +} +END_TEST + +/** + @test + Check the CLR mechanism with an aborted logical operation, and multipl Tinit()/Tdeinit() cycles. +*/ +START_TEST(recovery_clr) { + recordid rid; + int xid; + int j; + int k; + + DEBUG("\n\nStart CLR test\n\n"); + + Tinit(); + + xid = Tbegin(); + + rid = Talloc(xid, sizeof(int)); + + Tread(xid, rid, &j); + + Tincrement(xid, rid); + + Tabort(xid); + + xid = Tbegin(); + + Tread(xid, rid, &k); + + Tcommit(xid); + + fail_unless(j == k, NULL); + + Tdeinit(); + + + Tinit(); + Tdeinit(); + + Tinit(); + + xid = Tbegin(); + + Tread(xid, rid, &k); + + Tcommit(xid); + + fail_unless(j == k, NULL); + + Tdeinit(); + Tinit(); + + xid = Tbegin(); + + Tread(xid, rid, &k); + + Tcommit(xid); + + fail_unless(j == k, NULL); + + Tdeinit(); + + +} END_TEST + +void simulateBufferManagerCrash(); +extern int numActiveXactions; +/** + @test + + Tests the undo phase of recovery by simulating a crash, and calling Tinit(). */ +START_TEST(recovery_crash) { + int xid; + recordid rid; + int j; + + Tinit(); + + xid = Tbegin(); + rid = Talloc(xid, sizeof(int)); + + j = 0; + + Tset(xid, rid, &j); + + Tincrement(xid, rid); + Tincrement(xid, rid); + Tincrement(xid, rid); + + Tincrement(xid, rid); + Tincrement(xid, rid); + Tincrement(xid, rid); + + Tincrement(xid, rid); + Tincrement(xid, rid); + Tincrement(xid, rid); + + /* RID = 9. */ + + Tread(xid, rid, &j); + fail_unless(j == 9, "Increment not working?"); + + + Tcommit(xid); + xid = Tbegin(); + + Tdecrement(xid, rid); + Tdecrement(xid, rid); + Tdecrement(xid, rid); + + /* RID = 6. */ + + Tread(xid, rid, &j); + fail_unless(j == 6, "Decrement not working?"); + + simulateBufferManagerCrash(); + closeLogWriter(); + numActiveXactions = 0; + + Tinit(); + + Tread(xid, rid, &j); + + fail_unless(j == 9, "Recovery didn't roll back in-progress xact!"); + + Tdeinit(); + Tinit(); + + Tread(xid, rid, &j); + + fail_unless(j == 9, "Recovery failed on second re-open."); + + Tdeinit(); + +} END_TEST +/** + @test + + Tests recovery when more than one transaction is in progress at the time of the crash. +*/ +START_TEST (recovery_multiple_xacts) { + int xid1, xid2, xid3, xid4; + recordid rid1, rid2, rid3, rid4; + int j1, j2, j3, j4, k; + Tinit(); + j1 = 1; + j2 = 2; + j3 = 4; + j4 = 3; + xid1 = Tbegin(); + rid1 = Talloc(xid1, sizeof(int)); + + xid2 = Tbegin(); + + xid3 = Tbegin(); + + Tset(xid1, rid1, &j1); + + rid2 = Talloc(xid2, sizeof(int)); + rid3 = Talloc(xid3, sizeof(int)); + Tread(xid3, rid3, &k); + + Tset(xid3, rid3, &j3); + + Tcommit(xid3); + xid3 = Tbegin(); + + Tincrement(xid3, rid3); + Tset(xid2, rid2, &j2); + Tcommit(xid1); + + + xid4 = Tbegin(); + Tcommit(xid2); + + rid4 = Talloc(xid4, sizeof(int)); + Tset(xid4, rid4, &j4); + Tincrement(xid4, rid4); + Tcommit(xid4); + + xid1 = Tbegin(); + k = 100000; + Tset(xid1, rid1,&k); + xid2 = Tbegin(); + Tdecrement(xid2, rid2); + + Tdecrement(xid2, rid2); + Tdecrement(xid2, rid2); + Tdecrement(xid2, rid2); + Tdecrement(xid2, rid2); + Tincrement(xid1, rid1); + Tset(xid1, rid1,&k); + + /*simulate crash */ + + simulateBufferManagerCrash(); + closeLogWriter(); + numActiveXactions = 0; + Tinit(); + Tdeinit(); + Tinit(); + xid1 = Tbegin(); + xid2 = Tbegin(); + xid3 = Tbegin(); + xid4 = Tbegin(); + + Tread(xid1, rid1, &j1); + Tread(xid2, rid2, &j2); + Tread(xid3, rid3, &j3); + Tread(xid4, rid4, &j4); + + fail_unless(j1 == 1, NULL); + fail_unless(j2 == 2, NULL); + fail_unless(j3 == 4, NULL); + fail_unless(j4 == 4, NULL); + Tdeinit(); +} END_TEST + + +/** + Add suite declarations here +*/ +Suite * check_suite(void) { + Suite *s = suite_create("recovery_suite"); + /* Begin a new test */ + TCase *tc = tcase_create("recovery"); + + /* Sub tests are added, one per line, here */ + tcase_add_test(tc, recovery_idempotent); + tcase_add_test(tc, recovery_exactlyOnce); + + tcase_add_test(tc, recovery_idempotentAbort); + tcase_add_test(tc, recovery_exactlyOnceAbort); + + tcase_add_test(tc, recovery_clr); + tcase_add_test(tc, recovery_crash); + tcase_add_test(tc, recovery_multiple_xacts); + + /* --------------------------------------------- */ + tcase_add_checked_fixture(tc, setup, teardown); + suite_add_tcase(s, tc); + + return s; +} + +#include "../check_setup.h" diff --git a/test/lladd/check_transactional2.c b/test/lladd/check_transactional2.c new file mode 100644 index 0000000..c662975 --- /dev/null +++ b/test/lladd/check_transactional2.c @@ -0,0 +1,106 @@ +/*--- This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include + +#include + +#define LOG_NAME "check_transactional2.log" +/** + Assuming that the Tset() operation is implemented correctly, checks + that doUpdate, redoUpdate and undoUpdate are working correctly, for + operations that use physical logging. +*/ +START_TEST(transactional_smokeTest) { + + int xid; + recordid rid; + int foo = 2; + int bar; + + Tinit(); + + xid = Tbegin(); + + rid = Talloc(xid, sizeof(int)); + + Tset(xid, rid, &foo); + + bar = 4; + + Tread(xid, rid, &bar); + + fail_unless(bar == foo, NULL); + + Tcommit(xid); + + xid = Tbegin(); + + bar = 4; + Tread(xid, rid, &bar); + fail_unless(bar == foo, NULL); + + + Tabort(xid); + + Tdeinit(); +} +END_TEST + +/** + Add suite declarations here +*/ +Suite * check_suite(void) { + Suite *s = suite_create("transactional"); + /* Begin a new test */ + TCase *tc = tcase_create("transactional_smokeTest"); + + /* Sub tests are added, one per line, here */ + tcase_add_test(tc, transactional_smokeTest); + /* --------------------------------------------- */ + suite_add_tcase(s, tc); + + + return s; +} + +#include "../check_setup.h" diff --git a/test/messages/Makefile.am b/test/messages/Makefile.am new file mode 100644 index 0000000..e69de29 diff --git a/test/messages/ping_pong.c b/test/messages/ping_pong.c new file mode 100644 index 0000000..9cd305d --- /dev/null +++ b/test/messages/ping_pong.c @@ -0,0 +1,94 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../libdfa/messages.h" +#include +#include +#include +#include +#include +#include + +int main (int argc, char ** argv) { + short portnum; + /* short target_portnum; + char * target_ip; */ + NetworkSetup ns; + Message m; + /* struct sockaddr_in to, from; */ + char * to; + char from[MAX_ADDRESS_LENGTH+1]; + + printf("This test code is out of date. Exiting.\n"); + + if(argc != 3) { + printf("Usage: %s port_num ip_address\n", argv[0]); + return -1; + + } + + return 0; + + portnum = (unsigned short) atoi(argv[1]); + to = argv[2]; + /* target_ip = argv[2]; + target_portnum = (unsigned short) atoi(argv[3]); */ + + init_network(&ns, portnum); + + /* to.sin_family = AF_INET; + err=inet_aton(target_ip, &(to.sin_addr)); + if(err == 0) { + perror("inet_aton"); + } + to.sin_port = htons(target_portnum); + */ + send_message(&ns, &m, to); + + printf("Ping"); + fflush(NULL); + + receive_message(&ns, &m, from); + + + printf("Hello %s\n", from); + return 0; +} diff --git a/test/monotree/Makefile.am b/test/monotree/Makefile.am new file mode 100644 index 0000000..dcffca1 --- /dev/null +++ b/test/monotree/Makefile.am @@ -0,0 +1,4 @@ +LDADD=$(top_builddir)/src/libdfa/libdfa.a $(top_builddir)/src/lladd/liblladd.a +bin_PROGRAMS=bit_arithmetic binary_search soundness +soundness_SOURCES = soundness.c +AM_CFLAGS= -g -Wall -pedantic -std=c99 diff --git a/test/monotree/binary_search.c b/test/monotree/binary_search.c new file mode 100644 index 0000000..f313d28 --- /dev/null +++ b/test/monotree/binary_search.c @@ -0,0 +1,77 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../src/libdfa/monotree.h" +#include +#include +int main () { + MonoTree * rb; + int size = 100; + state_machine_id i; + StateMachine * sm; + + rb = malloc(sizeof(MonoTree)); + + rb->buffer = malloc(size * sizeof(StateMachine)); + + init_MonoTree(rb, size); + + /* Shouldn't call compact, so we don't rely on that code to get here. */ + + for(i = 0; i < size; i++) { + sm = allocMachine(rb); + assert(0 != sm); + sm->current_state = 1; + assert(sm->machine_id==i); + } + + assert(0 == allocMachine(rb)); + + for(i = 0; i < size; i++) { + sm = getMachine(rb, i); + assert(sm->machine_id==i); + } + + free(rb->buffer); + free(rb); + + return 0; +} diff --git a/test/monotree/bit_arithmetic.c b/test/monotree/bit_arithmetic.c new file mode 100644 index 0000000..046776c --- /dev/null +++ b/test/monotree/bit_arithmetic.c @@ -0,0 +1,67 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include +#include +#include "../../libdfa/libdfa.h" +int round_size_up(int orig_size); + +int main () { + printf("Testing round_size_up"); + + + assert(0 == round_size_up(0)); + assert(1 == round_size_up(1)); + assert(2 == round_size_up(2)); + assert(4 == round_size_up(3)); + assert(4 == round_size_up(4)); + assert(8 == round_size_up(5)); + assert(8 == round_size_up(8)); + assert(16 == round_size_up(9)); + assert(16 == round_size_up(16)); + assert(32 == round_size_up(17)); + assert(32 == round_size_up(32)); + + printf("Passed.\n"); + + return 0; + +} diff --git a/test/monotree/soundness.c b/test/monotree/soundness.c new file mode 100644 index 0000000..68b5cdd --- /dev/null +++ b/test/monotree/soundness.c @@ -0,0 +1,190 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ +#include "../../src/libdfa/monotree.h" + +#include +#include +#include +#include + +int main () { + + MonoTree * rb; + + srand (1); + + while (1) { + + int i = 0; + int rb_size = 1 + (int) (5000.0*rand()/(RAND_MAX+1.0)); + int tx_count = 1 + (int)(30000.0*rand()/(RAND_MAX+1.0)); + unsigned char * bitmap = calloc(tx_count, sizeof(unsigned char)); + unsigned int new_seed = (int) ((1.0* INT_MAX*rand())/(RAND_MAX+1.0)); + state_machine_id remaining_xact = 0; + state_machine_id last_xact = 0; + rb = malloc (sizeof(MonoTree)); + rb->buffer = malloc(sizeof(StateMachine) * rb_size); + + init_MonoTree(rb, rb_size); + + printf("Created a mono tree of size %d.\n", rb_size); + printf("Running %d random 'machines through it.\n", tx_count); + + for( ; remaining_xact != 0 || last_xact < tx_count; ) { + int choice = 1+ (int) (7.0*rand()/(RAND_MAX+1.0)); + int victim; + if(!(i % 50000)) { + printf("%d %ld %ld\n", i, last_xact, remaining_xact); + } i++; + switch (choice) { + case 1: + /* case 2: */ + /* Initiate new */ + if(last_xact < tx_count) { + StateMachine * sm = allocMachine(rb); + if(sm != 0) { + sm->current_state = 1; + assert(sm->machine_id == last_xact); + assert(bitmap[last_xact]==0); + bitmap[last_xact] = 1; + last_xact++; + remaining_xact++; + } + } + break; + case 3: + /* Kill random */ + victim = (int)((1.0 * last_xact * rand())/RAND_MAX+1.0); + while(!bitmap[victim] && victim < last_xact) { + victim++; + } + if(victim == last_xact) { + victim = 0; + while(!bitmap[victim] && victim < last_xact) { + victim++; + } + } + if(victim < last_xact) { + freeMachine(rb, victim); + assert(bitmap[victim] == 1); + assert(0 == getMachine(rb, victim)); + bitmap[victim] = 0; + remaining_xact--; + } + break; + case 4: + /* Lookup random empty */ + victim = (int)((1.0 * last_xact * rand())/RAND_MAX+1.0); + while(bitmap[victim] && victim < last_xact) { + victim++; + } + if(victim < last_xact) { + assert(0 == getMachine(rb, victim)); + } + break; + case 5: + case 2: + /* Insert random empty */ + if(last_xact < tx_count) { + victim = (int)((1.0 * last_xact * rand())/RAND_MAX+1.0); + while(bitmap[victim] && victim < last_xact) { + victim++; + } + if(victim < last_xact) { + if(rb->high_water_mark == rb->size) { + assert(0 == getMachine(rb, victim)); + if(insertMachine(rb, victim)) { + bitmap[victim] = 1; + remaining_xact++; + } + } else { + assert(0 != insertMachine(rb, victim)); + assert(victim == (getMachine(rb, victim)->machine_id)); + bitmap[victim] = 1; + remaining_xact++; + } + } + } + break; + case 6: + /* Insert random existing */ + victim = (int)((1.0 * last_xact * rand())/RAND_MAX+1.0); + while(!bitmap[victim] && victim < last_xact) { + victim++; + } + if(victim < last_xact) { + assert(0 == insertMachine(rb, victim)); + } + break; + default: + /* Lookup random existing */ + victim = (int)((1.0 * last_xact * rand())/RAND_MAX+1.0); + while(!bitmap[victim] && victim < last_xact) { + victim++; + } + if(victim < last_xact) { + assert(0 != getMachine(rb, victim)); + } + break; + } + /* for(i = 1; i < rb->size; i++) { + assert(rb->buffer[i-1].machine_id < rb->buffer[i].machine_id || + (rb->buffer[i-1].machine_id == ULONG_MAX && rb->buffer[i].machine_id == ULONG_MAX)); + }*/ + + } + + + free(rb->buffer); + free(rb); + free(bitmap); + + printf("New seed %d\n", new_seed); + srand(new_seed); + + + } + + return 0; + + +}