// Copyright (C) 2019 Nexedi SA and Contributors. // Kirill Smelkov <kirr@nexedi.com> // // This program is free software: you can Use, Study, Modify and Redistribute // it under the terms of the GNU General Public License version 3, or (at your // option) any later version, as published by the Free Software Foundation. // // You can also Link and Combine this program with other software covered by // the terms of any of the Free Software licenses or any of the Open Source // Initiative approved licenses and Convey the resulting work. Corresponding // source of such a combination shall include the source code for all other // software used. // // This program is distributed WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // // See COPYING file for full licensing terms. // See https://www.nexedi.com/licensing for rationale and options. package main // ΔFtail - merge btree.ΔTail with history of ZBlk import ( "lab.nexedi.com/kirr/neo/go/zodb" "lab.nexedi.com/kirr/neo/go/zodb/btree" "./internal/xbtree" ) // ΔFTail is like btree.ΔTail but additionally tracks tree-root -> file relation and // takes ZBlk history into account. type ΔFTail struct { *xbtree.ΔTail fileIdx map[*btree.LOBTree]SetBigFile // root -> {} BigFile XXX root -> oid? } type ΔFentry struct { Rev zodb.Tid Changev []ΔFile } type ΔFile struct { File *BigFile Blkv []int64 } func NewΔFTail(at0 zodb.Tid) *ΔFTail { return &ΔFTail{ ΔTail: xbtree.NewΔTail(at0), fileIdx: make(map[*btree.LOBTree]SetBigFile), } } // Track adds tree path to tracked set and associates path root with file. // // A root can be associated with several files (each provided on different Track call). func (δf *ΔFTail) Track(file *BigFile, path []btree.LONode) { δf.ΔTail.Track(path) root := path[0].(*btree.LOBTree) files, ok := δf.fileIdx[root] if !ok { files = SetBigFile{} δf.fileIdx[root] = files } files.Add(file) } // XXX func (δf *ΔFTail) Update(δZ *zodb.EventCommit) ΔFentry { δB := δf.ΔTail.Update(δZ) var changev []ΔFile // δB.Changev root -> file (via .fileIdx) for _, δ := range δB.Changev { files := δf.fileIdx[δ.Root] if len(files) == 0 { panicf("ΔFTail: root<%s> -> ø file", δ.Root.POid()) } for file := range files { changev = append(changev, ΔFile{ File: file, Blkv: δ.Keyv, }) } } return ΔFentry{ Rev: δB.Rev, Changev: changev, } } // LastRevOf return last_rev file[blk] @at XXX // // XXX -> merge into ZBigFile.LoadBlk? // XXX ZBigFile.LoadBlk(blk) -> blkdata, rev // // XXX no - cannot merge - f.LastBlkRev is used for both @head (where we have // zblk.rev) and for @w.at, where we don't have zblk.rev because we was not // handling load and just need to pin watcher with the result. func (δf *ΔFTail) LastRevOf(file *BigFile, blk int64, at zodb.Tid) (_ zodb.Tid, exact bool) { // revision of when blktab[blk] entry changed last. treeKeyRev, exact := δf.ΔTail.LastRevOf(file.zfile.blktab, blk, at) // XXX activate? // blktab[blk] is only a pointer (to ZBlk) and ZBlk could itself have // been changing after treeKeyRev. We have to check for that. panic("TODO") }