db

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 20, 2022 License: MIT Imports: 11 Imported by: 0

README

C4 DB

c4/db is a go package implementing a C4 ID key/value database.

This package has been recently updated to improve the interface, functionality, and performance.

A database built on the C4 framework is at it's core very simple. A key is associated with a C4 ID, and a reverse index provides the inverse mapping of a C4 ID to a list of keys that refer to it.

Typically one finds the C4 ID of an asset and stores it's ID along with it's filepath or other 'assigned' id as the key. C4 IDs can also be associated together with an arbitrary string identifying the type of relationship. So, the type and meaning of relationships is up to the user, but here's an example for saving a file's ID and the ID for some metadata about the file.

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    c4db "github.com/Avalanche-io/c4/db"
    c4 "github.com/Avalanche-io/c4/id"
    "io"
    "os"
    "path/filepath"
)

func assert(is_true bool) {
    if !is_true {
        panic("assertion not true")
    }
}
func stopOnError(err error) {
    if err != nil {
        fmt.Errorf("error %s\n", err)
        os.Exit(-1)
    }
}

func main() {
    // Open or create a C4 database
    db, err := c4db.Open("test.c4db", nil)
    stopOnError(err)
    defer db.Close()

    // get the current working directory and set main.go as the input
    expath, err := os.Executable()
    stopOnError(err)
    cwd := filepath.Dir(expath)
    inputname := "main.go"
    inputpath := filepath.Join(cwd, inputname)

    // open the input file
    fin, err := os.Open(inputname)
    stopOnError(err)
    defer fin.Close()

    // get os.FileInfo metadata about the file
    info, err := fin.Stat()
    stopOnError(err)

    // marshal the metadata
    info_data, err := json.Marshal(info)
    stopOnError(err)

    // Find the C4 ID of the file and of the metadata
    main_id := c4.Identify(fin)
    info_id := c4.Identify(bytes.NewReader(info_data))

    // Save the metadata in some file, and close.
    outputpath := filepath.Join(cwd, "main.info")
    fout, err := os.Create(outputpath)
    stopOnError(err)
    _, err = io.Copy(fout, bytes.NewReader(info_data))
    stopOnError(err)
    fout.Close()

    // save the main_id with it's path as the key
    _, err = db.KeySet(inputpath, main_id.Digest())
    stopOnError(err)
    // save the info_id with it's path as the key
    _, err = db.KeySet(outputpath, info_id.Digest())
    stopOnError(err)

    // link the main_id to the info_id as 'metadata'
    err = db.LinkSet("metadata", main_id.Digest(), info_id.Digest())
    stopOnError(err)

    // Get the main_id from the key:
    main_id2, err := db.KeyGet(inputpath)
    stopOnError(err)
    _ = main_id2

    // Get all keys and IDs under a key prefix:
    count := 0
    for en := range db.KeyGetAll(cwd) {
        key := en.Key()
        digest := en.Value()
        fmt.Printf("Key: %q\n", key)
        fmt.Printf("ID: %s\n", digest.ID())
        en.Close()
        count++
    }
    assert(count == 2)

    // Find keys from IDs
    keys := db.KeyFind(main_id.Digest())
    assert(keys[0] == inputpath)

    // Find "metadata" links from the main_id
    for en := range db.LinkGet("metadata", main_id.Digest()) {
        source_digest := en.Source()
        target_digest := en.Target()
        fmt.Printf("main.go id: %s\n", source_digest.ID())
        fmt.Printf("main.info id: %s\n", target_digest.ID())
        en.Close()
    }

}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB stores

func Open

func Open(path string, options *Options) (db *DB, err error)

Open opens or initializes a DB for the given path. When creating file permissions are set to 0700, when opening an existing database file permissions are not modified.

func (*DB) Batch

func (db *DB) Batch(fn func(*bolt.Tx) error) error

Update, View and Batch call the methods of the same name on the underlying bolt database. See github.com/boltdb/bolt for more information.

Batch calls fn as part of a batch. It behaves similar to Update, except:

1. concurrent Batch calls can be combined into a single Bolt transaction.

2. the function passed to Batch may be called multiple times, regardless of whether it returns error or not.

This means that Batch function side effects must be idempotent and take permanent effect only after a successful return is seen in caller.

The maximum batch size and delay can be adjusted with DB.MaxBatchSize and DB.MaxBatchDelay, respectively.

Batch is only useful when there are multiple goroutines calling it.

func (*DB) Close

func (db *DB) Close() error

func (*DB) KeyBatch

func (db *DB) KeyBatch(f func(*Tx) bool)

func (*DB) KeyCAS

func (db *DB) KeyCAS(key string, old_digest, new_digest c4.Digest) bool

