### page under construction

common, abstract interfaces for Subversion data trees

It is intended that defining and then implementing common, abstract interfaces will make it easier to develop conceptually simple features such as Shelving and Checkpointing that fundamentally require little more than the ability to copy versioned data between a WC, a repository, a shelf, and other locations yet to be defined (such as a streamy 'patch file' format or an external service).

Introduction: The Problem

In order to implement features such as shelving, we need to be able to move data between the WC and repository and other places – initially from the WC to a "shelf" storage location and back again.

So far (up to Subversion 1.10) each subsystem's APIs work in different ways – writing a new revision at the RA layer uses the "delta editor" which is used in several other places, whereas reading or writing the working tree in the WC requires using a combination of many separate functions, and a different set again for accessing the WC base tree. Some higher level semantics are inconsistent – for example, some property getter and setter APIs may operate on only user-visible properties, while others also handle hidden properties (e.g. those called "WC props" or "DAV props"). Read and write APIs are not symmetric.

Introduction: The Solution

These trees – a repository revision, the WC base, the WC working tree – have very much in common, as well as significant differences. The idea is to factor out the common parts of the interface while providing an elegant way to deal with their differences. A conceptually simple application-level task such as copying a WC working sub-tree to a shelf will require only setting up the source and destination and calling a generic "read from tree A, write to tree B" routine, and will not require a deep implementation of a new specific variant of that routine.

It will be easier to test data transfer to and from subsystems, using round-trip testing. For example, it will be easy to write a test that performs "export" followed by "import" and checks for no change, and run it against every subsystem that can store versioned data.

There is an emphasis here on aspects of a tree as represented in a Working Copy, which are particularly useful for Shelving-related use cases.

Generic tree traversal interfaces are being prototyped in the "tree-api" branch.

Common Tree Interfaces

These interfaces operate on any tree that Subversion can work with (dirs, files, symlinks, each with properties), as found in a repo or in a WC or even an unversioned tree.

tree node data types

Each of these describes some aspect of a tree.

Tree (node) types used throughout Subversion:


dirs, files, symlinks, each with properties

describes the (potentially) versioned content of a tree
layoutrevisions, URLs (in-repository paths), depthsdescribes a WC base shape (potentially mixed-rev, switched, sparse) by reference to a repository
other WC base state

last-changed-*, lock-token, changelist, incomplete, ...

describes the rest of a WC base state
other WC working/actual stateconflicts, missing/obstructed, copy-from/move, ...describes the rest of a WC working/actual state


tree traversal interfaces

Generic references to trees and tree nodes, and tree walking facilities.

The smallest tree that can be described is (a single non-existent node? a single file or symlink or directory?).

walkvisit each node
walk-dirsvisit each directory
walk-twowalk two trees in parallel


tree data interfaces

state could be implemented as delta against empty state

assuming state is X, change state to Y (else undefined)

a unidirectional non-context difference; not suitable for merging, on its own


derived tree interfaces

pairaccess to state X, state Y, delta(X:Y), delta(Y:X)gives producer the flexibility to store one state and one delta, or two states, deriving the rest on demand, without the consumer caring
proto-revbase-layout + pair(base-content, content-delta) + rev-propsbase-content can be dereferenced


WC Content APIs

get content state (base) n/a (closest: export.c)

get content state (revert-base)

top working layer; used in friendly diffn/a
get content state (actual) n/a (closest: export.c)
get content delta (base : actual) (closest: svn_wc__diff7() -> diff_processor_t)
get content delta (revert-base : actual)used in friendly diff(closest: svn_wc__diff7() + svn_diff__tree_processor_copy_as_changed_create())
apply content delta (base)what should happen to working/actual state? maybe in present WC design this is tied to merge-into-actual 
apply content delta (actual) (closest: see diff_processor in merge.c?)

WC Layout APIs

get layout stateused in "info", "viewspec export", ...presently: svn_wc_crawl_revisions5() -> svn_ra_reporter3_t
apply layout deltaused in "--set-depth", updating (server-exclude), "viewspec apply", ...n/a



if we're going to store the base content as well:

  • wc.get-base-layout() -> shelf.store-base-layout()
  • wc.get-content-pair-delta(base, actual) -> shelf.store-content-pair()

if we're going to store a base description but not its content:

  • wc.get-base-layout() -> maybe add Merkle hashes or something? -> shelf.store-base-layout()
  • wc.get-content-delta() -> shelf.store-content-delta()


unshelve, requiring the WC base layout matches the shelf's base layout:

  • check wc base layout matches (abort, warn, require force if not)
    • compare(shelf.get-base-layout(), wc.get-base-layout())
  • apply changes
    • shelf.get-content-delta() -> wc(actual).apply-content-delta()

unshelve, changing the WC base layout to match the shelf's base layout:

  • set wc base layout
    • shelf.read-base-layout() -> wc.set-base-layout()
  • apply changes
    • shelf.read-content-delta() -> wc(actual).apply-content-delta()

unshelve, requiring the WC content matches the shelf's base content:

  • either: check the WC actual content matches the shelf base content (perhaps using a Merkle tree);
  • or (not covering every case) check the WC base matches the shelf base content and no local mods in WC

unshelve, merging with the present WC content:

  • merge changes
    • shelf.get-content-diff() -> wc(actual).apply-merge()



  • No labels