dhash

package
v0.0.0-...-e1dc7cb Latest Latest
Warning

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

Go to latest
Published: Feb 7, 2013 License: BSD-2-Clause-Views Imports: 24 Imported by: 0

README

dhash

The distributed hash bits and pieces in god. Uses radix for tree structure, discord for routing and timenet for clock synchronization.

Inspiration

god is mainly inspired by the scalability of Chord/DHash, and the performance and feature set of Redis.

It tries to couple a performant in-memory database and simple yet powerful features with a scalable and operationally simple cluster concept.

Timestamps

To avoid temporarily disconnected nodes from rejoining the network and either reanimating deleted entries or just reintroducing previously changed data, all entries have a timestamp based on the time synchronization of the timenet.Timer.

All removed entries are replaced with a tombstone, also having a timestamp, which makes it less likely that old data may live again.

Tombstones are lazily removed after 24 hours, when data in their vicinity is changed. This makes it imperative that any network splits or temporarily dead nodes be fixed or cleaned before rejoining the main cluster again.

Synchronization

To ensure that all Nodes in the network have the data they should have, each node regularly synchronizes with those nodes that should have redundant copies of its data.

This is done by comparing their respective databases, and copying any entries with newer timestamps within the relevant range, using radix.Sync.

Cleaning

To ensure that all Nodes in the network get rid of the data they should not have, each node regularly cleans its database.

This is done by looking at the first entry it should not own (the first one after its own position), checking what other Node should own it, and then doing a destructive sync (again using radix.Sync) between the misplaced entry and the position of the proper owner.

Migration

Using non hashed values as keys in the cluster would normally cause severe imbalances between the Nodes, since it would be very unlikely that the spread out position they take by default would represent the actual keys used.

To avoid this, it is normally recommended to use a hashing function, for example murmur.Hash, to create keys for the data.

But to allow those user who so wish to use other data (perhaps ordered, or segmented in some way) as keys, the Nodes will migrate to cover roughly the same amount of data each.

This is done by comparing the owned entries (both tombstones and sub trees and regular data) each node owns to the data its successor owns, and if the predecessor owns too much it will decrease its position to achieve balance.

This is not a perfect mechanism, but it seems to even out the load quite a bit in situations where non hashed keys are used a lot.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CleanListener

type CleanListener func(source, dest common.Remote, cleaned, pushed int) (keep bool)

CleanListener is a function listening for clean events where one dhash.Node has cleaned items from itself and pushed items to another dhash.Node.

type Comm

type Comm struct {
	Source      common.Remote
	Destination common.Remote
	Key         []byte
	SubKey      []byte
	Type        string
}

Comm contains metadata about one communication between two dhash.Nodes.

type CommListener

type CommListener func(comm Comm) (keep bool)

CommListener is a function listening to generic communications between two dhash.Nodes.

type Conf

type Conf struct {
	Key   string
	Value string
}

type HashTreeItem

type HashTreeItem struct {
	Key       []radix.Nibble
	SubKey    []radix.Nibble
	Timestamp int64
	Expected  int64
	Value     []byte
	Exists    bool
}

type IndexRange

type IndexRange struct {
	Key      []byte
	MinIndex *int
	MaxIndex *int
}

type JSONApi

type JSONApi Node

func (*JSONApi) AddConfiguration

func (self *JSONApi) AddConfiguration(co Conf, x *Nothing) (err error)

func (*JSONApi) Clear

func (self *JSONApi) Clear(x Nothing, y *Nothing) (err error)

func (*JSONApi) Configuration

func (self *JSONApi) Configuration(x Nothing, result *common.Conf) (err error)

func (*JSONApi) Count

func (self *JSONApi) Count(kr KeyRange, result *int) (err error)

func (*JSONApi) Del

func (self *JSONApi) Del(d KeyOp, n *Nothing) (err error)

func (*JSONApi) Describe

func (self *JSONApi) Describe(x Nothing, result *common.DHashDescription) (err error)

func (*JSONApi) DescribeTree

func (self *JSONApi) DescribeTree(x Nothing, result *string) (err error)

func (*JSONApi) First

func (self *JSONApi) First(k KeyReq, result *SubValueRes) (err error)

func (*JSONApi) Get

func (self *JSONApi) Get(k KeyReq, result *ValueRes) (err error)

func (*JSONApi) IndexOf

func (self *JSONApi) IndexOf(i SubKeyReq, result *common.Index) (err error)

func (*JSONApi) Last

func (self *JSONApi) Last(k KeyReq, result *SubValueRes) (err error)

func (*JSONApi) MirrorCount

func (self *JSONApi) MirrorCount(kr KeyRange, result *int) (err error)

func (*JSONApi) MirrorFirst

func (self *JSONApi) MirrorFirst(k KeyReq, result *SubValueRes) (err error)

func (*JSONApi) MirrorIndexOf

func (self *JSONApi) MirrorIndexOf(i SubKeyReq, result *common.Index) (err error)

func (*JSONApi) MirrorLast

func (self *JSONApi) MirrorLast(k KeyReq, result *SubValueRes) (err error)

func (*JSONApi) MirrorNextIndex

func (self *JSONApi) MirrorNextIndex(i SubIndex, result *SubValueIndexRes) (err error)

func (*JSONApi) MirrorPrevIndex

func (self *JSONApi) MirrorPrevIndex(i SubIndex, result *SubValueIndexRes) (err error)

func (*JSONApi) MirrorReverseIndexOf

func (self *JSONApi) MirrorReverseIndexOf(i SubKeyReq, result *common.Index) (err error)

func (*JSONApi) MirrorReverseSlice

func (self *JSONApi) MirrorReverseSlice(kr KeyRange, result *[]ValueRes) (err error)

func (*JSONApi) MirrorReverseSliceIndex

func (self *JSONApi) MirrorReverseSliceIndex(ir IndexRange, result *[]ValueRes) (err error)

func (*JSONApi) MirrorReverseSliceLen

func (self *JSONApi) MirrorReverseSliceLen(pr PageRange, result *[]ValueRes) (err error)

func (*JSONApi) MirrorSlice

func (self *JSONApi) MirrorSlice(kr KeyRange, result *[]ValueRes) (err error)

func (*JSONApi) MirrorSliceIndex

func (self *JSONApi) MirrorSliceIndex(ir IndexRange, result *[]ValueRes) (err error)

func (*JSONApi) MirrorSliceLen

func (self *JSONApi) MirrorSliceLen(pr PageRange, result *[]ValueRes) (err error)

func (*JSONApi) Next

func (self *JSONApi) Next(kr KeyReq, result *ValueRes) (err error)

func (*JSONApi) NextIndex

func (self *JSONApi) NextIndex(i SubIndex, result *SubValueIndexRes) (err error)

func (*JSONApi) Nodes

func (self *JSONApi) Nodes(x Nothing, result *common.Remotes) (err error)

func (*JSONApi) Owned

func (self *JSONApi) Owned(x Nothing, result *int) (err error)

func (*JSONApi) Prev

func (self *JSONApi) Prev(kr KeyReq, result *ValueRes) (err error)

func (*JSONApi) PrevIndex

func (self *JSONApi) PrevIndex(i SubIndex, result *SubValueIndexRes) (err error)

func (*JSONApi) Put

func (self *JSONApi) Put(d ValueOp, n *Nothing) (err error)

func (*JSONApi) ReverseIndexOf

func (self *JSONApi) ReverseIndexOf(i SubKeyReq, result *common.Index) (err error)

func (*JSONApi) ReverseSlice

func (self *JSONApi) ReverseSlice(kr KeyRange, result *[]ValueRes) (err error)

func (*JSONApi) ReverseSliceIndex

func (self *JSONApi) ReverseSliceIndex(ir IndexRange, result *[]ValueRes) (err error)

func (*JSONApi) ReverseSliceLen

func (self *JSONApi) ReverseSliceLen(pr PageRange, result *[]ValueRes) (err error)

func (*JSONApi) SetExpression

func (self *JSONApi) SetExpression(expr setop.SetExpression, items *[]setop.SetOpResult) (err error)

func (*JSONApi) Size

func (self *JSONApi) Size(x Nothing, result *int) (err error)

func (*JSONApi) Slice

func (self *JSONApi) Slice(kr KeyRange, result *[]ValueRes) (err error)

func (*JSONApi) SliceIndex

func (self *JSONApi) SliceIndex(ir IndexRange, result *[]ValueRes) (err error)

func (*JSONApi) SliceLen

func (self *JSONApi) SliceLen(pr PageRange, result *[]ValueRes) (err error)

func (*JSONApi) SubAddConfiguration

func (self *JSONApi) SubAddConfiguration(co SubConf, x *Nothing) (err error)

func (*JSONApi) SubClear

func (self *JSONApi) SubClear(d SubKeyOp, n *Nothing) (err error)

func (*JSONApi) SubConfiguration

func (self *JSONApi) SubConfiguration(k KeyReq, result *common.Conf) (err error)

func (*JSONApi) SubDel

func (self *JSONApi) SubDel(d SubKeyOp, n *Nothing) (err error)

func (*JSONApi) SubGet

func (self *JSONApi) SubGet(k SubKeyReq, result *SubValueRes) (err error)

func (*JSONApi) SubMirrorNext

func (self *JSONApi) SubMirrorNext(k SubKeyReq, result *SubValueRes) (err error)

func (*JSONApi) SubMirrorPrev

func (self *JSONApi) SubMirrorPrev(k SubKeyReq, result *SubValueRes) (err error)

func (*JSONApi) SubNext

func (self *JSONApi) SubNext(k SubKeyReq, result *SubValueRes) (err error)

func (*JSONApi) SubPrev

func (self *JSONApi) SubPrev(k SubKeyReq, result *SubValueRes) (err error)

func (*JSONApi) SubPut

func (self *JSONApi) SubPut(d SubValueOp, n *Nothing) (err error)

func (*JSONApi) SubSize

func (self *JSONApi) SubSize(k KeyReq, result *int) (err error)

type JSONClient

type JSONClient string

JSONClient is used in the tests to ensure that the JSON API provides roughly the same functionality as the gob API. It is also a demonstration and example of how the JSON API can be used. It is NOT meant to be used as a real client, since if you are using Go anyway the client.Conn type is much more efficient.

func (JSONClient) AddConfiguration

func (self JSONClient) AddConfiguration(key, value string)

func (JSONClient) Count

func (self JSONClient) Count(key, min, max []byte, mininc, maxinc bool) (result int)

func (JSONClient) Del

func (self JSONClient) Del(key []byte)

func (JSONClient) First

func (self JSONClient) First(key []byte) (firstKey, firstValue []byte, existed bool)

func (JSONClient) Get

func (self JSONClient) Get(key []byte) (value []byte, existed bool)

func (JSONClient) IndexOf

func (self JSONClient) IndexOf(key, subKey []byte) (index int, existed bool)

func (JSONClient) Last

func (self JSONClient) Last(key []byte) (lastKey, lastValue []byte, existed bool)

func (JSONClient) MirrorCount

func (self JSONClient) MirrorCount(key, min, max []byte, mininc, maxinc bool) (result int)

func (JSONClient) MirrorFirst

func (self JSONClient) MirrorFirst(key []byte) (firstKey, firstValue []byte, existed bool)

func (JSONClient) MirrorIndexOf

func (self JSONClient) MirrorIndexOf(key, subKey []byte) (index int, existed bool)

func (JSONClient) MirrorLast

func (self JSONClient) MirrorLast(key []byte) (lastKey, lastValue []byte, existed bool)

func (JSONClient) MirrorNextIndex

func (self JSONClient) MirrorNextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool)

func (JSONClient) MirrorPrevIndex

func (self JSONClient) MirrorPrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool)

func (JSONClient) MirrorReverseIndexOf

func (self JSONClient) MirrorReverseIndexOf(key, subKey []byte) (index int, existed bool)

func (JSONClient) MirrorReverseSlice

func (self JSONClient) MirrorReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item)

func (JSONClient) MirrorReverseSliceIndex

