Add 'bolt pages'.

master
Ben Johnson 2014-03-21 22:34:54 -06:00
parent 8fa6531b1c
commit 0e4d77d424
4 changed files with 97 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import (
"bytes"
"log"
"os"
"strconv"
"github.com/boltdb/bolt"
"github.com/codegangsta/cli"
@ -30,6 +31,11 @@ func NewApp() *cli.App {
Usage: "retrieve a list of all keys in a bucket",
Action: KeysCommand,
},
{
Name: "pages",
Usage: "dump page information for a database",
Action: PagesCommand,
},
}
return app
}
@ -108,6 +114,45 @@ func KeysCommand(c *cli.Context) {
}
}
// PagesCommand prints a list of all pages in a database.
func PagesCommand(c *cli.Context) {
path := c.Args().Get(0)
if _, err := os.Stat(path); os.IsNotExist(err) {
fatal(err)
return
}
db, err := bolt.Open(path, 0600)
if err != nil {
fatal(err)
return
}
defer db.Close()
logger.Println("ID TYPE ITEMS OVRFLW")
logger.Println("======== ========== ====== ======")
db.Do(func(tx *bolt.Tx) error {
var id int
for {
p, err := tx.Page(id)
if err != nil {
fatalf("page error: %d: %s", id, err)
} else if p == nil {
break
}
var overflow string
if p.OverflowCount > 0 {
overflow = strconv.Itoa(p.OverflowCount)
}
logger.Printf("%-8d %-10s %-6d %-6s", p.ID, p.Type, p.Count, overflow)
id += 1 + p.OverflowCount
}
return nil
})
}
var logger = log.New(os.Stderr, "", 0)
var logBuffer *bytes.Buffer

View File

@ -70,6 +70,23 @@ func (f *freelist) release(txid txid) {
sort.Sort(reverseSortedPgids(f.ids))
}
// isFree returns whether a given page is in the free list.
func (f *freelist) isFree(pgid pgid) bool {
for _, id := range f.ids {
if id == pgid {
return true
}
}
for _, m := range f.pending {
for _, id := range m {
if id == pgid {
return true
}
}
}
return false
}
// read initializes the freelist from a freelist page.
func (f *freelist) read(p *page) {
ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0:p.count]

View File

@ -119,3 +119,11 @@ func (n *leafPageElement) value() []byte {
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize]
}
// PageInfo represents human readable information about a page.
type PageInfo struct {
ID int
Type string
Count int
OverflowCount int
}

27
tx.go
View File

@ -420,3 +420,30 @@ func (t *Tx) forEachPage(pgid pgid, depth int, fn func(*page, int)) {
}
}
}
// Page returns page information for a given page number.
// This is only available from writable transactions.
func (t *Tx) Page(id int) (*PageInfo, error) {
if !t.writable {
return nil, ErrTxNotWritable
} else if pgid(id) >= t.meta.pgid {
return nil, nil
}
// Build the page info.
p := t.page(pgid(id))
info := &PageInfo{
ID: id,
Count: int(p.count),
OverflowCount: int(p.overflow),
}
// Determine the type (or if it's free).
if t.db.freelist.isFree(pgid(id)) {
info.Type = "free"
} else {
info.Type = p.typ()
}
return info, nil
}