Oh yeah, there is something interesting going on in the wrapper, We keep track of the ongoing transactions by mapping the
user-idto a list of transaction contexts (every nested transaction by a user "pushes" a new
Anyway, it's the
repository-persistent-informationthat has the interesting stuff:
(defclass repository-persistent-information () ( (type :initarg :type :initform (error "Required initarg :type omitted.") :reader repository-persistent-information/type :type repository-type) ;; Database parent is the root extent for an extent database, or the master database for a satellite. ;; Root extents or master repositories won't have a parent (parent-repository :initarg :parent-repository :initform nil :reader repository-persistent-information/parent :type (optional relative-pathname)) ;; Satellite repositories is non-nil only for master repositories. (satellite-repositories :initform nil :initarg :satellite-repositories :accessor repository-persistent-information/satellite-repositories) (canonical-class-dictionary :initform (make-instance 'canonical-class-dictionary) :reader repository-persistent-information/canonical-class-dictionary) (cid-master-table :initform (make-instance 'cid-master-table) :reader repository-persistent-information/cid-master-table) (root-mapper :initarg :root-mapper :initform (error "Required initarg :root-mapper omitted.") :reader repository-persistent-information/root-mapper) (cid-mapper :initarg :cid-mapper :initform (error "Required initarg :cid-mapper omitted.") :reader repository-persistent-information/cid-mapper) (local-mapper :initarg :local-mapper :initform (error "Required initarg :local-mapper omitted.") :reader repository-persistent-information/local-mapper) (locally-named-roots :initarg :locally-named-roots :initform (error "Required initarg :locally-named-roots omitted.") :reader repository-persistent-information/locally-named-roots) (anonymous-user :initarg :anonymous-user :initform nil :reader repository-persistent-information/anonymous-user)) (:default-initargs :node-id +object-id-of-root+) ;; force this to always be the root object. (:documentation "Persistent information describing a repositiory, and stored in the repository") (:metaclass persistent-standard-class) (:schema-version 0))
repository-typeis just a keyword:
(defconstant *repository-types* '(:basic :master :satellite :transport :extent :workspace) "Type of repositories. Note that all but :EXTENT types of repositories serve as root extents for databases which have multiple extents, and therefore imply extent.")The
satellite-repositoriesare for juggling multiple "satellite" repositories for holding particular subsets of changes (for, say, geographically distributing the servers for different product groups).
canonical-class-dictionaryis an intern table for objects.
cid-master-tableis (logically) the collection of audit-records. A CID (after change id) is represented as an integer index into the master table.
root-mapperis a mapping table from distributed identifiers to objects.
cid-mapperis a mapping table from the distributed identifier that represents the CID to the integer index of that CID in the master table. It is a subtable of the local mapper.
local-mapperis submapping of the
root-mapping, but a supermapping of the
locally-named-rootsis a hash table for storing the root objects of the repository.
Finally, there is the
anonymous-userslot, which is the user id assigned for bootstrapping.
And all this crap is in support of this procedure:
(defun call-with-repository-transaction (&key repository transaction-type user-id-specifier reason ;; generally, you only want to specify these two meta-cid-set-specifier cid-set-specifier ;; but if you are doing a comparison, ;; specify these as well aux-meta-cid-set-specifier aux-cid-set-specifier receiver) (check-type user-id-specifier (or keyword distributed-identifier)) (check-type transaction-type repository-transaction-type) (check-type reason string) ;; implementation omitted for brevity, ha ha )
Naturally we need to specify the
:transaction-typeis one of
(defconstant *repository-transaction-types* '(:read-only :read-write :read-cons :read-only-compare :read-cons-nonversioned :read-only-nonversioned :read-write-nonversioned))The
:user-id-specifiershould be a
:reasonis a human readable string describing the transaction.
:meta-cid-set-specifieris mumble, mumble... just a sec...
:cid-set-specifieris how you specify which CIDs will form the basis view for the transaction. We allow this to be a procedure that returns a
cid-setobject, and we will call this procedure as we are setting up the transaction and use the
:meta-cid-set-specifierto specify the CIDs to form the versioned view the procedure will see.
:meta-cid-set-specifiercan be the symbol
:latest-metaversion, a timestamp, or a
:latest-metaversionmeans to use all CIDS while resolving the
:cid-set-specifier, a timestamp is useful for rewinding the world, and the main use for using an explicit cid-set is for synchronizing views between master and satellite repositories.
:receiveris invoked within the dynamic extent of a transaction. It is passed a
core-txnobject that contains the metadata associated with the transaction.
The ChangeSafe core components are the repository that holds changes and associated meta-information, and simple versioned CLOS objects. It is only useful as a foundation layer, though.
Next up, another level of abstraction...