mirror of https://github.com/etcd-io/bbolt.git
Add 'bolt pages'.
parent
8fa6531b1c
commit
0e4d77d424
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
@ -30,6 +31,11 @@ func NewApp() *cli.App {
|
||||||
Usage: "retrieve a list of all keys in a bucket",
|
Usage: "retrieve a list of all keys in a bucket",
|
||||||
Action: KeysCommand,
|
Action: KeysCommand,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "pages",
|
||||||
|
Usage: "dump page information for a database",
|
||||||
|
Action: PagesCommand,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return app
|
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 logger = log.New(os.Stderr, "", 0)
|
||||||
var logBuffer *bytes.Buffer
|
var logBuffer *bytes.Buffer
|
||||||
|
|
||||||
|
|
17
freelist.go
17
freelist.go
|
@ -70,6 +70,23 @@ func (f *freelist) release(txid txid) {
|
||||||
sort.Sort(reverseSortedPgids(f.ids))
|
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.
|
// read initializes the freelist from a freelist page.
|
||||||
func (f *freelist) read(p *page) {
|
func (f *freelist) read(p *page) {
|
||||||
ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0:p.count]
|
ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0:p.count]
|
||||||
|
|
8
page.go
8
page.go
|
@ -119,3 +119,11 @@ func (n *leafPageElement) value() []byte {
|
||||||
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
||||||
return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize]
|
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
27
tx.go
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue