Changeset 3698

Show
Ignore:
Timestamp:
07/30/08 15:44:57 (4 months ago)
Author:
hans
Message:

back out changeset 3682, too - this needs more thought

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/bknr/datastore/src/data/object-tests.lisp

    r3694 r3698  
    4646    (close-store))) 
    4747 
    48 (defvar *tests* (make-hash-table)) 
     48(defmacro define-datastore-test (name &rest body) 
     49  `(make-instance 'datastore-test-class 
     50    :unit :datastore 
     51    :name ,name 
     52    :body (lambda () 
     53            ,@body))) 
    4954 
    50 (defmacro define-datastore-test (name &rest body) 
    51   `(setf (gethash ,name *tests*) 
    52          (make-instance 'datastore-test-class 
    53                         :unit :datastore 
    54                         :name ,name 
    55                         :body (lambda () 
    56                                 ,@body)))) 
    57  
    58 (define-datastore-test :store-setup 
     55(define-datastore-test "Datastore setup" 
    5956    (test-assert *test-datastore*)) 
    6057 
    61 (define-datastore-test :create-object 
     58(define-datastore-test "Create object" 
    6259    (let ((obj (make-object 'store-object))) 
    6360      (test-assert obj) 
    6461      (test-equal (list obj) (all-store-objects)))) 
    6562 
    66 (define-datastore-test :create-multiple-objects 
     63(define-datastore-test "Create multiple objects" 
    6764    (let ((o1 (make-object 'store-object)) 
    6865          (o2 (make-object 'store-object))) 
     
    7269      (test-assert (subsetp (list o1 o2) (all-store-objects))))) 
    7370 
    74 (define-datastore-test :delete-multiple-objects 
     71(define-datastore-test "Delete multiple objects" 
    7572    (let ((o1 (make-object 'store-object)) 
    7673          (o2 (make-object 'store-object))) 
     
    8481      (test-equal (all-store-objects) nil))) 
    8582 
    86 (define-datastore-test :restore 
     83(define-datastore-test "Restore" 
    8784    (make-object 'store-object) 
    8885  (restore) 
    8986  (test-equal (length (all-store-objects)) 1)) 
    9087 
    91 (define-datastore-test :snapshot-and-restore 
     88(define-datastore-test "Snapshot and Restore" 
    9289    (make-object 'store-object) 
    9390  (snapshot) 
     
    9592  (test-equal (length (all-store-objects)) 1)) 
    9693 
    97 (define-datastore-test :restore-multiple-objects 
     94(define-datastore-test "Restore multiple objects" 
    9895    (dotimes (i 10) (make-object 'store-object)) 
    9996  (restore) 
    10097  (test-equal (length (all-store-objects)) 10)) 
    10198 
    102 (define-datastore-test :snapshot-restore-multiple-objects 
     99(define-datastore-test "Snapshot and Restore multiple objects" 
    103100    (dotimes (i 10) (make-object 'store-object)) 
    104101  (snapshot) 
     
    108105(defconstant +stress-size+ 10000) 
    109106 
    110 (define-datastore-test :stress-test 
     107(define-datastore-test "Stress test object creation" 
    111108    (format t "Creating ~a objects~%" +stress-size+) 
    112109  (time (bknr.datastore::without-sync () 
     
    125122  ()) 
    126123 
    127 (define-datastore-test :serialize-circular-in-anon-txn 
     124(define-datastore-test "Serialize circular dependency in anonymous txn" 
    128125  (let ((parent (make-object 'parent))) 
    129126    (with-transaction (:circular) 
     
    132129  (test-equal (find-class 'child) 
    133130              (class-of (parent-child (first (class-instances 'parent)))))) 
    134  
    135 (define-datastore-test :delete-object-in-anon-txn 
    136   (let (object) 
    137     (with-transaction (:make) 
    138       (setf object (make-object 'child))) 
    139     (with-transaction (:delete) 
    140       (delete-object object)) 
    141     (restore) 
    142     (test-assert (object-destroyed-p object)))) 
  • trunk/bknr/datastore/src/data/object.lisp

    r3694 r3698  
    9797(defmethod (setf slot-value-using-class) :after (newval (class persistent-class) object slotd) 
    9898  (when (in-anonymous-transaction-p) 
    99     (encode (make-instance 'transaction 
    100                            :timestamp (get-universal-time) 
    101                           :function-symbol 'tx-change-slot-values 
    102                           :args (list object (slot-definition-name slotd) newval)) 
    103             (anonymous-transaction-log-buffer *current-transaction*)))) 
     99    (push (make-instance 'transaction 
     100                         :timestamp (get-universal-time) 
     101                        :function-symbol 'tx-change-slot-values 
     102                        :args (list object (slot-definition-name slotd) newval)) 
     103         (anonymous-transaction-transactions *current-transaction*)))) 
    104104 
    105105(defmethod direct-slot-definition-class ((class persistent-class) &key &allow-other-keys) 
     
    196196      (prog1 
    197197          (call-next-method) 
    198         (encode (make-instance 'transaction 
    199                                :function-symbol 'make-instance 
    200                                :timestamp (get-universal-time) 
    201                                :args (cons (class-name (class-of object)) 
    202                                           (loop for slotd in (class-slots (class-of object)) 
    203                                               for slot-name = (slot-definition-name slotd) 
    204                                               for slot-initarg = (first (slot-definition-initargs slotd)) 
    205                                               when (and slot-initarg 
    206                                                         (slot-boundp object slot-name)) 
    207                                               appending (list slot-initarg (slot-value object slot-name))))) 
    208                 (anonymous-transaction-log-buffer *current-transaction*))) 
     198        (push (make-instance 'transaction 
     199                            :function-symbol 'make-instance 
     200                            :timestamp (get-universal-time) 
     201                            :args (cons (class-name (class-of object)) 
     202                                        (loop for slotd in (class-slots (class-of object)) 
     203                                           for slot-name = (slot-definition-name slotd) 
     204                                           for slot-initarg = (first (slot-definition-initargs slotd)) 
     205                                           when (and slot-initarg 
     206                                                     (slot-boundp object slot-name)) 
     207                                           appending (list slot-initarg (slot-value object slot-name))))) 
     208             (anonymous-transaction-transactions *current-transaction*))) 
    209209      (call-next-method))) 
    210210 
     
    662662 
    663663(defun delete-object (object) 
    664   (if (and (in-transaction-p) 
    665            (not (in-anonymous-transaction-p))) 
     664  (if (in-transaction-p) 
    666665      (destroy-object object) 
    667666      (execute (make-instance 'transaction :function-symbol 'tx-delete-object 
  • trunk/bknr/datastore/src/data/txn.lisp

    r3682 r3698  
    1111  () 
    1212  (:documentation 
    13    "Signaled when an operation on persistent slots is executed outside 
    14    a transaction context")) 
     13   "Thrown when an operation on persistent slots is executed outside a transaction context")) 
    1514 
    1615(define-condition store-not-open (error) 
    1716  () 
    1817  (:documentation 
    19    "Signaled when a transaction is executed on a store that is not 
    20    opened")) 
    21  
    22 (define-condition store-already-open (error) 
    23   () 
    24   (:documentation 
    25    "Signaled when an attempt is made to open a store with another 
    26    store being open")) 
    27  
    28 (define-condition invalid-store-random-state (error) 
    29   () 
    30   (:documentation 
    31    "Signaled when the on-disk store random state cannot be read, 
    32    typically because it has been written with another Lisp")) 
    33  
    34 (define-condition unsupported-lambda-list-option (error) 
    35   ((option :initarg :option :reader option)) 
    36   (:documentation 
    37    "Signaled when DEFTRANSACTION is used with an unsupported option in 
    38    its lambda list")) 
    39  
    40 (define-condition default-arguments-unsupported (error) 
    41   ((tx-name :initarg :tx-name :reader tx-name) 
    42    (argument :initarg :argument :reader argument)) 
    43   (:report (lambda (c stream) 
    44              (format stream "argument ~A defaulted in DEFTRANSACTION ~S" 
    45                      (argument c) (tx-name c)))) 
    46   (:documentation 
    47    "Signaled when an argument in a DEFTRANSACTION definition has a 
    48    default declaration")) 
    49  
    50 (define-condition undefined-transaction (error) 
    51   ((tx-name :initarg :tx-name :reader tx-name)) 
    52   (:report (lambda (c stream) 
    53              (format stream "undefined transaction ~A in transaction log, please ensure that all the necessary code is loaded." 
    54                      (tx-name c)))) 
    55   (:documentation 
    56    "Signaled when a named transaction is loaded from the transaction 
    57    log and no matching function definition could be found")) 
    58  
    59 (define-condition invalid-transaction-nesting (error) 
    60   () 
    61   (:documentation 
    62    "Signaled when WITH-TRANSACTION forms are nested.")) 
    63  
    64 (define-condition anonymous-transaction-in-named-transaction (error) 
    65   () 
    66   (:documentation 
    67    "Signaled when an anonymous transaction is started from within a named transaction.")) 
    68  
    69 (define-condition no-subsystems (error) 
    70   () 
    71   (:documentation 
    72    "Signaled when an attempt is made to snapshot a store without subsystems")) 
     18   "Thrown when a transaction is executed on a store that is not opened")) 
    7319 
    7420;;; store 
     
    12975        (when (and (boundp '*store*) 
    13076                   *store*) 
    131           (error 'store-already-open)) 
     77          (error "A store is already opened.")) 
    13278      (close-store () 
    13379        :report "Close the opened store." 
     
    208154                    (error (e) 
    209155                      (declare (ignore e)) 
    210                       (error 'invalid-store-random-state)))) 
     156                      (error "Invalid store random state")))) 
    211157          (initialize-store-random-state () 
    212158            :report "Initialize the random state of the store.  Use 
     
    300246  (if (in-transaction-p) 
    301247      *current-transaction* 
    302       (error 'not-in-transaction))) 
     248      (error "store-current-transaction called outside of a transaction"))) 
    303249 
    304250;;; All transactions are executed by an 'executor', which is the store 
     
    317263(defmethod execute-transaction :before (executor transaction) 
    318264  (unless (store-open-p) 
    319     (error 'store-not-open))) 
     265    (error (make-condition 'store-not-open)))) 
    320266 
    321267(defmethod execute-transaction ((executor transaction) transaction) 
     
    372318           (&rest (setf args (cdr args))) ; skip argument, too 
    373319           (&key (setf in-keywords-p t)) 
    374            (otherwise (error 'unsupported-lambda-list-option :option arg)))) 
     320           (otherwise (error "unsupported lambda list option ~A in DEFTRANSACTION" arg)))) 
    375321        (t 
    376322         (when in-keywords-p 
     
    390336    (dolist (arg args) 
    391337      (when (listp arg) 
    392         (error 'default-arguments-unsupported :tx-name name :argument (car arg)))) 
     338        (error "can't have argument defaults in transaction declaration for transaction ~A, please implement a wrapper" name))) 
    393339    (let ((tx-name (intern (format nil "TX-~A" name) 
    394340                           (symbol-package name)))) 
     
    463409    (let ((*current-transaction* transaction)) 
    464410      (apply (or (symbol-function (transaction-function-symbol transaction)) 
    465                  (error 'undefined-transaction 
    466                         :tx-name (transaction-function-symbol transaction))) 
     411                 (error "Undefined transaction function ~A, please ensure that all the necessary code is loaded." 
     412                        (transaction-function-symbol transaction))) 
    467413             (transaction-args transaction))))) 
    468414 
     
    491437  `(with-store-guard () 
    492438     (when (in-transaction-p) 
    493        (error 'invalid-transaction-nesting)) 
     439       (error "can't open nested with-transaction-log blocks")) 
    494440     (with-store-state (:transaction) 
    495441       (prog1 
     
    527473;;; with-transaction macro. 
    528474 
    529 ;;; An anonymous transaction has a label which is stored in the 
    530 ;;; transaction log in order to make the source code location where 
     475;;; An anonymous transaction has an optional label which is stored in 
     476;;; the transaction log in order to make the source code location where 
    531477;;; the actual transaction code lives identifieable. 
    532478 
    533479(defclass anonymous-transaction (transaction) 
    534   ((label :initarg :label 
    535           :accessor anonymous-transaction-label 
    536           :initform (error "missing label in anonymous transaction definition")) 
    537    (log-buffer :initarg :log-buffer 
    538                :accessor anonymous-transaction-log-buffer 
    539                :initform (flex:make-in-memory-output-stream)))) 
     480  ((label :initarg :label :accessor anonymous-transaction-label) 
     481   (transactions :initarg :transactions :accessor anonymous-transaction-transactions)) 
     482  (:default-initargs :transactions nil :label nil)) 
    540483 
    541484(defmethod print-object ((transaction anonymous-transaction) stream) 
    542485  (print-unreadable-object (transaction stream :type t) 
    543     (format stream "~A ~A (~A)
     486    (format stream "~A ~A ~A
    544487            (format-date-time (transaction-timestamp transaction)) 
    545488            (anonymous-transaction-label transaction) 
    546             (class-name (class-of (anonymous-transaction-log-buffer transaction)))))) 
     489            (anonymous-transaction-transactions transaction)))) 
    547490 
    548491(defmethod in-anonymous-transaction-p () 
     
    550493 
    551494(defmethod encode-object ((transaction anonymous-transaction) stream) 
    552   (%write-tag #\N stream) 
    553   (%encode-string (anonymous-transaction-label transaction) stream) 
    554   (let ((subtxns (flex:get-output-stream-sequence (anonymous-transaction-log-buffer transaction)))) 
    555     (%encode-integer (length subtxns) stream) 
    556     (write-sequence subtxns stream))) 
     495  (cond 
     496    ((anonymous-transaction-label transaction) 
     497     (%write-tag #\N stream) 
     498     (%encode-string (anonymous-transaction-label transaction) stream)) 
     499    (t 
     500     (%write-tag #\G stream))) 
     501  (%encode-list (reverse (anonymous-transaction-transactions transaction)) stream)) 
     502 
     503(defmethod decode-object ((tag (eql #\G)) stream) 
     504  (make-instance 'anonymous-transaction 
     505                 :transactions (%decode-list stream))) 
    557506 
    558507(defvar *txn-log-stream* nil 
     
    562511 
    563512(defmethod decode-object ((tag (eql #\N)) stream) 
    564   (let* ((label (%decode-string stream)) 
    565          (length (%decode-integer stream)) 
    566          (buffer (make-array length :element-type '(unsigned-byte 8)))) 
    567     (read-sequence buffer stream) 
    568     (make-instance 'anonymous-transaction 
    569                    :label label 
    570                    :log-buffer (flex:make-in-memory-input-stream buffer)))) 
     513  ;; When decoding an anonymous transaction from the transaction log, 
     514  ;; we only read its name.  The subtransaction are not read here, but 
     515  ;; rather in EXECUTE-UNLOGGED below.  The reason for this is that we 
     516  ;; need to execute the subtransactions while reading them, as we'd 
     517  ;; otherwise not be able to properly deserialize references to 
     518  ;; objects that have been created within this anonymous transaction. 
     519 
     520  ;; Thus, while restoring, the TRANSACTIONS slot of the anonymous 
     521  ;; transaction object is not used. 
     522  (make-instance 'anonymous-transaction 
     523                 :label (%decode-string stream))) 
    571524 
    572525(defmacro with-transaction ((&optional label) &body body) 
     
    574527    `(progn 
    575528       (when (in-transaction-p)  
    576          (error 'anonymous-transaction-in-named-transaction)) 
     529         (error "tried to start anonymous transaction while in a transaction")) 
    577530       (let ((,txn (make-instance 'anonymous-transaction :label ,(if (symbolp label) (symbol-name label) label)))) 
    578531         (with-transaction-log (,txn) 
     
    585538  (assert (eq :restore (store-state *store*)) () 
    586539          "Unexpected store state ~A for EXECUTE-UNLOGGED on an anonymous transaction" (store-state *store*)) 
    587   (let ((stream (anonymous-transaction-log-buffer transaction))) 
    588     (handler-case 
    589         (loop 
    590            (execute-unlogged (decode stream))) 
    591       (end-of-file ())))) 
    592  
    593 (defmethod execute-transaction :before ((executor anonymous-transaction) transaction) 
    594   (encode transaction (anonymous-transaction-log-buffer executor))) 
     540  (let ((subtxns (%decode-integer *txn-log-stream*))) 
     541    (dotimes (i subtxns) 
     542      (execute-unlogged (decode *txn-log-stream*))) 
     543    (when (plusp subtxns) 
     544      ;; In order to maintain the previous on-disk format, we read the last cdr of the list 
     545      (assert (eq nil (decode *txn-log-stream*)))))) 
     546 
     547(defmethod execute-transaction :after ((executor anonymous-transaction) transaction) 
     548  (push transaction (anonymous-transaction-transactions executor))) 
    595549 
    596550;;; Subsystems 
     
    618572(defmethod snapshot-store ((store store)) 
    619573  (unless (store-open-p) 
    620     (error 'store-not-open)) 
     574    (error (make-condition 'store-not-open))) 
    621575  (when (null (store-subsystems store)) 
    622     (error 'no-subsystems)) 
     576    (error "Cannot snapshot store without subsystems...")) 
    623577  (ensure-store-current-directory store) 
    624578  (with-store-state (:read-only store)