KeyCAS implements a 'compare and swap' operation on key. In other words if the value of key is not the expected `old_digest` value the operation will do noting and return false. If `old_digest` is the current value of key the key is updated with new_digest, KeyCAS returns `true`.

func (*DB) KeyDelete

func (db *DB) KeyDelete(key string) (c4.Digest, error)

func (*DB) KeyDeleteAll

func (db *DB) KeyDeleteAll(key_prefixs ...string) (int, error)

KeyDeleteAll deletes all keys with the provided prefix, or all keys in the case of an empty string. KeyDeleteAll returns the number of items deleted and/or an error.

func (*DB) KeyFind

func (db *DB) KeyFind(digest c4.Digest) []string

func (*DB) KeyGet

func (db *DB) KeyGet(key string) (c4.Digest, error)

func (*DB) KeyGetAll

func (db *DB) KeyGetAll(key_prefix ...string) <-chan Entry

func (*DB) KeySet

func (db *DB) KeySet(key string, digest c4.Digest) (c4.Digest, error)

KeySet stores a digest with the key provided. If the key was previously set the previous digest is returned otherwise nil is returned.

func (*DB) LinkDelete

func (db *DB) LinkDelete(relationship string, source c4.Digest, targets ...c4.Digest) (int, error)

func (*DB) LinkDeleteAll

func (db *DB) LinkDeleteAll(sources ...c4.Digest) (int, error)

func (*DB) LinkGet

func (db *DB) LinkGet(relationship string, source c4.Digest) <-chan Entry

func (*DB) LinkGetAll

func (db *DB) LinkGetAll(sources ...c4.Digest) <-chan Entry

func (*DB) LinkSet

func (db *DB) LinkSet(relationship string, source c4.Digest, targets ...c4.Digest) error

LinkSet creates a relationship between a `source` digest and one or more `target` digests. The relationship is an arbitrary string that is application dependent, but could be something like "metadata", "parent", or "children" for example.

func (*DB) Stats

func (db *DB) Stats() *Stats

func (*DB) TreeDelete

func (db *DB) TreeDelete(tree c4.Digest) error

func (*DB) TreeGet

func (db *DB) TreeGet(tree_digest c4.Digest) (*c4.Tree, error)

func (*DB) TreeSet

func (db *DB) TreeSet(tree *c4.Tree) error

func (*DB) Update

func (db *DB) Update(fn func(*bolt.Tx) error) error

Update, View and Batch call the methods of the same name on the underlying bolt database. See github.com/boltdb/bolt for more information.

Update executes a function within the context of a read-write managed transaction. If no error is returned from the function then the transaction is committed. If an error is returned then the entire transaction is rolled back. Any error that is returned from the function or returned from the commit is returned from the Update() method.

Attempting to manually commit or rollback within the function will cause a panic.

func (*DB) View

func (db *DB) View(fn func(*bolt.Tx) error) error

Update, View and Batch call the methods of the same name on the underlying bolt database. See github.com/boltdb/bolt for more information.

View executes a function within the context of a managed read-only transaction. Any error that is returned from the function is returned from the View() method.

Attempting to manually rollback within the function will cause a panic.

type Entry

type Entry interface {
	Key() string
	Value() c4.Digest
	Source() c4.Digest
	Target() c4.Digest
	Relationships() []string
	Err() error
	Stop()
	Close()
}

Entry is an interface for items returned from listing methods like KeyGetAll. For performance an Entry must be closed when done using it.

type Options

type Options struct {
	// Maximum size in bytes of a tree stored directly in the database.  Trees
	// over this size will be written out to separate files.
	TreeMaxSize int

	// Sets the strategy to use for tree storage.
	TreeStrategy TreeStrategyType

	// Path to an alternative storage location.
	ExternalStore []string
}

type Stats

type Stats struct {
	Keys       int
	KeyIndexes int
	Trees      int
	Links      int
	TreesSize  uint64
}

type TreeStrategyType

type TreeStrategyType int
func init() {
	bucketList := [][]byte{keyBucket, linkBucket}
}
const (
	TreeStrategyNone TreeStrategyType = iota

	// Sets the tree storage strategy to always store the entire tree.
	TreeStrategyCache

	// Sets the tree storage strategy to always store only the id list, and
	// compute the tree when restored.
	TreeStrategyCompute

	// Sets the tree storage strategy to automatically balance between the
	// cashing strategy and computing strategy.
	TreeStrategyBalance
)

type Tx

type Tx struct {
	// contains filtered or unexported fields
}

func (*Tx) Err

func (t *Tx) Err() error

func (*Tx) KeySet

func (t *Tx) KeySet(key string, digest c4.Digest)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL