mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 00:55:55 +00:00
We switch everything to use QueryContext/QueryRead/etc instead of Qcx/Tx. We drop the short_txkey subpackage (it's now handled by either keys or querycontext). We drop all the dbshard stuff, and all the tx/txfactory stuff. We remove all the things that related to the old "Block" concept, which was mostly used by the anti-entropy code, but had one fragmentary usage left in the ImportRoaringOverwrite case of ImportRoaring. That's replaced by using a rewriter that deletes all bits (not just bits in specific columns) from an existing thing, but writes in new bits. Actually we could probably do that better with a custom "eradicate-rewriter" that doesn't try to be clever, and just eliminates things. This includes a number of minor bug fixes that were exposed by getting the testing to work. For example: * When checking whether an operation "requires write", we now consider a Delete a kind of a Write, because it is. * Several tests were relying on the fact that writes through Qcx were being committed whether or not the Qcx was ever told to finish. With QueryContext, you actually have to reach a Commit() or the writes don't happen (except for special cases in Delete). * Replaced a lot of panics with t.Fatalf in tests. There's also some minor staticcheck fixes, like deleting the unused "db" member of a boltdb transaction wrapper.
219 lines
5.9 KiB
Go
219 lines
5.9 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package rbf
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/molecula/featurebase/v3/vprint"
|
|
)
|
|
|
|
// we don't currently use dumpAllPages but it's tricky enough to get right
|
|
// that it's probably worth keeping as a debugging tool.
|
|
var _ = (*Tx).dumpAllPages
|
|
|
|
func (tx *Tx) dumpAllPages(showLeaves bool) error {
|
|
|
|
infos, err := tx.PageInfos()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Write header.
|
|
fmt.Printf("Pgno ")
|
|
fmt.Printf("TYPE ")
|
|
spc := strings.Repeat(" ", 29)
|
|
fmt.Printf("TREE " + spc)
|
|
fmt.Printf("EXTRA\n")
|
|
|
|
fmt.Printf("======== ")
|
|
fmt.Printf("========== ")
|
|
fmt.Printf("============================== " + spc)
|
|
fmt.Printf("====================\n")
|
|
|
|
// Print one line for each page.
|
|
for pgno, info := range infos {
|
|
switch info := info.(type) {
|
|
case *MetaPageInfo:
|
|
fmt.Printf("Pgno:%-8d ", pgno)
|
|
fmt.Printf("%-10s ", "meta")
|
|
fmt.Printf("%-54s ", "")
|
|
fmt.Printf("pageN=%d,walid=%d,rootrec=%d,freelist=%d\n", info.PageN, info.WALID, info.RootRecordPageNo, info.FreelistPageNo)
|
|
|
|
case *RootRecordPageInfo:
|
|
fmt.Printf("Pgno:%-8d ", pgno)
|
|
fmt.Printf("%-10s ", "rootrec")
|
|
fmt.Printf("%-54s ", "")
|
|
fmt.Printf("next=%d\n", info.Next)
|
|
|
|
page, _, err := tx.readPage(uint32(pgno))
|
|
vprint.PanicOn(err)
|
|
rootRecords, err := readRootRecords(page)
|
|
vprint.PanicOn(err)
|
|
for k, rr := range rootRecords {
|
|
fmt.Printf(" [%02v] Name:'%v' pgno:%v\n", k, PrefixToString(rr.Name), rr.Pgno)
|
|
}
|
|
|
|
case *LeafPageInfo:
|
|
if !showLeaves {
|
|
continue
|
|
}
|
|
fmt.Printf("Pgno:%-8d ", pgno)
|
|
fmt.Printf("%-10s ", "leaf")
|
|
fmt.Printf("%-54q ", PrefixToString(info.Tree))
|
|
fmt.Printf("flags=x%x,celln=%d\n", info.Flags, info.CellN)
|
|
|
|
page, _, err := tx.readPage(uint32(pgno))
|
|
vprint.PanicOn(err)
|
|
|
|
var leafCells [PageSize / 8]leafCell
|
|
cells := readLeafCells(page, leafCells[:])
|
|
for k, cell := range cells {
|
|
fmt.Printf(" [%02v] : (container)Key:%v Type:%v BitN:%v len(Data):%v\n", k, cell.Key, cell.Type, cell.BitN, len(cell.Data))
|
|
}
|
|
|
|
case *BranchPageInfo:
|
|
fmt.Printf("Pgno:%-8d ", pgno)
|
|
fmt.Printf("%-10s ", "branch")
|
|
fmt.Printf("%-54q ", PrefixToString(info.Tree))
|
|
fmt.Printf("flags=x%x,celln=%d\n", info.Flags, info.CellN)
|
|
|
|
page, _, err := tx.readPage(uint32(pgno))
|
|
vprint.PanicOn(err)
|
|
|
|
cells := readBranchCells(page)
|
|
for i, cell := range cells {
|
|
fmt.Printf(" [%02v] : (ChildPages's smallest) Key:%05v -> (Child) pgno:%v\n", i, cell.LeftKey, cell.ChildPgno)
|
|
}
|
|
|
|
case *BitmapPageInfo:
|
|
fmt.Printf("Pgno:%-8d ", pgno)
|
|
fmt.Printf("%-10s ", "bitmap")
|
|
fmt.Printf("%-54q ", PrefixToString(info.Tree))
|
|
fmt.Printf("-\n")
|
|
|
|
case *FreePageInfo:
|
|
fmt.Printf("Pgno:%-8d ", pgno)
|
|
fmt.Printf("%-10s ", "free")
|
|
fmt.Printf("%-54s ", "")
|
|
fmt.Printf("-\n")
|
|
|
|
case nil:
|
|
fmt.Printf("Pgno:%-8d ", pgno)
|
|
fmt.Printf("%-10s ", "<nil> problem, corrupt page set")
|
|
fmt.Printf("%-54s ", "")
|
|
fmt.Printf("-\n")
|
|
|
|
default:
|
|
panic(fmt.Sprintf("unexpected page info type %T at pgno %v", info, pgno))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (tx *Tx) dumpPages(pgnos []uint32) error {
|
|
// Fetch the page.
|
|
pages, err := tx.Pages(pgnos)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, page := range pages {
|
|
switch page := page.(type) {
|
|
case *MetaPage:
|
|
printMetaPage(page)
|
|
case *RootRecordPage:
|
|
printRootRecordPage(page)
|
|
case *LeafPage:
|
|
printLeafPage(page)
|
|
case *BranchPage:
|
|
printBranchPage(page)
|
|
case *BitmapPage:
|
|
printBitmapPage(page)
|
|
case *FreePage:
|
|
printFreePage(page)
|
|
default:
|
|
return fmt.Errorf("unexpected page type %T", page)
|
|
}
|
|
fmt.Printf("\n")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var _ = (&Tx{}).dumpPages
|
|
|
|
func printMetaPage(page *MetaPage) {
|
|
fmt.Printf("Pgno: %d\n", page.Pgno)
|
|
fmt.Printf("Type: meta\n")
|
|
fmt.Printf("PageN: %d\n", page.PageN)
|
|
fmt.Printf("WALID: %d\n", page.WALID)
|
|
fmt.Printf("Root Record Pgno: %d\n", page.RootRecordPageNo)
|
|
fmt.Printf("Freelist Pgno: %d\n", page.FreelistPageNo)
|
|
}
|
|
|
|
func printRootRecordPage(page *RootRecordPage) {
|
|
fmt.Printf("Pgno: %d\n", page.Pgno)
|
|
fmt.Printf("Type: root record\n")
|
|
fmt.Printf("Next: %d\n", page.Next)
|
|
fmt.Printf("Records: n=%d\n", len(page.Records))
|
|
for i, rec := range page.Records {
|
|
fmt.Printf("[%d]: name=%q pgno=%d\n", i, rec.Name, rec.Pgno)
|
|
}
|
|
}
|
|
|
|
func printLeafPage(page *LeafPage) {
|
|
fmt.Printf("Pgno: %d\n", page.Pgno)
|
|
fmt.Printf("Type: leaf\n")
|
|
fmt.Printf("Cells: n=%d\n", len(page.Cells))
|
|
for i, cell := range page.Cells {
|
|
if cell.Type == ContainerTypeBitmapPtr {
|
|
fmt.Printf("[%d]: ckey=%d type=%s pgno=%d\n", i, cell.Key, cell.Type, cell.Pgno)
|
|
} else {
|
|
fmt.Printf("[%d]: ckey=%d type=%s values=%v\n", i, cell.Key, cell.Type, cell.Values)
|
|
}
|
|
}
|
|
}
|
|
|
|
func printBranchPage(page *BranchPage) {
|
|
fmt.Printf("Pgno: %d\n", page.Pgno)
|
|
fmt.Printf("Type: branch\n")
|
|
fmt.Printf("Cells: n=%d\n", len(page.Cells))
|
|
for i, cell := range page.Cells {
|
|
fmt.Printf("[%d]: ckey=%d flags=%d pgno=%d\n", i, cell.Key, cell.Flags, cell.Pgno)
|
|
}
|
|
}
|
|
|
|
func printBitmapPage(page *BitmapPage) {
|
|
fmt.Printf("Pgno: %d\n", page.Pgno)
|
|
fmt.Printf("Type: bitmap\n")
|
|
fmt.Printf("Values: %v\n", page.Values)
|
|
}
|
|
|
|
func printFreePage(page *FreePage) {
|
|
fmt.Printf("Pgno: %d\n", page.Pgno)
|
|
fmt.Printf("Type: free\n")
|
|
}
|
|
|
|
// PrefixToString converts a fragment key (used to denote
|
|
// a root bitmap in an RBF file) into a description of it
|
|
// suitable for printing. This behavior reflects the
|
|
// historical practice of the short_txkey package, which
|
|
// we no longer have. It's exported because the rbf_pages
|
|
// command wants to use it to display things.
|
|
func PrefixToString(s string) (ret string) {
|
|
var field, view string
|
|
n, err := fmt.Sscanf(s, "~%s;%s<", &field, &view)
|
|
if err != nil || n != 2 {
|
|
return s
|
|
}
|
|
return fmt.Sprintf("field:%s;view:%s", field, view)
|
|
}
|
|
|
|
///////////////// happy linter
|
|
|
|
var _ = printMetaPage
|
|
var _ = printRootRecordPage
|
|
var _ = printLeafPage
|
|
var _ = printBranchPage
|
|
var _ = printBitmapPage
|
|
var _ = printFreePage
|