Update of /project/elephant/cvsroot/elephant/src
In directory common-lisp.net:/tmp/cvs-serv25936/src
Modified Files:
sleepycat.lisp
Log Message:
split off berkeley-db
doc-strings
buffer-streamified
cmu pointer arithmetic
Date: Thu Sep 16 06:22:41 2004
Author: blee
Index: elephant/src/sleepycat.lisp
diff -u elephant/src/sleepycat.lisp:1.9 elephant/src/sleepycat.lisp:1.10
--- elephant/src/sleepycat.lisp:1.9 Thu Sep 2 16:47:09 2004
+++ elephant/src/sleepycat.lisp Thu Sep 16 06:22:41 2004
@@ -42,20 +42,54 @@
(defpackage sleepycat
+ (:documentation "A low-level UFFI-based interface to
+Berkeley DB / Sleepycat, via the libsleepycat.c wrapper.
+Partly intended to be usable outside Elephant, but with some
+magic for Elephant. In general there is a 1-1 mapping from
+functions here and functions in Sleepycat, so refer to their
+documentation for details.")
(:use common-lisp uffi)
+ #+cmu
+ (:use alien)
+ #+sbcl
+ (:use sb-alien)
+ #+cmu
+ (:import-from :sys
+ #:sap+)
+ #+sbcl
+ (:import-from :sb-sys
+ #:sap+)
+ #+openmcl
+ (:import-from :ccl
+ #:byte-length)
(:export #:*current-transaction*
- #:read-int #:read-uint #:read-float #:read-double
- #:write-int #:write-uint #:write-float #:write-double
- #:offset-char-pointer #:copy-str-to-buf #:copy-bufs #:byte-length
+
+ #:buffer-stream #:make-buffer-stream #:with-buffer-streams
+ #:resize-buffer-stream #:resize-buffer-stream-no-copy
+ #:reset-buffer-stream #:buffer-stream-buffer
+ #:buffer-write-byte #:buffer-write-int
+ #:buffer-write-uint #:buffer-write-float #:buffer-write-double
+ #:buffer-write-string #:buffer-read-byte #:buffer-read-fixnum
+ #:buffer-read-int #:buffer-read-uint #:buffer-read-float
+ #:buffer-read-double #:buffer-read-string #:byte-length
+
#:pointer-int #:pointer-void #:array-or-pointer-char
+
#:db-env-create #:db-env-close #:db-env-open #:db-env-dbremove
#:db-env-dbrename #:db-env-remove
#:db-env-set-flags #:db-env-get-flags
#:db-create #:db-close #:db-open
#:db-remove #:db-rename #:db-sync #:db-truncate
+ #:db-set-flags #:db-get-flags
#:db-get-key-buffered #:db-get-buffered #:db-get
#:db-put-buffered #:db-put
#:db-delete-buffered #:db-delete
+ #:db-cursor #:db-cursor-close #:db-cursor-delete
+ #:db-cursor-duplicate
+ #:db-cursor-move-buffered #:db-cursor-set-buffered
+ #:db-cursor-get-both-buffered
+ #:db-cursor-pmove-buffered #:db-cursor-pset-buffered
+ #:db-cursor-pget-both-buffered #:db-cursor-put-buffered
#:db-transaction-begin #:db-transaction-abort
#:db-transaction-commit #:with-transaction
#:db-transaction-id #:db-env-lock-id #:db-env-lock-id-free
@@ -63,6 +97,7 @@
#:db-env-set-timeout #:db-env-get-timeout
#:db-env-set-lock-detect #:db-env-get-lock-detect
#:db-error #:db-error-errno
+
#:+NULL-VOID+ #:+NULL-CHAR+
#:DB-BTREE #:DB-HASH #:DB-QUEUE #:DB-RECNO #:DB-UNKNOWN
#:DB_KEYEMPTY #:DB_LOCK_DEADLOCK #:DB_LOCK_NOTGRANTED
@@ -74,6 +109,10 @@
(in-package "SLEEPYCAT")
+#+cmu
+(eval-when (:compile-toplevel)
+ (proclaim '(optimize (ext:inhibit-warnings 3))))
+
(eval-when (:compile-toplevel :load-toplevel)
;; UFFI
;;(asdf:operate 'asdf:load-op :uffi)
@@ -98,14 +137,14 @@
#+(or bsd freebsd)
"/usr/local/lib/db42/libdb.so"
#+darwin
- "/usr/local/BerkeleyDB.4.2/lib/libdb.dylib"
+ "/usr/local/BerkeleyDB.4.2/lib/libdb.dylib"
:module "sleepycat")
(error "Couldn't load libdb (Sleepycat)!"))
;; Libsleepycat.so: edit this
(unless
(uffi:load-foreign-library
- "/usr/local/share/common-lisp/elephant-0.1/libsleepycat.so"
+ "/usr/local/share/common-lisp/elephant-0.2/libsleepycat.so"
:module "libsleepycat")
(error "Couldn't load libsleepycat!"))
@@ -123,16 +162,15 @@
(declaim (inline read-int read-uint read-float read-double
write-int write-uint write-float write-double
offset-char-pointer copy-str-to-buf copy-bufs
- %db-get-key-buffered db-get-key-buffered
- %db-get-buffered db-get-buffered db-get
- %db-put-buffered db-put-buffered
- %db-put db-put
- %db-delete db-delete-buffered db-delete
- %db-txn-begin db-transaction-begin
- %db-txn-abort db-transaction-abort
- %db-txn-commit db-transaction-commit
- %db-transaction-id
- flags))
+ ;;resize-buffer-stream
+ ;;buffer-stream-buffer buffer-stream-size buffer-stream-position
+ ;;buffer-stream-length
+ reset-buffer-stream
+ buffer-write-byte buffer-write-int buffer-write-uint
+ buffer-write-float buffer-write-double buffer-write-string
+ buffer-read-byte buffer-read-fixnum buffer-read-int
+ buffer-read-uint buffer-read-float buffer-read-double
+ buffer-read-string))
;; Constants and Flags
;; eventually write a macro which generates a custom flag function.
@@ -169,81 +207,293 @@
(defconstant DB_TXN_NOWAIT #x0001000)
(defconstant DB_TXN_SYNC #x0002000)
(defconstant DB_LOCK_NOWAIT #x001)
+(defconstant DB_DUP #x0000002)
+(defconstant DB_DUPSORT #x0000004)
-(defconstant DB_GET_BOTH 10)
-(defconstant DB_SET_LOCK_TIMEOUT 29)
-(defconstant DB_SET_TXN_TIMEOUT 33)
-
-(defconstant DB_KEYEMPTY -30997)
-(defconstant DB_LOCK_DEADLOCK -30995)
-(defconstant DB_LOCK_NOTGRANTED -30994)
-(defconstant DB_NOTFOUND -30990)
+(defconstant DB_CURRENT 7)
+(defconstant DB_FIRST 9)
+(defconstant DB_GET_BOTH 10)
+(defconstant DB_GET_BOTH_RANGE 12)
+(defconstant DB_LAST 17)
+(defconstant DB_NEXT 18)
+(defconstant DB_NEXT_DUP 19)
+(defconstant DB_NEXT_NODUP 20)
+(defconstant DB_PREV 25)
+(defconstant DB_PREV_NODUP 26)
+(defconstant DB_SET 28)
+(defconstant DB_SET_RANGE 30)
+
+(defconstant DB_AFTER 1)
+(defconstant DB_BEFORE 3)
+(defconstant DB_KEYFIRST 15)
+(defconstant DB_KEYLAST 16)
+
+(defconstant DB_NODUPDATA 21)
+(defconstant DB_NOOVERWRITE 22)
+(defconstant DB_NOSYNC 23)
+
+(defconstant DB_POSITION 24)
+
+(defconstant DB_SET_LOCK_TIMEOUT 29)
+(defconstant DB_SET_TXN_TIMEOUT 33)
+
+(defconstant DB_KEYEMPTY -30997)
+(defconstant DB_KEYEXIST -30996)
+(defconstant DB_LOCK_DEADLOCK -30995)
+(defconstant DB_LOCK_NOTGRANTED -30994)
+(defconstant DB_NOTFOUND -30990)
-(defvar +NULL-VOID+ (make-null-pointer :void))
-(defvar +NULL-CHAR+ (make-null-pointer :char))
+(defconstant DB_LOCK_DEFAULT 1)
+(defconstant DB_LOCK_EXPIRE 2)
+(defconstant DB_LOCK_MAXLOCKS 3)
+(defconstant DB_LOCK_MINLOCKS 4)
+(defconstant DB_LOCK_MINWRITE 5)
+(defconstant DB_LOCK_OLDEST 6)
+(defconstant DB_LOCK_RANDOM 7)
+(defconstant DB_LOCK_YOUNGEST 8)
+(defvar +NULL-VOID+ (make-null-pointer :void)
+ "A null pointer to a void type.")
+(defvar +NULL-CHAR+ (make-null-pointer :char)
+ "A null pointer to a char type.")
-;; Buffer management / pointer arithmetic
-;; Notes: on CMUCL and Allegro: with-cast-pointer +
-;; deref-array is faster than FFI + C pointer arithmetic.
-;; however pointer arithmetic is usually consing. OpenMCL
-;; supports non-consing pointer arithmentic though.
+(def-enum DB-LOCKOP ((:DUMP 0) :GET :GET-TIMEOUT :INHERIT
+ :PUT :PUT-ALL :PUT-OBJ :PUT-READ
+ :TIMEOUT :TRADE :UPGRADE-WRITE))
+(def-enum DB-LOCKMODE ((:NG 0) :READ :WRITE :WAIT
+ :IWRITE :IREAD :IWR :DIRTY :WWRITE))
-;; TODO: #+openmcl versions which do macptr arith.
+(def-struct DB-LOCK
+ (off :unsigned-int)
+ (ndx :unsigned-int)
+ (gen :unsigned-int)
+ (mode DB-LOCKMODE))
+
+#+openmcl
+(ccl:def-foreign-type DB-LOCK (:struct DB-LOCK))
+
+(def-struct DB-LOCKREQ
+ (op DB-LOCKOP)
+ (mode DB-LOCKMODE)
+ (timeout :unsigned-int)
+ (obj (:array :char))
+ (lock (* DB-LOCK)))
+
+#+openmcl
+(ccl:def-foreign-type DB-LOCKREQ (:struct DB-LOCKREQ))
+
+
+;; Thread local storage (special variables)
+
+(defvar *current-transaction* +NULL-VOID+
+ "The transaction which is currently in effect.")
+
+(defvar *errno-buffer* (allocate-foreign-object :int 1)
+ "Resourced space for errno return values.")
+(defvar *buffer-streams* (make-array 0 :adjustable t :fill-pointer t)
+ "Vector of buffer-streams, which you can grab / return.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; buffer-streams
+;;;
+;;; a stream-like interface for our buffers; methods are
+;;; below. ultimately we might want a gray / simple -stream
+;;; for real, for now who cares?
+
+(defstruct buffer-stream
+ "A stream-like interface to foreign (alien) char buffers."
+ (buffer (allocate-foreign-object :char 10) :type array-or-pointer-char)
+ (size 0 :type fixnum)
+ (position 0 :type fixnum)
+ (length 10 :type fixnum))
+
+(defun grab-buffer-stream ()
+ "Grab a buffer-stream from the *buffer-streams* resource pool."
+ (declare (optimize (speed 3)))
+ (if (= (length *buffer-streams*) 0)
+ (make-buffer-stream)
+ (vector-pop *buffer-streams*)))
+
+(defun return-buffer-stream (bs)
+ "Return a buffer-stream to the *buffer-streams* resource pool."
+ (declare (optimize (speed 3)))
+ (reset-buffer-stream bs)
+ (vector-push-extend bs *buffer-streams*))
+
+(defmacro with-buffer-streams (names &body body)
+ "Grab a buffer-stream, executes forms, and returns the
+stream to the pool on exit."
+ `(let ,(loop for name in names collect (list name '(grab-buffer-stream)))
+ (unwind-protect
+ (progn ,@body)
+ (progn
+ ,@(loop for name in names
+ collect (list 'return-buffer-stream name))))))
+
+;; Buffer management / pointer arithmetic
+
+;; Notes: on Allegro: with-cast-pointer + deref-array is
+;; faster than FFI + C pointer arithmetic. however pointer
+;; arithmetic is usually consing. OpenMCL supports
+;; non-consing pointer arithmentic though. Check these
+;; CMUCL / SBCL things don't cons unless necessary.
+
+;; TODO: #+openmcl versions which do macptr arith.
+
+#+(or cmu sbcl)
+(defun read-int (buf offset)
+ "Read a 32-bit signed integer from a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type fixnum offset))
+ (the (signed-byte 32)
+ (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* integer)))))
+
+#+(or cmu sbcl)
+(defun read-uint (buf offset)
+ "Read a 32-bit unsigned integer from a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type fixnum offset))
+ (the (unsigned-byte 32)
+ (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* (unsigned 32))))))
+
+#+(or cmu sbcl)
+(defun read-float (buf offset)
+ "Read a single-float from a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type fixnum offset))
+ (the single-float
+ (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* single-float)))))
+
+#+(or cmu sbcl)
+(defun read-double (buf offset)
+ "Read a double-float from a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type fixnum offset))
+ (the double-float
+ (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* double-float)))))
+
+#+(or cmu sbcl)
+(defun write-int (buf num offset)
+ "Write a 32-bit signed integer to a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type (signed-byte 32) num)
+ (type fixnum offset))
+ (setf (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* integer))) num))
+
+#+(or cmu sbcl)
+(defun write-uint (buf num offset)
+ "Write a 32-bit unsigned integer to a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type (unsigned-byte 32) num)
+ (type fixnum offset))
+ (setf (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* (unsigned 32)))) num))
+
+#+(or cmu sbcl)
+(defun write-float (buf num offset)
+ "Write a single-float to a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type single-float num)
+ (type fixnum offset))
+ (setf (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* single-float))) num))
+
+#+(or cmu sbcl)
+(defun write-double (buf num offset)
+ "Write a double-float to a foreign char buffer."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) buf)
+ (type double-float num)
+ (type fixnum offset))
+ (setf (deref (cast (sap-alien (sap+ (alien-sap buf) offset) (* char))
+ (* double-float))) num))
+
+#+(or cmu sbcl)
+(defun offset-char-pointer (p offset)
+ "Pointer arithmetic."
+ (declare (optimize (speed 3) (safety 0))
+ (type (alien (* char)) p)
+ (type fixnum offset))
+ (sap-alien (sap+ (alien-sap p) offset) (* char)))
+#-(or cmu sbcl)
(def-function ("read_int" read-int)
((buf array-or-pointer-char)
(offset :int))
:returning :int)
+#-(or cmu sbcl)
(def-function ("read_uint" read-uint)
((buf array-or-pointer-char)
(offset :int))
:returning :unsigned-int)
+#-(or cmu sbcl)
(def-function ("read_float" read-float)
((buf array-or-pointer-char)
(offset :int))
:returning :float)
+#-(or cmu sbcl)
(def-function ("read_double" read-double)
((buf array-or-pointer-char)
(offset :int))
:returning :double)
+#-(or cmu sbcl)
(def-function ("write_int" write-int)
((buf array-or-pointer-char)
(num :int)
(offset :int))
:returning :void)
+#-(or cmu sbcl)
(def-function ("write_uint" write-uint)
((buf array-or-pointer-char)
(num :unsigned-int)
(offset :int))
:returning :void)
+#-(or cmu sbcl)
(def-function ("write_float" write-float)
((buf array-or-pointer-char)
(num :float)
(offset :int))
:returning :void)
+#-(or cmu sbcl)
(def-function ("write_double" write-double)
((buf array-or-pointer-char)
(num :double)
(offset :int))
:returning :void)
+#-(or cmu sbcl)
(def-function ("offset_charp" offset-char-pointer)
((p array-or-pointer-char)
(offset :int))
:returning array-or-pointer-char)
;; Allegro and Lispworks use 16-bit unicode characters
+#+(or cmu sbcl allegro lispworks)
(defmacro byte-length (s)
+ "Return the number of bytes of the internal representation
+of a string."
#+(or lispworks (and allegro ics))
`(let ((l (length ,s))) (+ l l))
#-(or lispworks (and allegro ics))
@@ -274,6 +524,7 @@
;; but OpenMCL can't directly pass string bytes.
#+openmcl
(defun copy-str-to-buf (dest dest-offset src src-offset length)
+ "Copy a string to a foreign buffer. From Gary Byers."
(declare (optimize (speed 3) (safety 0))
(type string src)
(type array-or-pointer-char dest)
@@ -287,6 +538,7 @@
;; Lisp version, for kicks. this assumes 8-bit chars!
#+(not (or cmu sbcl scl allegro openmcl lispworks))
(defun copy-str-to-buf (dest dest-offset src src-offset length)
+ "Copy a string to a foreign buffer."
(declare (optimize (speed 3) (safety 0))
(type string src)
(type array-or-pointer-char dest)
@@ -313,36 +565,240 @@
(length :int))
:returning :void)
-;; Thread local storage (special variables)
-(declaim (type array-or-pointer-char *get-buffer*)
- (type fixnum *get-buffer-length*))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; buffer-stream functions
+
+(eval-when (:compile-toplevel)
+ (defun process-struct-slot-defs (slot-defs struct)
+ (loop for def in slot-defs
+ collect (list (first def) (list (second def) struct)))))
+
+(defmacro with-struct-slots (slot-defs struct &body body)
+ `(symbol-macrolet ,(process-struct-slot-defs slot-defs struct)
+ ,@body))
+
+(defun resize-buffer-stream (bs length)
+ "Resize the underlying buffer of a buffer-stream, copying the old data."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type fixnum length))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (when (> length len)
+ (let ((newlen (max length (* len 2))))
+ (declare (type fixnum newlen))
+ (let ((newbuf (allocate-foreign-object :char newlen)))
+ ;; technically we just need to copy from position to size.....
+ (copy-bufs newbuf 0 buf 0 size)
+ (free-foreign-object buf)
+ (setf buf newbuf)
+ (setf len newlen)
+ nil)))))
+
+(defun resize-buffer-stream-no-copy (bs length)
+ "Resize the underlying buffer of a buffer-stream."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type fixnum length))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (when (> length len)
+ (let ((newlen (max length (* len 2))))
+ (declare (type fixnum newlen))
+ (let ((newbuf (allocate-foreign-object :char newlen)))
+ (free-foreign-object buf)
+ (setf buf newbuf)
+ (setf len newlen)
+ nil)))))
-(defvar *current-transaction* +NULL-VOID+)
+(defun reset-buffer-stream (bs)
+ "'Empty' the buffer-stream."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs))
+ (setf (buffer-stream-size bs) 0)
+ (setf (buffer-stream-position bs) 0))
-(defvar *errno-buffer* (allocate-foreign-object :int 1))
+(defun buffer-write-byte (b bs)
+ "Write a byte."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type (unsigned-byte 8) b))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (let ((needed (+ size 1)))
+ (when (> needed len)
+ (resize-buffer-stream bs needed))
+ (setf (deref-array buf '(:array :char) size) b)
+ (setf size needed))))
-(defvar *get-buffer* (allocate-foreign-object :char 1))
-(defvar *get-buffer-length* 0)
+(defun buffer-write-int (i bs)
+ "Write a 32-bit signed integer."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type (signed-byte 32) i))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (let ((needed (+ size 4)))
+ (when (> needed len)
+ (resize-buffer-stream bs needed))
+ (write-int buf i size)
+ (setf size needed)
+ nil)))
-(defun resize-get-buffer (length)
- (declare (optimize (speed 3) (safety 0) (space 0))
+(defun buffer-write-uint (u bs)
+ "Write a 32-bit unsigned integer."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type (unsigned-byte 32) u))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (let ((needed (+ size 4)))
+ (when (> needed len)
+ (resize-buffer-stream bs needed))
+ (write-uint buf u size)
+ (setf size needed)
+ nil)))
+
+(defun buffer-write-float (d bs)
+ "Write a single-float."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type single-float d))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (let ((needed (+ size 4)))
+ (when (> needed len)
+ (resize-buffer-stream bs needed))
+ (write-float buf d size)
+ (setf size needed)
+ nil)))
+
+(defun buffer-write-double (d bs)
+ "Write a double-float."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type double-float d))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (let ((needed (+ size 8)))
+ (when (> needed len)
+ (resize-buffer-stream bs needed))
+ (write-double buf d size)
+ (setf size needed)
+ nil)))
+
+(defun buffer-write-string (s bs)
+ "Write the underlying bytes of a string. On Unicode
+Lisps, this is a 16-bit operation."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
+ (type string s))
+ (with-struct-slots ((buf buffer-stream-buffer)
+ (size buffer-stream-size)
+ (len buffer-stream-length))
+ bs
+ (let* ((str-bytes (byte-length s))
+ (needed (+ size str-bytes)))
+ (declare (type fixnum str-bytes needed)
+ (dynamic-extent str-bytes needed))
+ (when (> needed len)
+ (resize-buffer-stream bs needed))
+ (copy-str-to-buf buf size s 0 str-bytes)
+ (setf size needed)
+ nil)))
+
+(defun buffer-read-byte (bs)
+ "Read a byte."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs))
+ (let ((position (buffer-stream-position bs)))
+ (incf (buffer-stream-position bs))
+ (deref-array (buffer-stream-buffer bs) '(:array :char) position)))
+
+(defun buffer-read-fixnum (bs)
+ "Read a 32-bit signed integer, which is assumed to be a fixnum."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs))
+ (let ((position (buffer-stream-position bs)))
+ (setf (buffer-stream-position bs) (+ position 4))
+ (the fixnum (read-int (buffer-stream-buffer bs) position))))
+
+(defun buffer-read-int (bs)
+ "Read a 32-bit signed integer."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs))
+ (let ((position (buffer-stream-position bs)))
+ (setf (buffer-stream-position bs) (+ position 4))
+ (the (signed-byte 32) (read-int (buffer-stream-buffer bs) position))))
+
+(defun buffer-read-uint (bs)
+ "Read a 32-bit unsigned integer."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs))
+ (let ((position (buffer-stream-position bs)))
+ (setf (buffer-stream-position bs) (+ position 4))
+ (the (unsigned-byte 32)(read-uint (buffer-stream-buffer bs) position))))
+
+(defun buffer-read-float (bs)
+ "Read a single-float."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs))
+ (let ((position (buffer-stream-position bs)))
+ (setf (buffer-stream-position bs) (+ position 4))
+ (read-float (buffer-stream-buffer bs) position)))
+
+(defun buffer-read-double (bs)
+ "Read a double-float."
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs))
+ (let ((position (buffer-stream-position bs)))
+ (setf (buffer-stream-position bs) (+ position 8))
+ (read-double (buffer-stream-buffer bs) position)))
+
+(defun buffer-read-string (bs length)
+ "Read a string. On Unicode Lisps this is a 16-bit operation!"
+ (declare (optimize (speed 3) (safety 0))
+ (type buffer-stream bs)
(type fixnum length))
- (if (< length *get-buffer-length*)
- (values *get-buffer* *get-buffer-length*)
- (let ((newlen (max length (* *get-buffer-length* 2))))
- (declare (type fixnum newlen))
- (setq *get-buffer-length* newlen)
- (free-foreign-object *get-buffer*)
- (setq *get-buffer* (allocate-foreign-object :char newlen))
- (values *get-buffer* *get-buffer-length*))))
+ (let ((position (buffer-stream-position bs)))
+ (setf (buffer-stream-position bs) (+ position length))
+ ;; wide!!!
+ #+(and allegro ics)
+ (excl:native-to-string
+ (offset-char-pointer (buffer-stream-buffer bs) position)
+ :length length
+ :external-format :unicode)
+ #+lispworks
+ (fli:convert-from-foreign-string
+ (offset-char-pointer (buffer-stream-buffer bs) position)
+ :length length :external-format :unicode :null-terminated-p nil)
+ #-(or lispworks (and allegro ics))
+ (convert-from-foreign-string
+ (offset-char-pointer (buffer-stream-buffer bs) position)
+ :length length :null-terminated-p nil)))
;; Wrapper macro -- handles errno return values
;; makes flags into keywords
;; makes keyword args, cstring wrappers
-(eval-when (:compile-toplevel :load-toplevel)
+(eval-when (:compile-toplevel)
(defun make-wrapper-args (args flags keys)
(if (or flags keys)
(append (remove-keys (remove 'flags args) keys)
@@ -378,6 +834,7 @@
(defmacro wrap-errno (names args &key (keys nil) (flags nil)
(cstrings nil) (outs 1) (declarations nil)
+ (documentation nil)
(transaction nil))
(let ((wname (if (listp names) (first names) names))
(fname (if (listp names) (second names)
@@ -388,7 +845,8 @@
(if (> outs 1)
(let ((out-args (make-out-args outs)))
`(defun ,wname ,wrapper-args
- ,@(if declarations (list declarations) (values))
+ ,@(if documentation (list documentation) (values))
+ ,@(if declarations (list declarations) (values))
(with-cstrings ,(symbols-to-pairs cstrings)
(multiple-value-bind ,out-args
(,fname ,@fun-args)
@@ -399,10 +857,11 @@
,@(if transaction
(list `((or (= ,errno DB_LOCK_DEADLOCK)
(= ,errno DB_LOCK_NOTGRANTED))
- (throw ,transaction ,transaction)))
+ (throw 'transaction ,transaction)))
(values))
(t (error 'db-error :errno ,errno))))))))
`(defun ,wname ,wrapper-args
+ ,@(if documentation (list documentation) (values))
,@(if declarations (list declarations) (values))
(with-cstrings ,(symbols-to-pairs cstrings)
(let ((,errno (,fname ,@fun-args)))
@@ -412,769 +871,71 @@
,@(if transaction
(list `((or (= ,errno DB_LOCK_DEADLOCK)
(= ,errno DB_LOCK_NOTGRANTED))
- (throw ,transaction ,transaction)))
+ (throw 'transaction ,transaction)))
(values))
(t (error 'db-error :errno ,errno)))))))))
+(defmacro flags (&key auto-commit joinenv init-cdb init-lock init-log
+ init-mpool init-rep init-txn recover recover-fatal lockdown
+ private system-mem thread force dirty-read create excl nommap
+ rdonly truncate txn-nosync txn-nowait txn-sync lock-nowait
+ dup dup-sort current first get-both get-both-range last next
+ next-dup next-nodup prev prev-nodup set set-range
+ after before keyfirst keylast
+ no-dup-data no-overwrite nosync position set-lock-timeout
+ set-transaction-timeout)
+ (let ((flags (gensym)))
+ `(let ((,flags 0))
+ (declare (type fixnum ,flags))
+ ,@(when auto-commit `((when ,auto-commit (setq ,flags (logior ,flags DB_AUTO_COMMIT)))))
+ ,@(when joinenv `((when ,joinenv (setq ,flags (logior ,flags DB_JOINENV)))))
+ ,@(when init-cdb `((when ,init-cdb (setq ,flags (logior ,flags DB_INIT_CDB)))))
+ ,@(when init-lock `((when ,init-lock (setq ,flags (logior ,flags DB_INIT_LOCK)))))
+ ,@(when init-log `((when ,init-log (setq ,flags (logior ,flags DB_INIT_LOG)))))
+ ,@(when init-mpool `((when ,init-mpool (setq ,flags (logior ,flags DB_INIT_MPOOL)))))
+ ,@(when init-rep `((when ,init-rep (setq ,flags (logior ,flags DB_INIT_REP)))))
+ ,@(when init-txn `((when ,init-txn (setq ,flags (logior ,flags DB_INIT_TXN)))))
+ ,@(when recover `((when ,recover (setq ,flags (logior ,flags DB_RECOVER)))))
+ ,@(when recover-fatal `((when ,recover-fatal (setq ,flags (logior ,flags DB_RECOVER_FATAL)))))
+ ,@(when lockdown `((when ,lockdown (setq ,flags (logior ,flags DB_LOCKDOWN)))))
+ ,@(when private `((when ,private (setq ,flags (logior ,flags DB_PRIVATE)))))
+ ,@(when system-mem `((when ,system-mem (setq ,flags (logior ,flags DB_SYSTEM_MEM)))))
+ ,@(when thread `((when ,thread (setq ,flags (logior ,flags DB_THREAD)))))
+ ,@(when force `((when ,force (setq ,flags (logior ,flags DB_FORCE)))))
+ ,@(when dirty-read `((when ,dirty-read (setq ,flags (logior ,flags DB_DIRTY_READ)))))
+ ,@(when create `((when ,create (setq ,flags (logior ,flags DB_CREATE)))))
+ ,@(when excl `((when ,excl (setq ,flags (logior ,flags DB_EXCL)))))
+ ,@(when nommap `((when ,nommap (setq ,flags (logior ,flags DB_NOMMAP)))))
+ ,@(when rdonly `((when ,rdonly (setq ,flags (logior ,flags DB_RDONLY)))))
+ ,@(when truncate `((when ,truncate (setq ,flags (logior ,flags DB_TRUNCATE)))))
+ ,@(when txn-nosync `((when ,txn-nosync (setq ,flags (logior ,flags DB_TXN_NOSYNC)))))
+ ,@(when txn-nowait `((when ,txn-nowait (setq ,flags (logior ,flags DB_TXN_NOWAIT)))))
+ ,@(when txn-sync `((when ,txn-sync (setq ,flags (logior ,flags DB_TXN_SYNC)))))
+ ,@(when lock-nowait `((when ,lock-nowait (setq ,flags (logior ,flags DB_LOCK_NOWAIT)))))
+ ,@(when dup `((when ,dup (setq ,flags (logior ,flags DB_DUP)))))
+ ,@(when dup-sort `((when ,dup-sort (setq ,flags (logior ,flags DB_DUPSORT)))))
+ ,@(when current `((when ,current (setq ,flags (logior ,flags DB_CURRENT)))))
+ ,@(when first `((when ,first (setq ,flags (logior ,flags DB_FIRST)))))
+ ,@(when get-both `((when ,get-both (setq ,flags (logior ,flags DB_GET_BOTH)))))
+ ,@(when get-both-range `((when ,get-both-range (setq ,flags (logior ,flags DB_GET_BOTH_RANGE)))))
+ ,@(when last `((when ,last (setq ,flags (logior ,flags DB_LAST)))))
+ ,@(when next `((when ,next (setq ,flags (logior ,flags DB_NEXT)))))
+ ,@(when next-dup `((when ,next-dup (setq ,flags (logior ,flags DB_NEXT_DUP)))))
+ ,@(when next-nodup `((when ,next-nodup (setq ,flags (logior ,flags DB_NEXT_NODUP)))))
+ ,@(when prev `((when ,prev (setq ,flags (logior ,flags DB_PREV)))))
+ ,@(when prev-nodup `((when ,prev-nodup (setq ,flags (logior ,flags DB_PREV_NODUP)))))
+ ,@(when set `((when ,set (setq ,flags (logior ,flags DB_SET)))))
+ ,@(when set-range `((when ,set-range (setq ,flags (logior ,flags DB_SET_RANGE)))))
+ ,@(when after `((when ,after (setq ,flags (logior ,flags DB_AFTER)))))
+ ,@(when before `((when ,before (setq ,flags (logior ,flags DB_BEFORE)))))
+ ,@(when keyfirst `((when ,keyfirst (setq ,flags (logior ,flags DB_KEYFIRST)))))
+ ,@(when keylast `((when ,keylast (setq ,flags (logior ,flags DB_KEYLAST)))))
+ ,@(when no-dup-data `((when ,no-dup-data (setq ,flags (logior ,flags DB_NODUPDATA)))))
+ ,@(when no-overwrite `((when ,no-overwrite (setq ,flags (logior ,flags DB_NOOVERWRITE)))))
+ ,@(when nosync `((when ,nosync (setq ,flags (logior ,flags DB_NOSYNC)))))
+ ,@(when position `((when ,position (setq ,flags (logior ,flags DB_POSITION)))))
+ ,@(when set-lock-timeout `((when ,set-lock-timeout (setq ,flags (logior ,flags DB_SET_LOCK_TIMEOUT)))))
+ ,@(when set-transaction-timeout `((when ,set-transaction-timeout (setq ,flags (logior ,flags DB_SET_TXN_TIMEOUT)))))
+ ,flags)))
-;; Environment
-
-(def-function ("db_env_cr" %db-env-create)
- ((flags :unsigned-int)
- (errno :int :out))
- :returning :pointer-void)
-
-(defun db-env-create ()
- (multiple-value-bind (env errno)
- (%db-env-create 0)
- (declare (type fixnum errno))
- (if (= errno 0)
- env
- (error 'db-error :errno errno))))
-
-(def-function ("db_env_close" %db-env-close)
- ((dbenvp :pointer-void)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-close (dbenvp flags))
-
-(def-function ("db_env_open" %db-env-open)
- ((dbenvp :pointer-void)
- (home :cstring)
- (flags :unsigned-int)
- (mode :int))
- :returning :int)
-
-(wrap-errno db-env-open (dbenvp home flags mode)
- :flags (joinenv init-cdb init-lock init-log
- init-mpool init-rep init-txn
- recover recover-fatal create
- lockdown private system-mem thread)
- :keys ((mode #o640))
- :cstrings (home))
-
-(def-function ("db_env_dbremove" %db-env-dbremove)
- ((env :pointer-void)
- (txn :pointer-void)
- (file :cstring)
- (database :cstring)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-dbremove (env transaction file database flags)
- :flags (auto-commit)
- :keys ((transaction *current-transaction*)
- (database +NULL-CHAR+))
- :cstrings (file database)
- :transaction transaction)
-
-(def-function ("db_env_dbrename" %db-env-dbrename)
- ((env :pointer-void)
- (txn :pointer-void)
- (file :cstring)
- (database :cstring)
- (newname :cstring)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-dbrename (env transaction file database newname flags)
- :flags (auto-commit)
- :keys ((transaction *current-transaction*)
- (database +NULL-CHAR+))
- :cstrings (file database newname)
- :transaction transaction)
-
-(def-function ("db_env_remove" %db-env-remove)
- ((env :pointer-void)
- (home :cstring)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-remove (env home flags) :flags (force)
- :cstrings (home))
-
-(def-function ("db_env_set_flags" %db-env-set-flags)
- ((env :pointer-void)
- (flags :unsigned-int)
- (onoff :int))
- :returning :int)
-
-(wrap-errno db-env-set-flags (env flags onoff)
- :flags (auto-commit nommap txn-nosync))
-
-(def-function ("db_env_get_flags" %db-env-get-flags)
- ((env :pointer-void)
- (flags :unsigned-int :out))
- :returning :int)
-
-(wrap-errno db-env-get-flags (env) :outs 2)
-
-
-;; Database
-
-(def-function ("db_cr" %db-create)
- ((dbenv :pointer-void)
- (flags :unsigned-int)
- (errno :int :out))
- :returning :pointer-void)
-
-(defun db-create (&optional (dbenv +NULL-VOID+))
- (multiple-value-bind (db errno)
- (%db-create dbenv 0)
- (declare (type fixnum errno))
- (if (= errno 0)
- db
- (error 'db-error :errno errno))))
-
-(def-function ("db_close" %db-close)
- ((db :pointer-void)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-close (db flags))
-
-(def-function ("db_open" %db-open)
- ((db :pointer-void)
- (txn :pointer-void)
- (file :cstring)
- (database :cstring)
- (type DBTYPE)
- (flags :unsigned-int)
- (mode :int))
- :returning :int)
-
-(wrap-errno db-open (db transaction file database type flags mode)
- :flags (auto-commit create dirty-read excl nommap
- rdonly thread truncate)
- :keys ((transaction *current-transaction*)
- (file +NULL-CHAR+)
- (database +NULL-CHAR+)
- (type DB-UNKNOWN)
- (mode #o640))
- :cstrings (file database)
- :transaction transaction)
-
-(def-function ("db_remove" %db-remove)
- ((db :pointer-void)
- (file :cstring)
- (database :cstring)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-remove (db file database flags)
- :keys ((database +NULL-CHAR+))
- :cstrings (file database))
-
-(def-function ("db_rename" %db-rename)
- ((db :pointer-void)
- (file :cstring)
- (database :cstring)
- (newname :cstring)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-rename (db file database newname flags)
- :keys ((database +NULL-CHAR+))
- :cstrings (file database newname))
-
-(def-function ("db_sync" %db-sync)
- ((db :pointer-void)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-sync (db flags))
-
-(def-function ("db_truncate" %db-truncate)
- ((db :pointer-void)
- (txn :pointer-void)
- (count :unsigned-int :out)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-truncate (db transaction flags) :flags (auto-commit)
- :keys ((transaction *current-transaction*)) :outs 2
- :transaction transaction)
-
-;; Accessors
-
-(def-function ("db_get_raw" %db-get-key-buffered)
- ((db :pointer-void)
- (txn :pointer-void)
- (key array-or-pointer-char)
- (key-length :unsigned-int)
- (buffer array-or-pointer-char)
- (buffer-length :unsigned-int)
- (flags :unsigned-int)
- (result-length :unsigned-int :out))
- :returning :int)
-
-(defun db-get-key-buffered (db key-buffer key-length &key
- (transaction *current-transaction*)
- auto-commit get-both dirty-read)
- (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void db transaction)
- (type array-or-pointer-char key-buffer)
- (type fixnum key-length)
- (type boolean auto-commit get-both dirty-read))
- (loop
- do
- (multiple-value-bind (errno result-length)
- (%db-get-key-buffered db transaction key-buffer key-length
- *get-buffer* *get-buffer-length*
- (flags :auto-commit auto-commit
- :get-both get-both
- :dirty-read dirty-read))
- (declare (type fixnum result-length errno))
- (if (<= result-length *get-buffer-length*)
- (cond
- ((= errno 0)
- (return-from db-get-key-buffered
- (the (values array-or-pointer-char fixnum)
- (values *get-buffer* result-length))))
- ((or (= errno DB_NOTFOUND) (= errno DB_KEYEMPTY))
- (return-from db-get-key-buffered
- (the (values null fixnum) (values nil 0))))
- ((or (= errno DB_LOCK_DEADLOCK) (= errno DB_LOCK_NOTGRANTED))
- (throw transaction transaction))
- (t (error 'db-error :errno errno)))
- (resize-get-buffer result-length)))))
-
-(def-function ("db_get_raw" %db-get-buffered)
- ((db :pointer-void)
- (txn :pointer-void)
- (key :cstring)
- (key-length :unsigned-int)
- (buffer array-or-pointer-char)
- (buffer-length :unsigned-int)
- (flags :unsigned-int)
- (result-length :unsigned-int :out))
- :returning :int)
-
-(defun db-get-buffered (db key &key
- (key-length (length key))
- (transaction *current-transaction*)
- auto-commit get-both dirty-read)
- (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void db transaction)
- (type string key)
- (type fixnum key-length)
- (type boolean auto-commit get-both dirty-read))
- (with-cstring (k key)
- (loop
- do
- (multiple-value-bind (errno result-length)
- (%db-get-buffered db transaction k key-length
- *get-buffer* *get-buffer-length*
- (flags :auto-commit auto-commit
- :get-both get-both
- :dirty-read dirty-read))
- (declare (type fixnum result-length errno))
- (if (<= result-length *get-buffer-length*)
- (cond
- ((= errno 0)
- (return-from db-get-buffered
- (the (values array-or-pointer-char fixnum)
- (values *get-buffer* result-length))))
- ((or (= errno DB_NOTFOUND) (= errno DB_KEYEMPTY))
- (return-from db-get-buffered
- (the (values null fixnum) (values nil 0))))
- ((or (= errno DB_LOCK_DEADLOCK) (= errno DB_LOCK_NOTGRANTED))
- (throw transaction transaction))
- (t (error 'db-error :errno errno)))
- (resize-get-buffer result-length))))))
-
-(defun db-get (db key &key (key-length (length key))
- (transaction *current-transaction*)
- auto-commit get-both dirty-read)
- (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void db transaction)
- (type string key)
- (type fixnum key-length)
- (type boolean auto-commit get-both dirty-read))
- (with-cstring (k key)
- (loop
- do
- (multiple-value-bind (errno result-length)
- (%db-get-buffered db transaction k key-length
- *get-buffer* *get-buffer-length*
- (flags :auto-commit auto-commit
- :get-both get-both
- :dirty-read dirty-read))
- (declare (type fixnum result-length errno))
- (if (<= result-length *get-buffer-length*)
- (cond
- ((= errno 0)
- (return-from db-get
- (convert-from-foreign-string *get-buffer*
- :length result-length
- :null-terminated-p nil)))
- ((or (= errno DB_NOTFOUND) (= errno DB_KEYEMPTY))
- (return-from db-get nil))
- ((or (= errno DB_LOCK_DEADLOCK) (= errno DB_LOCK_NOTGRANTED))
- (throw transaction transaction))
- (t (error 'db-error :errno errno)))
- (resize-get-buffer result-length))))))
-
-(def-function ("db_put_raw" %db-put-buffered)
- ((db :pointer-void)
- (txn :pointer-void)
- (key array-or-pointer-char)
- (key-length :unsigned-int)
- (datum array-or-pointer-char)
- (datum-length :unsigned-int)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-put-buffered (db transaction key key-length
- datum datum-length flags)
- :flags (auto-commit)
- :keys ((transaction *current-transaction*))
- :declarations (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void db transaction)
- (type array-or-pointer-char key datum)
- (type fixnum key-length datum-length)
- (type boolean auto-commit))
- :transaction transaction)
-
-(def-function ("db_put_raw" %db-put)
- ((db :pointer-void)
- (txn :pointer-void)
- (key :cstring)
- (key-length :unsigned-int)
- (datum :cstring)
- (datum-length :unsigned-int)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-put (db transaction key key-length datum datum-length flags)
- :flags (auto-commit)
- :keys ((key-length (length key))
- (datum-length (length datum))
- (transaction *current-transaction*))
- :cstrings (key datum)
- :declarations (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void db transaction)
- (type string key datum)
- (type fixnum key-length datum-length)
- (type boolean auto-commit))
- :transaction transaction)
-
-(def-function ("db_del" %db-delete-buffered)
- ((db :pointer-void)
- (txn :pointer-void)
- (key array-or-pointer-char)
- (key-length :unsigned-int)
- (flags :unsigned-int))
- :returning :int)
-
-(defun db-delete-buffered (db key key-length &key auto-commit
- (transaction *current-transaction*))
- (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void db transaction) (type array-or-pointer-char key)
- (type fixnum key-length) (type boolean auto-commit))
- (let ((errno (%db-delete-buffered db transaction
- key key-length
- (flags :auto-commit auto-commit))))
- (declare (type fixnum errno))
- (cond ((= errno 0) t)
- ((or (= errno DB_NOTFOUND)
- (= errno DB_KEYEMPTY))
- nil)
- ((or (= errno DB_LOCK_DEADLOCK)
- (= errno DB_LOCK_NOTGRANTED))
- (throw transaction transaction))
- (t (error 'db-error :errno errno)))))
-
-(def-function ("db_del" %db-delete)
- ((db :pointer-void)
- (txn :pointer-void)
- (key :cstring)
- (key-length :unsigned-int)
- (flags :unsigned-int))
- :returning :int)
-
-(defun db-delete (db key &key auto-commit (key-length (length key))
- (transaction *current-transaction*))
- (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void db transaction) (type string key)
- (type fixnum key-length) (type boolean auto-commit))
- (with-cstrings ((key key))
- (let ((errno
- (%db-delete db transaction key
- key-length (flags :auto-commit auto-commit))))
- (declare (type fixnum errno))
- (cond ((= errno 0) nil)
- ((or (= errno DB_NOTFOUND)
- (= errno DB_KEYEMPTY))
- nil)
- ((or (= errno DB_LOCK_DEADLOCK)
- (= errno DB_LOCK_NOTGRANTED))
- (throw transaction transaction))
- (t (error 'db-error :errno errno))))))
-
-;; Transactions
-
-(def-function ("db_txn_begin" %db-txn-begin)
- ((env :pointer-void)
- (parent :pointer-void)
- (flags :unsigned-int)
- (errno (* :int)))
- :returning :pointer-void)
-
-(defun db-transaction-begin (env &key (parent *current-transaction*)
- dirty-read txn-nosync txn-nowait
- txn-sync)
- (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void env parent)
- (type boolean dirty-read txn-nosync txn-nowait
- txn-sync)
- (type pointer-int *errno-buffer*))
- (let* ((txn
- (%db-txn-begin env parent
- (flags :dirty-read dirty-read
- :txn-nosync txn-nosync
- :txn-nowait txn-nowait
- :txn-sync txn-sync)
- *errno-buffer*))
- (errno (deref-array *errno-buffer* '(:array :int) 0)))
- (declare (type pointer-void txn)
- (type fixnum errno))
- (if (= errno 0)
- txn
- (error 'db-error :errno errno))))
-
-(def-function ("db_txn_abort" %db-txn-abort)
- ((txn :pointer-void))
- :returning :int)
-
-(wrap-errno (db-transaction-abort %db-txn-abort) (transaction)
- :keys ((transaction *current-transaction*))
- :declarations (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void transaction)))
-
-(def-function ("db_txn_commit" %db-txn-commit)
- ((txn :pointer-void)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno (db-transaction-commit %db-txn-commit) (transaction flags)
- :keys ((transaction *current-transaction*))
- :flags (txn-nosync txn-sync)
- :declarations (declare (optimize (speed 3) (safety 0) (space 0))
- (type pointer-void transaction)
- (type boolean txn-nosync txn-sync)))
-
-(defmacro with-transaction ((&key transaction environment
- (parent '*current-transaction*)
- (retries 100)
- dirty-read txn-nosync
- txn-nowait txn-sync)
- &body body)
- (let ((txn (if transaction transaction (gensym)))
- (count (gensym))
- (result (gensym))
- (success (gensym)))
- `(loop for ,count fixnum from 1 to ,retries
- for ,txn of-type pointer-void =
- (db-transaction-begin ,environment
- :parent ,parent
- :dirty-read ,dirty-read
- :txn-nosync ,txn-nosync
- :txn-nowait ,txn-nowait
- :txn-sync ,txn-sync)
- for ,success of-type boolean = nil
- for ,result =
- (let ((*current-transaction* ,txn))
- (catch ,txn
- (unwind-protect
- (prog1 (progn ,@body)
- (setq ,success t)
- (db-transaction-commit :transaction ,txn
- :txn-nosync ,txn-nosync
- :txn-sync ,txn-sync))
- (unless ,success
- (db-transaction-abort :transaction ,txn)))))
- do
- (unless (and (eq ,result ,txn) (not ,success))
- (return ,result))
- finally (error "Too many retries"))))
-
-;; this is code for a non-consing with-transaction. which
-;; doesn't work in the (globally t) case (e.g. setting
-;; *current-transaction*.)
-
-; #+cmu
-; `(alien:with-alien ((,txn (* t)
-; (%db-txn-begin
-; ,environment ,parent
-; (flags :dirty-read ,dirty-read
-; :txn-nosync ,txn-nosync
-; :txn-nowait ,txn-nowait
-; :txn-sync ,txn-sync)
-; *errno-buffer*)))
-; (let ((,success nil)
-; ,@(if globally `((*current-transaction* ,txn)) (values)))
-; (declare (type pointer-void *current-transaction*)
-; (dynamic-extent *current-transaction*))
-; (unwind-protect
-; (prog1 (progn ,@body)
-; (setq ,success t)
-; (%db-txn-commit ,txn
-; (flags :txn-nosync ,txn-nosync
-; :txn-sync ,txn-sync)))
-; (unless ,success (%db-txn-abort ,txn)))))))
-
-
-;; Locks and timeouts
-
-
-(def-enum DB-LOCKOP ((:DUMP 0) :GET :GET-TIMEOUT :INHERIT
- :PUT :PUT-ALL :PUT-OBJ :PUT-READ
- :TIMEOUT :TRADE :UPGRADE-WRITE))
-
-(def-enum DB-LOCKMODE ((:NG 0) :READ :WRITE :WAIT
- :IWRITE :IREAD :IWR :DIRTY :WWRITE))
-
-(def-struct DB-LOCK
- (off :unsigned-int)
- (ndx :unsigned-int)
- (gen :unsigned-int)
- (mode DB-LOCKMODE))
-
-#+openmcl
-(ccl:def-foreign-type DB-LOCK (:struct DB-LOCK))
-
-(def-struct DB-LOCKREQ
- (op DB-LOCKOP)
- (mode DB-LOCKMODE)
- (timeout :unsigned-int)
- (obj (:array :char))
- (lock (* DB-LOCK)))
-
-#+openmcl
-(ccl:def-foreign-type DB-LOCKREQ (:struct DB-LOCKREQ))
-
-(def-function ("db_txn_id" %db-transaction-id)
- ((transaction :pointer-void))
- :returning :unsigned-int)
-
-(defun db-transaction-id (&optional (transaction *current-transaction*))
- (%db-transaction-id transaction))
-
-(def-function ("db_env_lock_id" %db-env-lock-id)
- ((env :pointer-void)
- (id :unsigned-int :out))
- :returning :int)
-
-(wrap-errno db-env-lock-id (env) :outs 2)
-
-
-(def-function ("db_env_lock_id_free" %db-env-lock-id-free)
- ((env :pointer-void)
- (id :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-lock-id-free (env id))
-
-(def-function ("db_env_lock_get" %db-env-lock-get)
- ((env :pointer-void)
- (locker :unsigned-int)
- (flags :unsigned-int)
- (object array-or-pointer-char)
- (object-length :unsigned-int)
- (lock-mode DB-LOCKMODE)
- (lock (* DB-LOCK)))
- :returning :int)
-
-(wrap-errno db-env-lock-get (env locker flags object object-length
- lock-mode lock)
- :flags (lock-nowait))
-
-(def-function ("db_env_lock_put" %db-env-lock-put)
- ((env :pointer-void)
- (lock (* DB-LOCK)))
- :returning :int)
-
-(wrap-errno db-env-lock-put (env lock))
-
-(defmacro with-lock ((env locker object object-length
- &key (lock-mode DB-LOCKMODE#WRITE)
- lock-nowait)
- &body body)
- (let ((lock (gensym))
- (locked (gensym)))
- `(with-foreign-object (,lock 'DB-LOCK)
- (let ((,locked nil))
- (unwind-protect
- (progn
- (db-env-lock-get ,env ,locker ,object ,object-length ,lock-mode
- ,lock :lock-nowait ,lock-nowait)
- (setq ,locked T)
- ,@body)
- (when ,locked (db-env-lock-put ,env ,lock)))))))
-
-(def-function ("db_env_lock_vec" %db-env-lock-vec)
- ((env :pointer-void)
- (locker :unsigned-int)
- (flags :unsigned-int)
- (list (:array DB-LOCKREQ))
- (nlist :int)
- (elistp (* (* DB-LOCKREQ))))
- :returning :int)
-
-(def-function ("db_env_set_timeout" %db-env-set-timeout)
- ((env :pointer-void)
- (timeout :unsigned-int)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-set-timeout (env timeout flags)
- :flags (set-lock-timeout set-transaction-timeout))
-
-(def-function ("db_env_get_timeout" %db-env-get-timeout)
- ((env :pointer-void)
- (timeout :unsigned-int :out)
- (flags :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-get-timeout (env flags) :outs 2
- :flags (set-lock-timeout set-transaction-timeout))
-
-(defconstant DB_LOCK_DEFAULT 1)
-(defconstant DB_LOCK_EXPIRE 2)
-(defconstant DB_LOCK_MAXLOCKS 3)
-(defconstant DB_LOCK_MINLOCKS 4)
-(defconstant DB_LOCK_MINWRITE 5)
-(defconstant DB_LOCK_OLDEST 6)
-(defconstant DB_LOCK_RANDOM 7)
-(defconstant DB_LOCK_YOUNGEST 8)
-
-(def-function ("db_env_set_lk_detect" %db-env-set-lock-detect)
- ((env :pointer-void)
- (detect :unsigned-int))
- :returning :int)
-
-(wrap-errno db-env-set-lock-detect (env detect))
-
-(def-function ("db_env_get_lk_detect" %db-env-get-lock-detect)
- ((env :pointer-void)
- (detect :unsigned-int :out))
- :returning :int)
-
-(wrap-errno db-env-get-lock-detect (env) :outs 2)
-
-(def-function ("db_env_lock_detect" %db-env-lock-detect)
- ((env :pointer-void)
- (flags :unsigned-int)
- (atype :unsigned-int)
- (aborted :int :out))
- :returning :int)
-
-(wrap-errno db-env-lock-detect (env flags atype) :outs 2)
-
-;; Poor man's counters
-
-(def-function ("next_counter" %next-counter)
- ((env :pointer-void)
- (db :pointer-void)
- (parent :pointer-void)
- (key array-or-pointer-char)
- (key-length :unsigned-int)
- (lockid array-or-pointer-char)
- (lockid-length :unsigned-int))
- :returning :int)
-(defun next-counter (env db parent key key-length lockid lockid-length)
- (let ((ret (%next-counter env db parent key key-length lockid lockid-length)))
- (if (< ret 0)
- (error 'db-error :errno ret)
- ret)))
-
-;; Misc
-
-(defun flags (&key
- auto-commit
- joinenv
- init-cdb
- init-lock
- init-log
- init-mpool
- init-rep
- init-txn
- recover
- recover-fatal
- lockdown
- private
- system-mem
- thread
- force
- get-both
- dirty-read
- create
- excl
- nommap
- rdonly
- truncate
- txn-nosync
- txn-nowait
- txn-sync
- set-lock-timeout
- set-transaction-timeout
- lock-nowait)
- (let ((flags 0))
- (declare (optimize (speed 3) (safety 0) (space 0))
- (type (unsigned-byte 32) flags)
- (type boolean auto-commit joinenv init-cdb init-lock
- init-log init-mpool init-rep init-txn
- recover recover-fatal lockdown private
- system-mem thread force get-both
- dirty-read create excl nommap rdonly
- truncate txn-nosync txn-nowait
- set-lock-timeout set-transaction-timeout))
- (when auto-commit (setq flags (logior flags DB_AUTO_COMMIT)))
- (when joinenv (setq flags (logior flags DB_JOINENV)))
- (when init-cdb (setq flags (logior flags DB_INIT_CDB)))
- (when init-lock (setq flags (logior flags DB_INIT_LOCK)))
- (when init-log (setq flags (logior flags DB_INIT_LOG)))
- (when init-mpool (setq flags (logior flags DB_INIT_MPOOL)))
- (when init-rep (setq flags (logior flags DB_INIT_REP)))
- (when init-txn (setq flags (logior flags DB_INIT_TXN)))
- (when recover (setq flags (logior flags DB_RECOVER)))
- (when recover-fatal (setq flags (logior flags DB_RECOVER_FATAL)))
- (when lockdown (setq flags (logior flags DB_LOCKDOWN)))
- (when private (setq flags (logior flags DB_PRIVATE)))
- (when system-mem (setq flags (logior flags DB_SYSTEM_MEM)))
- (when thread (setq flags (logior flags DB_THREAD)))
- (when force (setq flags (logior flags DB_FORCE)))
- (when get-both (setq flags (logior flags DB_GET_BOTH)))
- (when dirty-read (setq flags (logior flags DB_DIRTY_READ)))
- (when create (setq flags (logior flags DB_CREATE)))
- (when excl (setq flags (logior flags DB_EXCL)))
- (when nommap (setq flags (logior flags DB_NOMMAP)))
- (when rdonly (setq flags (logior flags DB_RDONLY)))
- (when truncate (setq flags (logior flags DB_TRUNCATE)))
- (when txn-nosync (setq flags (logior flags DB_TXN_NOSYNC)))
- (when txn-nowait (setq flags (logior flags DB_TXN_NOWAIT)))
- (when txn-sync (setq flags (logior flags DB_TXN_SYNC)))
- (when set-lock-timeout (setq flags (logior flags DB_SET_LOCK_TIMEOUT)))
- (when set-transaction-timeout (setq flags (logior flags DB_SET_TXN_TIMEOUT)))
- (when lock-nowait (setq flags (logior flags DB_LOCK_NOWAIT)))
- flags))
-
-;; Errors
-
-(def-function ("db_strerr" %db-strerror)
- ((error :int))
- :returning :cstring)
-
-(defun db-strerror (errno)
- (convert-from-cstring (%db-strerror errno)))
-
-(define-condition db-error (error)
- ((errno :type fixnum :initarg :errno :reader db-error-errno))
- (:report
- (lambda (condition stream)
- (declare (type db-error condition) (type stream stream))
- (format stream "Berkeley DB error: ~A"
- (db-strerror (db-error-errno condition))))))