接着分析memstore中索引的具体实现,它的B+树不是自己实现的,而是引用了一个第三方包,首先我们看下gen.go,它里面其实是运行来Makefile命令
package memstore//go:generate make specify
Makefile文件中下载了实现了B+树的包https://github.com/cznic/b,然后通过正则对其中的interface替换成了int64.
git clone https://github.com/cznic/bcd b && git checkout $(pinned)@sed -e 's|interface{}[^{]*/\*K\*/|int64|g' -e 's|interface{}[^{]*/\*V\*/|\*primitive|g' b/btree.go >keys.go
把b+树代码复制到keys.go文件里
// Keys and their associated values are interface{} typed, similar to all of// the containers in the standard library.$ make generic//// This command will write to stdout a version of the btree.go file where// every key type occurrence is replaced by the word 'key' (written in all// CAPS) and every value type occurrence is replaced by the word 'value'// (written in all CAPS). Then you have to replace these tokens with your// desired type(s), using any technique you're comfortable with.
quadstore.go中对索引定义如下:
type QuadDirectionIndex struct {index [4]map[int64]*Tree}
四元祖对应了4个b+树
func NewQuadDirectionIndex() QuadDirectionIndex {return QuadDirectionIndex{[...]map[int64]*Tree{quad.Subject - 1: make(map[int64]*Tree),quad.Predicate - 1: make(map[int64]*Tree),quad.Object - 1: make(map[int64]*Tree),quad.Label - 1: make(map[int64]*Tree),}}}
func (qdi QuadDirectionIndex) Tree(d quad.Direction, id int64) *Tree {tree, ok := qdi.index[d-1][id]if !ok {tree = TreeNew(cmp)qdi.index[d-1][id] = tree
func (qdi QuadDirectionIndex) Get(d quad.Direction, id int64) (*Tree, bool) {
type primitive struct {ID int64Quad internalQuadValue quad.Valuerefs int}
type internalQuad struct {S, P, O, L int64}
func (q *internalQuad) SetDir(d quad.Direction, n int64) {
func (q internalQuad) Dir(d quad.Direction) int64 {
具体quadstore定义如下:
type QuadStore struct {last int64// TODO: string -> quad.Value once Raw -> typed resolution is unnecessaryvals map[string]int64quads map[internalQuad]int64prim map[int64]*primitiveall []*primitive // might not be sorted by idreading bool // someone else might be reading "all" slice - next insert/delete should clone itindex QuadDirectionIndexhorizon int64 // used only to assign ids to tx// vip_index map[string]map[int64]map[string]map[int64]*b.Tree}
func New(quads ...quad.Quad) *QuadStore {qs := newQuadStore()for _, q := range quads {qs.AddQuad(q)
func newQuadStore() *QuadStore {return &QuadStore{vals: make(map[string]int64),quads: make(map[internalQuad]int64),prim: make(map[int64]*primitive),index: NewQuadDirectionIndex(),
func (qs *QuadStore) addPrimitive(p *primitive) int64 {qs.last++id := qs.lastp.ID = idp.refs = 1qs.appendPrimitive(p)
func (qs *QuadStore) appendPrimitive(p *primitive) {
const internalBNodePrefix = "memnode"
func (qs *QuadStore) resolveVal(v quad.Value, add bool) (int64, bool) {
func (qs *QuadStore) resolveQuad(q quad.Quad, add bool) (internalQuad, bool) {
func (qs *QuadStore) lookupVal(id int64) quad.Value {return quad.BNode(internalBNodePrefix + strconv.FormatInt(id, 10))
func (qs *QuadStore) lookupQuadDirs(p internalQuad) quad.Quad {
func (qs *QuadStore) indexesForQuad(q internalQuad) []*Tree {
func (qs *QuadStore) AddQuad(q quad.Quad) (int64, bool) {
writer定义了如何写入
type quadWriter struct {qs *QuadStore}
func (qs *QuadStore) deleteQuadNodes(q internalQuad) {for dir := quad.Subject; dir <= quad.Label; dir++ {
增量修改
func (qs *QuadStore) ApplyDeltas(deltas []graph.Delta, ignoreOpts graph.IgnoreOpts) error {
func (qs *QuadStore) quad(v graph.Ref) (q internalQuad, ok bool) {switch v := v.(type) {case bnode:p := qs.prim[int64(v)]
func (qs *QuadStore) QuadIterator(d quad.Direction, value graph.Ref) graph.Iterator {id, ok := asID(value)
func (qs *QuadStore) QuadIteratorSize(ctx context.Context, d quad.Direction, v graph.Ref) (graph.Size, error) {id, ok := asID(v)
类似mysql的分析器,也会统计四元祖的一些信息
func (qs *QuadStore) Stats(ctx context.Context, exact bool) (graph.Stats, error) {return graph.Stats{Nodes: graph.Size{
iterator.go里定义了迭代器,是cayley图数据库的核心
var _ graph.Iterator = &Iterator{}
type Iterator struct {it *iterator2graph.Iterator}
func NewIterator(tree *Tree, qs *QuadStore, d quad.Direction, value int64) *Iterator {it := &Iterator{it: newIterator(tree, qs, d, value),}it.Iterator = graph.NewLegacy(it.it, it)
var _ graph.IteratorShapeCompat = &iterator2{}
type iterator2 struct {qs *QuadStoretree *Treed quad.Directionvalue int64}
func newIterator(tree *Tree, qs *QuadStore, d quad.Direction, value int64) *iterator2 {
func (it *iterator2) Iterate() graph.Scanner {// TODO(dennwc): it doesn't check the direction and value, while Contains does; is it expected?return newIteratorNext(it.tree, it.qs, it.d)}
LookUp函数里面会调用contains接口,这个接口会加载满足条件的四元祖
func (it *iterator2) Lookup() graph.Index {return newIteratorContains(it.tree, it.qs, it.d, it.value)}
func (it *iterator2) AsLegacy() graph.Iterator {it2 := &Iterator{it: it}it2.Iterator = graph.NewLegacy(it, it2)
func (it *iterator2) Stats(ctx context.Context) (graph.IteratorCosts, error) {return graph.IteratorCosts{
type iteratorNext struct {nodes boolqs *QuadStoretree *Treed quad.Directioniter *Enumeratorcur *primitiveerr error}
func newIteratorNext(tree *Tree, qs *QuadStore, d quad.Direction) *iteratorNext {return &iteratorNext{
next会查找下一组节点:
func (it *iteratorNext) Next(ctx context.Context) bool {if it.iter == nil {it.iter, it.err = it.tree.SeekFirst()for {_, p, err := it.iter.Next()
type iteratorContains struct {nodes boolqs *QuadStoretree *Treecur *primitived quad.Directionvalue int64}
func newIteratorContains(tree *Tree, qs *QuadStore, d quad.Direction, value int64) *iteratorContains {
func (it *iteratorContains) Contains(ctx context.Context, v graph.Ref) bool {
all_iterator.go
var _ graph.IteratorFuture = (*AllIterator)(nil)
type AllIterator struct {it *allIteratorgraph.Iterator}
func newAllIterator(qs *QuadStore, nodes bool, maxid int64) *AllIterator {it := &AllIterator{it: newAllIterator2(qs, nodes, maxid),}it.Iterator = graph.NewLegacy(it.it, it)
func (it *AllIterator) AsShape() graph.IteratorShape {
var _ graph.IteratorShape = (*allIterator)(nil)
type allIterator struct {qs *QuadStoreall []*primitivemaxid int64 id of last observed insert (prim id)nodes bool}
func newAllIterator2(qs *QuadStore, nodes bool, maxid int64) *allIterator {
func (it *allIterator) Iterate() graph.Scanner {return newAllIteratorNext(it.qs, it.nodes, it.maxid, it.all)
func (it *allIterator) Lookup() graph.Index {
func (it *allIterator) AsLegacy() graph.Iterator {
还有子迭代器
func (it *allIterator) SubIterators() []graph.IteratorShape { return nil }
func (it *allIterator) Optimize(ctx context.Context) (graph.IteratorShape, bool) {
func (it *allIterator) String() string {
func (it *allIterator) Stats(ctx context.Context) (graph.IteratorCosts, error) {
func (p *primitive) filter(isNode bool, maxid int64) bool {
type allIteratorNext struct {qs *QuadStoreall []*primitivemaxid int64 id of last observed insert (prim id)nodes booli int // index into qs.allcur *primitivedone bool}
func newAllIteratorNext(qs *QuadStore, nodes bool, maxid int64, all []*primitive) *allIteratorNext {
func (it *allIteratorNext) ok(p *primitive) bool {return p.filter(it.nodes, it.maxid)
func (it *allIteratorNext) Next(ctx context.Context) bool {for ; it.i < len(all); it.i++ {p := all[it.i]if p.ID > it.maxid {break}if it.ok(p) {it.cur = preturn true}}
func (it *allIteratorNext) Result() graph.Ref {
type allIteratorContains struct {qs *QuadStoremaxid int64 // id of last observed insert (prim id)nodes boolcur *primitivedone bool}
func newAllIteratorContains(qs *QuadStore, nodes bool, maxid int64) *allIteratorContains {
func (it *allIteratorContains) ok(p *primitive) bool {
func (it *allIteratorContains) Contains(ctx context.Context, v graph.Ref) bool {
func (it *allIteratorContains) Result() graph.Ref {
func (it *allIteratorContains) NextPath(ctx context.Context) bool { return false }


文章转载自golang算法架构leetcode技术php,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




