clobber

2024-10-12

Library for transaction-oriented data bases.

Upstream URL

github.com/robert-strandh/Clobber

Author

Robert Strandh <[email protected]>

License

FreeBSD, see file LICENSE.text
README

1Explanation

Clobber is an alternative to so-called "object prevalence", and inparticular to cl-prevalence.

Clobber is both simpler, more flexible, and more robust than systems based on object prevalence.

1.1Simplicity

Clobber is simpler because we do not take any snapshots at all. Othersystems typically use a combination of transaction logs and snapshots.Clobber uses only a transaction log which is always read into an emptysystem.

1.2Flexibility

Clobber is more flexible because the system itself does not define theformat of a transaction. Client code can save transactions as Lisplists, as instances of standard-object, or anything else that can beserialized. It is also more flexible because transactions can containany object that can be serialized, including model objects. With thismethod, client code does not need to manipulate "manually createdpointers" such as social security numbers, account numbers, membershipnumbers, etc. whenever it needs to execute a transaction. Instead itcan use the model objects themselves such as people, accounts,automobiles and whatnot.

1.3Robustness

Clobber is more robust because serialization of instances of (subclassesof) standard-object is not accomplished based on slots. Clobber considers slots to beimplementation details. In other object prevalence systems, wheneverthe model evolves, the serialization might no longer be valid. Incontrast, Clobber serializes instances of standard-object as a list ofpairs, each one consisting of an initarg and a value. These pairs canbe handled by client code in any way it sees fit. They can be handledby an :initarg, by initialize-instance, or they can be ignored. Thedownside of the Clobber method is that client code must specify thesepairs in the form of an initarg and the name of an accessor functionto be called to obtain the value used for the initarg. Thisinconvenience is however relatively minor, especially considering theadditional robustness it buys in terms of less sensitivity to changesin the model classes.

1.4Design

At the heart of Clobber is a mechanism for serializing objects thatpreserves object identity, much like the reader macros #= and ##,except that Clobber detects sharing within the entire transaction log,not only within a single transaction. This mechanism is what makes itpossible for client code to put any old object in a transaction, whilemaking sure that sharing is preserved.

1.5Examples

Two examples are included - see files demo1.lisp, demo2.lisp and demo3.lisp

To run the demos -

  (ql:quickload :clobber)
  (in-package :clobber-demo/demo1)
  #+(or)(in-package :clobber-demo/demo2)
  #+(or)(in-package :clobber-demo/demo3)

  (delete-database) ; clean up
  (do-and-see)      ; see what the database file contains after the execution of transactions
#| sample output:
"#2!(NEW-BANK . #3!(#4![BANK] . NIL))
#5!(NEW-BANK . #6!(#7![BANK] . NIL))
#8!(ADD-CUSTOMER . #9!(#10![PERSON :NAME #11!\"Jane\"] . #12!(#4^ . NIL)))
#13!(ADD-CUSTOMER . #14!(#10^ . #15!(#7^ . NIL)))
#16!(ADD-CUSTOMER . #17!(#18![PERSON :NAME #19!\"Bill\"] . #20!(#4^ . NIL)))
#21!(ADD-ACCOUNT . #22!(#23![ACCOUNT :HOLDER #10^] . #24!(#4^ . NIL)))
#25!(ADD-ACCOUNT . #26!(#27![ACCOUNT :HOLDER #10^] . #28!(#7^ . NIL)))
#29!(ADD-ACCOUNT . #30!(#31![ACCOUNT :HOLDER #18^] . #32!(#4^ . NIL)))
#33!(DEPOSIT . #34!(100 . #35!(#23^ . NIL)))
#36!(DEPOSIT . #37!(200 . #38!(#27^ . NIL)))
#39!(DEPOSIT . #40!(300 . #41!(#31^ . NIL)))
#42!(WITHDRAW . #43!(10 . #44!(#31^ . NIL)))
#45!(TRANSFER . #46!(20 . #47!(#27^ . #48!(#23^ . NIL))))
"
|#
  ;; (reload-database-and-see) ; see that *banks* has the data freshly revived from the database file. 
#| sample output:
((:BANK-ID 45 :ACCOUNTS
  ((:ACCOUNT-ID 52 :PARENT-BANK-ID 45 :BALANCE 180 :HOLDER <Jane>)) :CUSTOMERS
  (<Jane>))
 (:BANK-ID 65 :ACCOUNTS
  ((:ACCOUNT-ID 73 :PARENT-BANK-ID 65 :BALANCE 300 :HOLDER <Bill>)
   (:ACCOUNT-ID 89 :PARENT-BANK-ID 65 :BALANCE 120 :HOLDER <Jane>))
  :CUSTOMERS (<Bill> <Jane>)))
|#

1.6License

Clobber is in the public domain in countries where it is possible toplace works in the public domain explicitly. In other countries, wewill distribute Clobber according to a license that lets the user dowhatever he or she pleases with the code.

1.7Contact

Send comments to [email protected]

A manual might be written one day.

2How to use Clobber

  1. If your application objects are instances of (subclasses of) standard-object, use clobber:define-save-info to tell Clobber how to serialize themr.
  2. Determine the data structure your application will use to represent each transaction, and how the application will restore state from each transaction.

    e.g. a transaction could be a list whose car is a function and whose cdr is a list of arguments to the function. State can be restored from such a transaction through (lambda (txn) (apply (first txn) (rest txn)))

  3. When you update your application state -
    1. Use clobber:with-transaction-log to create a transaction log.
    2. Within the body of clobber:with-transaction-log, use clobber:log-transaction to persist the changes to your application state. You may wish to define a helper function or macro for this.

If clobber:with-transaction-log is for some reason unsuitable -

  1. Use clobber:open-transaction-log to create a transaction log, usually stored in a special variable.
  2. Use clobber:log-transaction to persist changes to your application state.
  3. When the transaction log is no longer required, close it using clobber:close-transaction-log.

3Reference

3.0.1define-save-info (type &body save-info) :macro:

3.0.2with-transaction-log ((var file function) &body forms) :macro:

3.0.3open-transaction-log (filename function) :function:

3.0.4log-transaction (transaction transaction-log) :function:

3.0.5close-transaction-log (transaction-log) :function:

3.0.6transaction-log-open-p (transaction-log) :function:

Dependencies (1)

  • closer-mop

Dependents (0)

    • GitHub
    • Quicklisp