func (self JSONClient) MirrorReverseSliceIndex(key []byte, min, max *int) (result []common.Item)

func (JSONClient) MirrorReverseSliceLen

func (self JSONClient) MirrorReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item)

func (JSONClient) MirrorSlice

func (self JSONClient) MirrorSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item)

func (JSONClient) MirrorSliceIndex

func (self JSONClient) MirrorSliceIndex(key []byte, min, max *int) (result []common.Item)

func (JSONClient) MirrorSliceLen

func (self JSONClient) MirrorSliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item)

func (JSONClient) Next

func (self JSONClient) Next(key []byte) (nextKey, nextValue []byte, existed bool)

func (JSONClient) NextIndex

func (self JSONClient) NextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool)

func (JSONClient) Prev

func (self JSONClient) Prev(key []byte) (prevKey, prevValue []byte, existed bool)

func (JSONClient) PrevIndex

func (self JSONClient) PrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool)

func (JSONClient) Put

func (self JSONClient) Put(key, value []byte)

func (JSONClient) ReverseIndexOf

func (self JSONClient) ReverseIndexOf(key, subKey []byte) (index int, existed bool)

func (JSONClient) ReverseSlice

func (self JSONClient) ReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item)

func (JSONClient) ReverseSliceIndex

func (self JSONClient) ReverseSliceIndex(key []byte, min, max *int) (result []common.Item)

func (JSONClient) ReverseSliceLen

func (self JSONClient) ReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item)

func (JSONClient) SDel

func (self JSONClient) SDel(key []byte)

func (JSONClient) SPut

func (self JSONClient) SPut(key, value []byte)

func (JSONClient) SSubClear

func (self JSONClient) SSubClear(key []byte)

func (JSONClient) SSubDel

func (self JSONClient) SSubDel(key, subKey []byte)

func (JSONClient) SSubPut

func (self JSONClient) SSubPut(key, subKey, value []byte)

func (JSONClient) SetExpression

func (self JSONClient) SetExpression(expr setop.SetExpression) (result []setop.SetOpResult)

func (JSONClient) Size

func (self JSONClient) Size() (result int)

func (JSONClient) Slice

func (self JSONClient) Slice(key, min, max []byte, mininc, maxinc bool) (result []common.Item)

func (JSONClient) SliceIndex

func (self JSONClient) SliceIndex(key []byte, min, max *int) (result []common.Item)

func (JSONClient) SliceLen

func (self JSONClient) SliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item)

func (JSONClient) SubAddConfiguration

func (self JSONClient) SubAddConfiguration(treeKey []byte, key, value string)

func (JSONClient) SubClear

func (self JSONClient) SubClear(key []byte)

func (JSONClient) SubDel

func (self JSONClient) SubDel(key, subKey []byte)

func (JSONClient) SubGet

func (self JSONClient) SubGet(key, subKey []byte) (value []byte, existed bool)

func (JSONClient) SubMirrorNext

func (self JSONClient) SubMirrorNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool)

func (JSONClient) SubMirrorPrev

func (self JSONClient) SubMirrorPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool)

func (JSONClient) SubNext

func (self JSONClient) SubNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool)

func (JSONClient) SubPrev

func (self JSONClient) SubPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool)

func (JSONClient) SubPut

func (self JSONClient) SubPut(key, subKey, value []byte)

func (JSONClient) SubSize

func (self JSONClient) SubSize(key []byte) (result int)

type KeyOp

type KeyOp struct {
	Key  []byte
	Sync bool
}

type KeyRange

type KeyRange struct {
	Key    []byte
	Min    []byte
	Max    []byte
	MinInc bool
	MaxInc bool
}

type KeyReq

type KeyReq struct {
	Key []byte
}

type MigrateListener

type MigrateListener func(dhash *Node, source, destination []byte) (keep bool)

MigrateListener is a function listening for migrate events where one dhash.Node has migrated from one position to another.

type Node

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

Node is a node in the database. It contains a discord.Node containing routing and rpc functionality, a timenet.Timer containing time synchronization functionality and a radix.Tree containing the actual data.

func NewNode

