How to use snapshots and branches

Use the Yggdrasil xitdb adapter’s callbacks to change or read an object-store subtree. This guide is for applications already using the unpublished xitdb adapter. A released Yggdrasil dependency is not sufficient. See the required checkout and test command.

Change a branch without changing an earlier snapshot

Load these names:

(require '[ol.xitstash :as objects]
         '[yggdrasil.adapters.xitdb :as x]
         '[yggdrasil.protocols :as p])
(import '[io.github.radarroark.xitdb ReadHashMap WriteHashMap]
        '[java.io Closeable])

Create a file, open a historical view and rename the file on a separate branch:

(with-open [^Closeable system   (x/create)
            ^Closeable prepared (objects/prepare (byte-array [1 2 3]))]
  (x/transact! system
    (fn [root]
      (let [store (.putCursor (WriteHashMap. root) "objects")]
        (objects/initialize! store)
        (objects/put! store prepared)
        (objects/create! store [{:name "original.bin"
                                 :digest (:digest prepared)}]))))
  (with-open [^Closeable past (p/as-of system (p/snapshot-id system))]
    (p/branch! system :experiment)
    (let [experiment (p/checkout system :experiment)]
      (x/transact! experiment
        (fn [root]
          (objects/move! (.putCursor (WriteHashMap. root) "objects")
                         1 {:name "branch.bin"} 1)))
      (x/compact! system)
      (mapv (fn [view]
              (x/read! view
                (fn [root]
                  (objects/path (.getCursor (ReadHashMap. root) "objects") 1))))
            [system past experiment]))))

Result:

[["original.bin"] ["original.bin"] ["branch.bin"]]

Let write errors leave x/transact! to abort. Do not start a nested transaction or access the adapter’s physical catalog from the callback.

Read payloads within the callback

Open, read and close a payload stream inside x/read!. Return copied bytes or realised metadata. Do not return a borrowed cursor or stream.

Close historical views when finished. Do not close checkout handles separately, because they share the system’s lifetime.

Preserve catalog consistency

Do not pass xitstash’s internal maps through the adapter’s generic structural merger. If branches must merge, supply a custom merger that handles IDs, revisions and all catalog indexes together. No such merger is included with xitstash.

Deleting a payload on the current branch does not erase it from old commits. Compaction preserves content reachable from those commits. See Content and history.