commit d1f76f0b4a1fe9d0f2adcb751c5f4315c3ec0cb4 Author: Sears Russell Date: Thu Jun 24 21:10:31 2004 +0000 Initial revision 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 0000000..f78f30e Binary files /dev/null and b/src/pbl/doc/icon1.gif differ diff --git a/src/pbl/doc/icon2.gif b/src/pbl/doc/icon2.gif new file mode 100755 index 0000000..6cbe01a Binary files /dev/null and b/src/pbl/doc/icon2.gif differ 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 0000000..16ab92b Binary files /dev/null and b/src/pbl/pblhttst differ 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 0000000..887179d Binary files /dev/null and b/src/pbl/pbliftst differ 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: + *
    + * 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 \Ref{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! + * + *
+ */ + +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 0000000..b2031c1 Binary files /dev/null and b/src/pbl/pbliftstdeb.ncb differ diff --git a/src/pbl/pbliftstdeb.opt b/src/pbl/pbliftstdeb.opt new file mode 100755 index 0000000..bd1327e Binary files /dev/null and b/src/pbl/pbliftstdeb.opt differ 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 0000000..c528e5f Binary files /dev/null and b/src/pbl/pblkfblockprint differ diff --git a/src/pbl/pblkfblockprint.c b/src/pbl/pblkfblockprint.c new file mode 100644 index 0000000..ad337fb --- /dev/null +++ b/src/pbl/pblkfblockprint.c @@ -0,0 +1,74 @@ +/* + pblkfblockprint.c - shell program to print block layout + + 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:34 sears + Initial revision + + Revision 1.1 2003/12/11 09:10:49 jim + pbl + + Revision 1.1 2002/09/12 20:47:08 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" + +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 0000000..88ef8c3 Binary files /dev/null and b/src/pbl/pblkftst differ diff --git a/src/pbl/pblkftst.c b/src/pbl/pblkftst.c new file mode 100644 index 0000000..e2237b0 --- /dev/null +++ b/src/pbl/pblkftst.c @@ -0,0 +1,818 @@ +/* + pblkftst.c - interactive PBL key 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:12:09 sears + Initial revision + + Revision 1.1 2003/12/11 09:10:49 jim + pbl + + Revision 1.1 2002/09/12 20:47:08 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" + +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; + + +}