Update of /project/elephant/cvsroot/elephant/src/db-bdb In directory clnet:/tmp/cvs-serv22395
Modified Files: bdb-collections.lisp bdb-controller.lisp Log Message:
BUGFIX: add-index to a large, existing btree would fail on the BDB backend due to a transaction that was too large. This transaction has been broken into 1k entry blocks to avoid overflowing the buffer pools.
FEATURE: Added the ability to launch a deadlock detector process for any system that has the :port package loaded. :deadlock-detector is a new keyword option added to open-store that will determine whether to launch or not to launch a detector process.
The location of the deadlock detector is not generic at this time, edit bdb-controller.lisp to change the pathname or default lock policy. Manual launching of the controller can be done by calling start-deadlock-detector.
--- /project/elephant/cvsroot/elephant/src/db-bdb/bdb-collections.lisp 2006/04/26 19:19:12 1.7 +++ /project/elephant/cvsroot/elephant/src/db-bdb/bdb-collections.lisp 2006/06/19 00:47:24 1.8 @@ -103,40 +103,54 @@ ;; absolutely required at present, I think because the copying ;; of objects is calling "make-instance" without an argument. ;; I am sure I can find a way to make this cleaner, somehow. - (if (and (not (null index-name)) - (symbolp index-name) (or (symbolp key-form) (listp key-form))) + (if (and (not (null index-name)) + (symbolp index-name) + (or (symbolp key-form) (listp key-form))) ;; Can it be that this fails? - (let ( - (ht (indices bt)) - (index (build-btree-index sc :primary bt + (let ((ht (indices bt)) + (index (build-btree-index sc + :primary bt :key-form key-form))) (setf (gethash index-name (indices-cache bt)) index) (setf (gethash index-name ht) index) (setf (indices bt) ht) - (when populate - (let ((key-fn (key-fn index))) - (with-buffer-streams (primary-buf secondary-buf) - (with-transaction (:store-controller sc) - (map-btree - #'(lambda (k v) - (multiple-value-bind (index? secondary-key) - (funcall key-fn index k v) - (when index? - (buffer-write-int (oid bt) primary-buf) - (serialize k primary-buf) - (buffer-write-int (oid index) secondary-buf) - (serialize secondary-key secondary-buf) - ;; should silently do nothing if - ;; the key/value already exists - (db-put-buffered - (controller-indices sc) - secondary-buf primary-buf) - (reset-buffer-stream primary-buf) - (reset-buffer-stream secondary-buf)))) - bt))))) + (when populate (populate bt index)) index) - (error "Invalid index initargs!"))) -) + (error "Invalid index initargs!")))) + +(defmethod populate ((bt bdb-indexed-btree) index) + (let ((sc (get-con bt))) + (with-buffer-streams (primary-buf secondary-buf) + (flet ((index (key skey) + (buffer-write-int (oid bt) primary-buf) + (serialize key primary-buf) + (buffer-write-int (oid index) secondary-buf) + (serialize skey secondary-buf) + ;; should silently do nothing if + ;; the key/value already exists + (db-put-buffered + (controller-indices sc) + secondary-buf primary-buf) + (reset-buffer-stream primary-buf) + (reset-buffer-stream secondary-buf))) + (let ((key-fn (key-fn index)) + (last-key nil)) + (loop + (with-transaction (:store-controller sc) + (with-btree-cursor (cursor bt) + (if last-key + (cursor-set cursor last-key) + (cursor-first cursor)) + (loop for i from 0 upto 1000 do + (multiple-value-bind (valid? k v) (cursor-current cursor) + (unless valid? (return-from populate t)) + (multiple-value-bind (index? skey) (funcall key-fn index k v) + (when index? (index k skey)))) + (multiple-value-bind (valid? k v) (cursor-next cursor) + (declare (ignore v)) + (if valid? + (setf last-key k) + (return-from populate t))))))))))))
(defmethod map-indices (fn (bt bdb-indexed-btree)) (maphash fn (indices-cache bt))) --- /project/elephant/cvsroot/elephant/src/db-bdb/bdb-controller.lisp 2006/04/30 01:02:22 1.8 +++ /project/elephant/cvsroot/elephant/src/db-bdb/bdb-controller.lisp 2006/06/19 00:47:24 1.9 @@ -28,7 +28,9 @@ (btrees :type (or null pointer-void) :accessor controller-btrees) (indices :type (or null pointer-void) :accessor controller-indices) (indices-assoc :type (or null pointer-void) - :accessor controller-indices-assoc)) + :accessor controller-indices-assoc) + (deadlock-pid :accessor controller-deadlock-pid :initform nil) + (deadlock-input :accessor controller-deadlock-input :initform nil)) (:documentation "Class of objects responsible for the book-keeping of holding DB handles, the cache, table creation, counters, locks, the root (for garbage collection,) @@ -55,7 +57,8 @@
;; Open/close (defmethod open-controller ((sc bdb-store-controller) &key (recover t) - (recover-fatal nil) (thread t)) + (recover-fatal nil) (thread t) + (deadlock-detect nil)) (let ((env (db-env-create))) ;; thread stuff? (setf (controller-environment sc) env) @@ -112,10 +115,14 @@ (setf (slot-value sc 'class-root) (make-instance 'bdb-btree :from-oid -2 :sc sc))
+ (when deadlock-detect + (start-deadlock-detector sc)) + sc)))
(defmethod close-controller ((sc bdb-store-controller)) (when (slot-value sc 'root) + (stop-deadlock-detector sc) ;; no root (setf (slot-value sc 'class-root) nil) (setf (slot-value sc 'root) nil) @@ -144,6 +151,50 @@ (db-sequence-get-fixnum (controller-oid-seq sc) 1 :transaction +NULL-VOID+ :auto-commit t :txn-nosync t))
+(defparameter *deadlock-type-alist* + '((:oldest . "o") + (:youngest . "y") + (:timeout . "e") + (:most . "m") + (:least . "n"))) + +(defun lookup-deadlock-type (typestring) + (let ((result (assoc typestring *deadlock-type-alist*))) + (unless result + (error "Unrecognized deadlock type '~A'" typestring)) + (cdr result))) + +(eval-when (compile load eval) + (when (find-package :port) + (pushnew :port *features*))) + +(defmethod start-deadlock-detector ((ctrlr bdb-store-controller) &key (type :oldest) (time 0.1) log) + #+port + (multiple-value-bind (str errstr pid) + (port:run-prog (namestring + (make-pathname :directory "/usr/local/BerkeleyDB.4.3/bin/" + :name "db_deadlock")) + :args `("-a" ,(lookup-deadlock-type type) + "-t" ,(format nil "~D" time) + ,@(when log + (list "-L" (format nil "~A" log)))) + :wait nil) + (declare (ignore errstr)) + (setf (controller-deadlock-pid ctrlr) pid) + (setf (controller-deadlock-input ctrlr) str))) + +(defmethod stop-deadlock-detector ((ctrl bdb-store-controller)) + (when (controller-deadlock-pid ctrl) + (shell-kill (controller-deadlock-pid ctrl)) + (setf (controller-deadlock-pid ctrl) nil)) + (when (controller-deadlock-input ctrl) + (close (controller-deadlock-input ctrl)) + (setf (controller-deadlock-input ctrl) nil))) + +(defmethod shell-kill (pid) + #+allegro (sys:reap-os-subprocess :pid pid :wait t) + #+(port (not allegro)) (port:run-prog "kill" :wait t :args (list "-9" (format nil "~A" pid))) + )
;; ;; Persistent slot protocol