Oh yeah, there is something interesting going on in the wrapper, We keep track of the ongoing transactions by mapping the
user-id to a list of transaction contexts (every nested transaction by a user "pushes" a new txn-context). Anyway, it's the
repository-persistent-information that 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))The
repository-type is 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
parent-repository and thesatellite-repositories are for juggling multiple "satellite" repositories for holding particular subsets of changes (for, say, geographically distributing the servers for different product groups).The
canonical-class-dictionary is an intern table for objects.The
cid-master-table is (logically) the collection of audit-records. A CID (after change id) is represented as an integer index into the master table.The
root-mapper is a mapping table from distributed identifiers to objects. The
cid-mapper is 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.The
local-mapper is submapping of the root-mapping, but a supermapping of the cid-mapper.The
locally-named-rootsis a hash table for storing the root objects of the repository.Finally, there is the
anonymous-user slot, 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
:repository, the :transaction-type is 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-specifier should be a distributed-identifier of a core-user instance.The
:reason is a human readable string describing the transaction. The
:meta-cid-set-specifier is mumble, mumble... just a sec...The
:cid-set-specifier is how you specify which CIDs will form the basis view for the transaction. We allow this to be a procedure that returns a cid-set object, and we will call this procedure as we are setting up the transaction and use the :meta-cid-set-specifier to specify the CIDs to form the versioned view the procedure will see. The
:meta-cid-set-specifier can be the symbol :latest-metaversion, a timestamp, or a cid-set. :latest-metaversion means 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.The
:receiver is invoked within the dynamic extent of a transaction. It is passed a core-txn object 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...
No comments:
Post a Comment