func NewNode(listenAddr, broadcastAddr string) *Node

func NewNodeDir

func NewNodeDir(listenAddr, broadcastAddr, dir string) (result *Node)

NewNode will return a dhash.Node publishing itself on the given address.

func (*Node) AddChangeListener

func (self *Node) AddChangeListener(f common.RingChangeListener)

func (*Node) AddCleanListener

func (self *Node) AddCleanListener(l CleanListener)

func (*Node) AddCommListener

func (self *Node) AddCommListener(l CommListener)

func (*Node) AddConfiguration

func (self *Node) AddConfiguration(c common.ConfItem)

func (*Node) AddMigrateListener

func (self *Node) AddMigrateListener(l MigrateListener)

func (*Node) AddSyncListener

func (self *Node) AddSyncListener(l SyncListener)

func (*Node) Clear

func (self *Node) Clear()

func (*Node) Configuration

func (self *Node) Configuration(x int, result *common.Conf) error

func (*Node) Count

func (self *Node) Count(r common.Range, result *int) error

func (*Node) Del

func (self *Node) Del(data common.Item) error

func (*Node) Describe

func (self *Node) Describe() string

Describe will return a humanly readable string describing the node.

func (*Node) DescribeTree

func (self *Node) DescribeTree() string

DescribeTree will return a humanly readable string describing the node contents.

func (*Node) Description

func (self *Node) Description() common.DHashDescription

Description will return a current description of the node.

func (*Node) First

func (self *Node) First(data common.Item, result *common.Item) error

func (*Node) Get

func (self *Node) Get(data common.Item, result *common.Item) error

func (*Node) GetBroadcastAddr

func (self *Node) GetBroadcastAddr() string

func (*Node) IndexOf

func (self *Node) IndexOf(data common.Item, result *common.Index) error

func (*Node) Last

func (self *Node) Last(data common.Item, result *common.Item) error

func (*Node) MirrorCount

func (self *Node) MirrorCount(r common.Range, result *int) error

func (*Node) MirrorFirst

func (self *Node) MirrorFirst(data common.Item, result *common.Item) error

func (*Node) MirrorIndexOf

func (self *Node) MirrorIndexOf(data common.Item, result *common.Index) error

func (*Node) MirrorLast

func (self *Node) MirrorLast(data common.Item, result *common.Item) error

func (*Node) MirrorNextIndex

func (self *Node) MirrorNextIndex(data common.Item, result *common.Item) error

func (*Node) MirrorPrevIndex

func (self *Node) MirrorPrevIndex(data common.Item, result *common.Item) error

func (*Node) MirrorReverseIndexOf

func (self *Node) MirrorReverseIndexOf(data common.Item, result *common.Index) error

func (*Node) MirrorReverseSlice

func (self *Node) MirrorReverseSlice(r common.Range, items *[]common.Item) error

func (*Node) MirrorReverseSliceIndex

func (self *Node) MirrorReverseSliceIndex(r common.Range, items *[]common.Item) error

func (*Node) MirrorReverseSliceLen

func (self *Node) MirrorReverseSliceLen(r common.Range, items *[]common.Item) error

func (*Node) MirrorSlice

func (self *Node) MirrorSlice(r common.Range, items *[]common.Item) error

func (*Node) MirrorSliceIndex

func (self *Node) MirrorSliceIndex(r common.Range, items *[]common.Item) error

func (*Node) MirrorSliceLen

func (self *Node) MirrorSliceLen(r common.Range, items *[]common.Item) error

func (*Node) MustJoin

func (self *Node) MustJoin(addr string)

func (*Node) MustStart

func (self *Node) MustStart() *Node

func (*Node) Next

func (self *Node) Next(data common.Item, result *common.Item) error

func (*Node) NextIndex

func (self *Node) NextIndex(data common.Item, result *common.Item) error

func (*Node) Owned

func (self *Node) Owned() int

Owned returns the number of items, including tombstones, that this node has responsibility for.

func (*Node) Prev

func (self *Node) Prev(data common.Item, result *common.Item) error

func (*Node) PrevIndex

func (self *Node) PrevIndex(data common.Item, result *common.Item) error

func (*Node) Put

func (self *Node) Put(data common.Item) error

func (*Node) ReverseIndexOf

func (self *Node) ReverseIndexOf(data common.Item, result *common.Index) error

func (*Node) ReverseSlice

func (self *Node) ReverseSlice(r common.Range, items *[]common.Item) error

func (*Node) ReverseSliceIndex

func (self *Node) ReverseSliceIndex(r common.Range, items *[]common.Item) error

func (*Node) ReverseSliceLen

func (self *Node) ReverseSliceLen(r common.Range, items *[]common.Item) error

func (*Node) RingHash

func (self *Node) RingHash(x int, ringHash *[]byte) error

func (*Node) SetExpression

func (self *Node) SetExpression(expr setop.SetExpression, items *[]setop.SetOpResult) (err error)

func (*Node) Size

func (self *Node) Size() int

func (*Node) Slice

func (self *Node) Slice(r common.Range, items *[]common.Item) error

func (*Node) SliceIndex

func (self *Node) SliceIndex(r common.Range, items *[]common.Item) error

func (*Node) SliceLen

func (self *Node) SliceLen(r common.Range, items *[]common.Item) error

func (*Node) Start

func (self *Node) Start() (err error)

Start will spin up this dhash.Node, including its discord.Node and timenet.Timer. It will also start the sync, clean and migrate jobs.

func (*Node) Stop

func (self *Node) Stop()

Stop will shut down this dhash.Node, including its discord.Node and timenet.Timer, permanently.

func (*Node) SubAddConfiguration

func (self *Node) SubAddConfiguration(c common.ConfItem)

func (*Node) SubClear

func (self *Node) SubClear(data common.Item) error

func (*Node) SubConfiguration

func (self *Node) SubConfiguration(key []byte, result *common.Conf) error

func (*Node) SubDel

func (self *Node) SubDel(data common.Item) error

func (*Node) SubGet

func (self *Node) SubGet(data common.Item, result *common.Item) error

func (*Node) SubMirrorNext

func (self *Node) SubMirrorNext(data common.Item, result *common.Item) error

func (*Node) SubMirrorPrev

func (self *Node) SubMirrorPrev(data common.Item, result *common.Item) error

func (*Node) SubNext

func (self *Node) SubNext(data common.Item, result *common.Item) error

func (*Node) SubPrev

func (self *Node) SubPrev(data common.Item, result *common.Item) error

func (*Node) SubPut

func (self *Node) SubPut(data common.Item) error

func (*Node) SubSize

func (self *Node) SubSize(key []byte, result *int) error

func (*Node) Time

func (self *Node) Time() time.Time

type Nothing

type Nothing struct{}

type PageRange

type PageRange struct {
	Key     []byte
	From    []byte
	FromInc bool
	Len     int
}

type SubConf

type SubConf struct {
	TreeKey []byte
	Key     string
	Value   string
}

type SubIndex

type SubIndex struct {
	Key   []byte
	Index int
}

type SubKeyOp

type SubKeyOp struct {
	Key    []byte
	SubKey []byte
	Sync   bool
}

type SubKeyReq

type SubKeyReq struct {
	Key    []byte
	SubKey []byte
}

type SubValueIndexRes

type SubValueIndexRes struct {
	Key    []byte
	SubKey []byte
	Value  []byte
	Index  int
	Exists bool
}

type SubValueOp

type SubValueOp struct {
	Key    []byte
	SubKey []byte
	Value  []byte
	Sync   bool
}

type SubValueRes

type SubValueRes struct {
	Key    []byte
	SubKey []byte
	Value  []byte
	Exists bool
}

type SyncListener

type SyncListener func(source, dest common.Remote, pulled, pushed int) (keep bool)

SyncListener is a function listening for sync events where one dhash.Node has pushed items to, and pulled items from, another dhash.Node.

type ValueOp

type ValueOp struct {
	Key   []byte
	Value []byte
	Sync  bool
}

type ValueRes

type ValueRes struct {
	Key    []byte
	Value  []byte
	Exists bool
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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