Commit 8685b742 authored by Kirill Smelkov's avatar Kirill Smelkov

go/zodb: Tweak documentation a bit so it renders more well in godoc

While at it add draft overview of data model & friends to package
documentation.
parent 0e28fbb8
...@@ -56,7 +56,7 @@ type Cache struct { ...@@ -56,7 +56,7 @@ type Cache struct {
sizeMax int // cache is allowed to occupy not more than this sizeMax int // cache is allowed to occupy not more than this
} }
// oidCacheEntry maintains cached revisions for 1 oid // oidCacheEntry maintains cached revisions for 1 oid.
type oidCacheEntry struct { type oidCacheEntry struct {
oid Oid oid Oid
...@@ -70,7 +70,7 @@ type oidCacheEntry struct { ...@@ -70,7 +70,7 @@ type oidCacheEntry struct {
rcev []*revCacheEntry rcev []*revCacheEntry
} }
// revCacheEntry is information about 1 cached oid revision // revCacheEntry is information about 1 cached oid revision.
type revCacheEntry struct { type revCacheEntry struct {
parent *oidCacheEntry // oidCacheEntry holding us parent *oidCacheEntry // oidCacheEntry holding us
inLRU lruHead // in Cache.lru; protected by Cache.gcMu inLRU lruHead // in Cache.lru; protected by Cache.gcMu
...@@ -409,7 +409,7 @@ func (c *Cache) loadRCE(ctx context.Context, rce *revCacheEntry) { ...@@ -409,7 +409,7 @@ func (c *Cache) loadRCE(ctx context.Context, rce *revCacheEntry) {
c.gcMu.Unlock() c.gcMu.Unlock()
} }
// tryMerge tries to merge rce prev into next // tryMerge tries to merge rce prev into next.
// //
// both prev and next must be already loaded. // both prev and next must be already loaded.
// prev and next must come adjacent to each other in parent.rcev with // prev and next must come adjacent to each other in parent.rcev with
...@@ -561,7 +561,7 @@ func (oce *oidCacheEntry) release() { ...@@ -561,7 +561,7 @@ func (oce *oidCacheEntry) release() {
// ---------------------------------------- // ----------------------------------------
// isErrNoData returns whether an error is due to "there is no such data in // isErrNoData returns whether an error is due to "there is no such data in
// database", not e.g. some IO loading error // database", not e.g. some IO loading error.
func isErrNoData(err error) bool { func isErrNoData(err error) bool {
switch err.(type) { switch err.(type) {
default: default:
...@@ -631,7 +631,7 @@ func (oce *oidCacheEntry) del(rce *revCacheEntry) { ...@@ -631,7 +631,7 @@ func (oce *oidCacheEntry) del(rce *revCacheEntry) {
} }
// loaded reports whether rce was already loaded // loaded reports whether rce was already loaded.
// //
// must be called with rce.parent locked. // must be called with rce.parent locked.
func (rce *revCacheEntry) loaded() bool { func (rce *revCacheEntry) loaded() bool {
...@@ -653,7 +653,7 @@ func (h *lruHead) rceFromInLRU() (rce *revCacheEntry) { ...@@ -653,7 +653,7 @@ func (h *lruHead) rceFromInLRU() (rce *revCacheEntry) {
return (*revCacheEntry)(urce) return (*revCacheEntry)(urce)
} }
// errDB returns error about database being inconsistent // errDB returns error about database being inconsistent.
func errDB(oid Oid, format string, argv ...interface{}) error { func errDB(oid Oid, format string, argv ...interface{}) error {
// XXX -> separate type? // XXX -> separate type?
return fmt.Errorf("cache: database inconsistency: oid: %v: "+format, return fmt.Errorf("cache: database inconsistency: oid: %v: "+format,
......
...@@ -35,13 +35,13 @@ import ( ...@@ -35,13 +35,13 @@ import (
"github.com/kylelemons/godebug/pretty" "github.com/kylelemons/godebug/pretty"
) )
// tStorage implements read-only storage for cache testing // tStorage implements read-only storage for cache testing.
type tStorage struct { type tStorage struct {
// oid -> [](.serial↑, .data) // oid -> [](.serial↑, .data)
dataMap map[Oid][]tOidData dataMap map[Oid][]tOidData
} }
// data for oid for 1 revision // data for oid for 1 revision.
type tOidData struct { type tOidData struct {
serial Tid serial Tid
data []byte data []byte
......
...@@ -29,19 +29,19 @@ import ( ...@@ -29,19 +29,19 @@ import (
"lab.nexedi.com/kirr/go123/mem" "lab.nexedi.com/kirr/go123/mem"
) )
// OpenOptions describes options for OpenStorage // OpenOptions describes options for OpenStorage.
type OpenOptions struct { type OpenOptions struct {
ReadOnly bool // whether to open storage as read-only ReadOnly bool // whether to open storage as read-only
NoCache bool // don't use cache for read/write operations NoCache bool // don't use cache for read/write operations
} }
// DriverOpener is a function to open a storage driver // DriverOpener is a function to open a storage driver.
type DriverOpener func (ctx context.Context, u *url.URL, opt *OpenOptions) (IStorageDriver, error) type DriverOpener func (ctx context.Context, u *url.URL, opt *OpenOptions) (IStorageDriver, error)
// {} scheme -> DriverOpener // {} scheme -> DriverOpener
var driverRegistry = map[string]DriverOpener{} var driverRegistry = map[string]DriverOpener{}
// RegisterDriver registers opener to be used for URLs with scheme // RegisterDriver registers opener to be used for URLs with scheme.
func RegisterDriver(scheme string, opener DriverOpener) { func RegisterDriver(scheme string, opener DriverOpener) {
if _, already := driverRegistry[scheme]; already { if _, already := driverRegistry[scheme]; already {
panic(fmt.Errorf("ZODB URL scheme %q was already registered", scheme)) panic(fmt.Errorf("ZODB URL scheme %q was already registered", scheme))
...@@ -107,7 +107,7 @@ type storage struct { ...@@ -107,7 +107,7 @@ type storage struct {
} }
// loading always goes through cache - this way prefetching can work // loading goes through cache - this way prefetching can work
func (s *storage) Load(ctx context.Context, xid Xid) (*mem.Buf, Tid, error) { func (s *storage) Load(ctx context.Context, xid Xid) (*mem.Buf, Tid, error) {
// XXX here: offload xid validation from cache and driver ? // XXX here: offload xid validation from cache and driver ?
......
// Copyright (C) 2016-2017 Nexedi SA and Contributors. // Copyright (C) 2016-2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
...@@ -27,10 +27,10 @@ import ( ...@@ -27,10 +27,10 @@ import (
pickle "github.com/kisielk/og-rek" pickle "github.com/kisielk/og-rek"
) )
// PyData represents data stored into ZODB by Python applications. // PyData represents raw data stored into ZODB by Python applications.
// //
// The format is based on python pickles. Basically every serialized object has // The format is based on python pickles. Basically every serialized object has
// two parts: class description and object state. See // two parts: pickle with class description and pickle with object state. See
// //
// https://github.com/zopefoundation/ZODB/blob/a89485c1/src/ZODB/serialize.py // https://github.com/zopefoundation/ZODB/blob/a89485c1/src/ZODB/serialize.py
// //
......
...@@ -83,7 +83,7 @@ func (xid Xid) XFmtString(b xfmt.Buffer) xfmt.Buffer { ...@@ -83,7 +83,7 @@ func (xid Xid) XFmtString(b xfmt.Buffer) xfmt.Buffer {
*/ */
// parseHex64 decodes 16-character-wide hex-encoded string into uint64 // parseHex64 decodes 16-character-wide hex-encoded string into uint64.
func parseHex64(subj, s string) (uint64, error) { func parseHex64(subj, s string) (uint64, error) {
// XXX -> xfmt ? // XXX -> xfmt ?
// XXX like scanf("%016x") but scanf implicitly skips spaces without giving control to caller and is slower // XXX like scanf("%016x") but scanf implicitly skips spaces without giving control to caller and is slower
......
...@@ -41,7 +41,7 @@ func (t TimeStamp) XFmtString(b []byte) []byte { ...@@ -41,7 +41,7 @@ func (t TimeStamp) XFmtString(b []byte) []byte {
} }
// Time converts tid to time // Time converts tid to time.
func (tid Tid) Time() TimeStamp { func (tid Tid) Time() TimeStamp {
// the same as _parseRaw in TimeStamp/py // the same as _parseRaw in TimeStamp/py
// https://github.com/zopefoundation/persistent/blob/aba23595/persistent/timestamp.py#L75 // https://github.com/zopefoundation/persistent/blob/aba23595/persistent/timestamp.py#L75
......
// Copyright (C) 2016-2017 Nexedi SA and Contributors. // Copyright (C) 2016-2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
...@@ -23,6 +23,42 @@ ...@@ -23,6 +23,42 @@
// Data model this package provides is partly based on ZODB/py // Data model this package provides is partly based on ZODB/py
// (https://github.com/zopefoundation/ZODB) to maintain compatibility in // (https://github.com/zopefoundation/ZODB) to maintain compatibility in
// between Python and Go implementations. // between Python and Go implementations.
//
// Data model
//
// A ZODB database is conceptually modeled as transactional log of changes to objects.
// Oid identifies an object and Tid - a transaction. A transaction can change
// several objects and also has metadata, like user and description, associated
// with it. If an object is changed by transaction, it is said that there is
// revision of the object with particular object state committed by that transaction.
// Object revision is the same as tid of transaction that modified the object.
// The combination of object identifier and particular revision (serial)
// uniquely addresses corresponding data record.
//
// Tids of consecutive database transactions are monotonically increasing and
// are connected with time when transaction in question was committed.
// This way, besides identifying a transaction with changes, Tid can also be
// used to specify whole database state constructed by all cumulated
// transaction changes from database beginning up to, and including,
// transaction specified by it. Xid is "extended" oid that specifies particular
// object state: it is (oid, at) pair that is mapped to object's latest
// revision with serial ≤ at.
//
// Object state data is generally opaque, but is traditionally based on Python
// pickles in ZODB/py world.
//
//
// Operations
//
// A ZODB database can be opened with OpenStorage. Once opened IStorage
// interface is returned that represents access to the database. Please see
// documentation of IStorage, and other interfaces it embeds, for details.
//
//
// --------
//
// See also package lab.nexedi.com/kirr/neo/go/zodb/zodbtools and associated
// zodb command that provide tools for managing ZODB databases.
package zodb package zodb
import ( import (
...@@ -64,7 +100,7 @@ type Oid uint64 ...@@ -64,7 +100,7 @@ type Oid uint64
// //
// At specifies whole database state at which object identified with Oid should // At specifies whole database state at which object identified with Oid should
// be looked up. The object revision is taken from latest transaction modifying // be looked up. The object revision is taken from latest transaction modifying
// the object with tid <= At. // the object with tid At.
// //
// Note that Xids are not unique - the same object revision can be addressed // Note that Xids are not unique - the same object revision can be addressed
// with several xids. // with several xids.
...@@ -106,7 +142,7 @@ type DataInfo struct { ...@@ -106,7 +142,7 @@ type DataInfo struct {
DataTidHint Tid DataTidHint Tid
} }
// TxnStatus represents status of a transaction // TxnStatus represents status of a transaction.
type TxnStatus byte type TxnStatus byte
const ( const (
...@@ -118,7 +154,7 @@ const ( ...@@ -118,7 +154,7 @@ const (
// ---- interfaces ---- // ---- interfaces ----
// NoObjectError is the error which tells that there is no such object in the database at all // NoObjectError is the error which tells that there is no such object in the database at all.
type NoObjectError struct { type NoObjectError struct {
Oid Oid Oid Oid
} }
...@@ -282,7 +318,7 @@ type IDataIterator interface { ...@@ -282,7 +318,7 @@ type IDataIterator interface {
// ---- misc ---- // ---- misc ----
// Valid returns whether tid is in valid transaction identifiers range // Valid returns whether tid is in valid transaction identifiers range.
func (tid Tid) Valid() bool { func (tid Tid) Valid() bool {
// NOTE 0 is invalid tid // NOTE 0 is invalid tid
if 0 < tid && tid <= TidMax { if 0 < tid && tid <= TidMax {
...@@ -292,7 +328,7 @@ func (tid Tid) Valid() bool { ...@@ -292,7 +328,7 @@ func (tid Tid) Valid() bool {
} }
} }
// Valid returns true if transaction status value is well-known and valid // Valid returns true if transaction status value is well-known and valid.
func (ts TxnStatus) Valid() bool { func (ts TxnStatus) Valid() bool {
switch ts { switch ts {
case TxnComplete, TxnPacked, TxnInprogress: case TxnComplete, TxnPacked, TxnInprogress:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment