aboutsummaryrefslogtreecommitdiff
path: root/src/dedo.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/dedo.go')
-rw-r--r--src/dedo.go1354
1 files changed, 682 insertions, 672 deletions
diff --git a/src/dedo.go b/src/dedo.go
index 73b6604..ad6ef15 100644
--- a/src/dedo.go
+++ b/src/dedo.go
@@ -24,18 +24,657 @@ import (
"strconv"
"unicode"
"unicode/utf8"
+
+ g "gobang"
)
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0xFFFFFFFFFFFF // 256TB
+type pgid uint64
+
+// bucket represents the on-file representation of a bucket.
+// This is stored as the "value" of a bucket key. If the bucket is small enough,
+// then its root page can be stored inline in the "value", after the bucket
+// header. In the case of inline buckets, the "root" will be 0.
+type bucket struct {
+ root pgid // page id of the bucket's root-level page
+ sequence uint64 // monotonically incrementing, used by NextSequence()
+}
+
+// Bucket represents a distinct collection of key/value pairs inside the
+// database. Keys aren't unique across different buckets.
+type Bucket struct {
+ ref *bucket
+ tx *Tx // the associated transaction
+ buckets map[string]*Bucket // subbucket cache
+ page *page // inline page reference
+ rootNode *node // materialized node for the root page.
+ nodes map[pgid]*node // node cache
+
+ // Sets the threshold for filling nodes when they split. By default,
+ // the bucket will fill to 50% but it can be useful to increase this
+ // amount if you know that your write workloads are mostly append-only.
+ //
+ // This is non-persisted across transactions so it must be set in every Tx.
+ FillPercent float64
+}
+
+// BucketStats records statistics about resources used by a bucket.
+type BucketStats struct {
+ // Page count statistics.
+ BranchPageN int // number of logical branch pages
+ BranchOverflowN int // number of physical branch overflow pages
+ LeafPageN int // number of logical leaf pages
+ LeafOverflowN int // number of physical leaf overflow pages
+
+ // Tree statistics.
+ KeyN int // number of keys/value pairs
+ Depth int // number of levels in B+tree
+
+ // Page size utilization.
+ BranchAlloc int // bytes allocated for physical branch pages
+ BranchInuse int // bytes actually used for branch data
+ LeafAlloc int // bytes allocated for physical leaf pages
+ LeafInuse int // bytes actually used for leaf data
+
+ // Bucket statistics
+ BucketN int // total number of buckets including the top bucket
+ InlineBucketN int // total number on inlined buckets
+ InlineBucketInuse int // bytes used for inlined buckets (also accounted for in LeafInuse)
+}
+
+// Cursor represents an iterator that can traverse over all key/value pairs in a bucket in sorted order.
+// Cursors see nested buckets with value == nil.
+// Cursors can be obtained from a transaction and are valid as long as the transaction is open.
+//
+// Keys and values returned from the cursor are only valid for the life of the transaction.
+//
+// Changing data while traversing with a cursor may cause it to be invalidated
+// and return unexpected keys and/or values. You must reposition your cursor
+// after mutating data.
+type Cursor struct {
+ bucket *Bucket
+ stack []elemRef
+}
+
+// elemRef represents a reference to an element on a given page/node.
+type elemRef struct {
+ page *page
+ node *node
+ index int
+}
+
+// DB represents a collection of buckets persisted to a file on disk.
+// All data access is performed through transactions which can be obtained through the DB.
+// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
+type DB struct {
+ // When enabled, the database will perform a Check() after every commit.
+ // A panic is issued if the database is in an inconsistent state. This
+ // flag has a large performance impact so it should only be used for
+ // debugging purposes.
+ StrictMode bool
+
+ // If you want to read the entire database fast, you can set MmapFlag to
+ // syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead.
+ MmapFlags int
+
+ // MaxBatchSize is the maximum size of a batch. Default value is
+ // copied from DefaultMaxBatchSize in Open.
+ //
+ // If <=0, disables batching.
+ //
+ // Do not change concurrently with calls to Batch.
+ MaxBatchSize int
+
+ // MaxBatchDelay is the maximum delay before a batch starts.
+ // Default value is copied from DefaultMaxBatchDelay in Open.
+ //
+ // If <=0, effectively disables batching.
+ //
+ // Do not change concurrently with calls to Batch.
+ MaxBatchDelay time.Duration
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0x7FFFFFFF
+ // AllocSize is the amount of space allocated when the database
+ // needs to create new pages. This is done to amortize the cost
+ // of truncate() and fsync() when growing the data file.
+ AllocSize int
+
+ path string
+ file *os.File
+ lockfile *os.File // windows only
+ dataref []byte // mmap'ed readonly, write throws SEGV
+ data *[maxMapSize]byte
+ datasz int
+ filesz int // current on disk file size
+ meta0 *meta
+ meta1 *meta
+ pageSize int
+ opened bool
+ rwtx *Tx
+ txs []*Tx
+ freelist *freelist
+ stats Stats
+
+ pagePool sync.Pool
+
+ batchMu sync.Mutex
+ batch *batch
+
+ rwlock sync.Mutex // Allows only one writer at a time.
+ metalock sync.Mutex // Protects meta page access.
+ mmaplock sync.RWMutex // Protects mmap access during remapping.
+ statlock sync.RWMutex // Protects stats access.
+
+ ops struct {
+ writeAt func(b []byte, off int64) (n int, err error)
+ }
+
+ // Read only mode.
+ // When true, Update() and Begin(true) return ErrDatabaseReadOnly immediately.
+ readOnly bool
+}
+
+type call struct {
+ fn func(*Tx) error
+ err chan<- error
+}
+
+type batch struct {
+ db *DB
+ timer *time.Timer
+ start sync.Once
+ calls []call
+}
+
+type panicked struct {
+ reason interface{}
+}
+
+// Options represents the options that can be set when opening a database.
+type Options struct {
+ // Timeout is the amount of time to wait to obtain a file lock.
+ // When set to zero it will wait indefinitely. This option is only
+ // available on Darwin and Linux.
+ Timeout time.Duration
+
+ // Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to
+ // grab a shared lock (UNIX).
+ ReadOnly bool
+
+ // Sets the DB.MmapFlags flag before memory mapping the file.
+ MmapFlags int
+
+ // InitialMmapSize is the initial mmap size of the database
+ // in bytes. Read transactions won't block write transaction
+ // if the InitialMmapSize is large enough to hold database mmap
+ // size. (See DB.Begin for more information)
+ //
+ // If <=0, the initial map size is 0.
+ // If initialMmapSize is smaller than the previous database size,
+ // it takes no effect.
+ InitialMmapSize int
+}
+
+// Stats represents statistics about the database.
+type Stats struct {
+ // Freelist stats
+ FreePageN int // total number of free pages on the freelist
+ PendingPageN int // total number of pending pages on the freelist
+ FreeAlloc int // total bytes allocated in free pages
+ FreelistInuse int // total bytes used by the freelist
+
+ // Transaction stats
+ TxN int // total number of started read transactions
+ OpenTxN int // number of currently open read transactions
+
+ TxStats TxStats // global, ongoing stats.
+}
+
+type Info struct {
+ Data uintptr
+ PageSize int
+}
+
+type meta struct {
+ magic uint32
+ version uint32
+ pageSize uint32
+ flags uint32
+ root bucket
+ freelist pgid
+ pgid pgid
+ txid txid
+ checksum uint64
+}
+
+// freelist represents a list of all pages that are available for allocation.
+// It also tracks pages that have been freed but are still in use by open transactions.
+type freelist struct {
+ ids []pgid // all free and available free page ids.
+ pending map[txid][]pgid // mapping of soon-to-be free page ids by tx.
+ cache map[pgid]bool // fast lookup of all free and pending page ids.
+}
+
+// node represents an in-memory, deserialized page.
+type node struct {
+ bucket *Bucket
+ isLeaf bool
+ unbalanced bool
+ spilled bool
+ key []byte
+ pgid pgid
+ parent *node
+ children nodes
+ inodes inodes
+}
+
+type nodes []*node
+
+type pages []*page
+
+// inode represents an internal node inside of a node.
+// It can be used to point to elements in a page or point
+// to an element which hasn't been added to a page yet.
+type inode struct {
+ flags uint32
+ pgid pgid
+ key []byte
+ value []byte
+}
+
+type inodes []inode
+
+type page struct {
+ id pgid
+ flags uint16
+ count uint16
+ overflow uint32
+ ptr uintptr
+}
+
+// branchPageElement represents a node on a branch page.
+type branchPageElement struct {
+ pos uint32
+ ksize uint32
+ pgid pgid
+}
+
+// leafPageElement represents a node on a leaf page.
+type leafPageElement struct {
+ flags uint32
+ pos uint32
+ ksize uint32
+ vsize uint32
+}
+
+// PageInfo represents human readable information about a page.
+type PageInfo struct {
+ ID int
+ Type string
+ Count int
+ OverflowCount int
+}
+
+type pgids []pgid
+
+// txid represents the internal transaction identifier.
+type txid uint64
+
+// Tx represents a read-only or read/write transaction on the database.
+// Read-only transactions can be used for retrieving values for keys and creating cursors.
+// Read/write transactions can create and remove buckets and create and remove keys.
+//
+// IMPORTANT: You must commit or rollback transactions when you are done with
+// them. Pages can not be reclaimed by the writer until no more transactions
+// are using them. A long running read transaction can cause the database to
+// quickly grow.
+type Tx struct {
+ writable bool
+ managed bool
+ db *DB
+ meta *meta
+ root Bucket
+ pages map[pgid]*page
+ stats TxStats
+ commitHandlers []func()
+
+ // WriteFlag specifies the flag for write-related methods like WriteTo().
+ // Tx opens the database file with the specified flag to copy the data.
+ //
+ // By default, the flag is unset, which works well for mostly in-memory
+ // workloads. For databases that are much larger than available RAM,
+ // set the flag to syscall.O_DIRECT to avoid trashing the page cache.
+ WriteFlag int
+}
+
+// TxStats represents statistics about the actions performed by the transaction.
+type TxStats struct {
+ // Page statistics.
+ PageCount int // number of page allocations
+ PageAlloc int // total bytes allocated
+
+ // Cursor statistics.
+ CursorCount int // number of cursors created
+
+ // Node statistics
+ NodeCount int // number of node allocations
+ NodeDeref int // number of node dereferences
+
+ // Rebalance statistics.
+ Rebalance int // number of node rebalances
+ RebalanceTime time.Duration // total time spent rebalancing
+
+ // Split/Spill statistics.
+ Split int // number of nodes split
+ Spill int // number of nodes spilled
+ SpillTime time.Duration // total time spent spilling
+
+ // Write statistics.
+ Write int // number of writes performed
+ WriteTime time.Duration // total time spent writing to disk
+}
+
+// Main represents the main program execution.
+type MainT struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// CheckCommand represents the "check" command execution.
+type CheckCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// InfoCommand represents the "info" command execution.
+type InfoCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// DumpCommand represents the "dump" command execution.
+type DumpCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// PageCommand represents the "page" command execution.
+type PageCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// PagesCommand represents the "pages" command execution.
+type PagesCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// StatsCommand represents the "stats" command execution.
+type StatsCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// BenchCommand represents the "bench" command execution.
+type BenchCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+}
+
+// BenchOptions represents the set of options that can be passed to "bolt bench".
+type BenchOptions struct {
+ ProfileMode string
+ WriteMode string
+ ReadMode string
+ Iterations int
+ BatchSize int
+ KeySize int
+ ValueSize int
+ CPUProfile string
+ MemProfile string
+ BlockProfile string
+ StatsInterval time.Duration
+ FillPercent float64
+ Work bool
+ Path string
+}
+
+// BenchResults represents the performance results of the benchmark.
+type BenchResults struct {
+ WriteOps int
+ WriteDuration time.Duration
+ ReadOps int
+ ReadDuration time.Duration
+}
+
+type PageError struct {
+ ID int
+ Err error
+}
+
+// CompactCommand represents the "compact" command execution.
+type CompactCommand struct {
+ Stdin io.Reader
+ Stdout io.Writer
+ Stderr io.Writer
+
+ SrcPath string
+ DstPath string
+ TxMaxSize int64
+}
+
+// walkFunc is the type of the function called for keys (buckets and "normal"
+// values) discovered by Walk. keys is the list of keys to descend to the bucket
+// owning the discovered key/value pair k/v.
+type walkFunc func(keys [][]byte, k, v []byte, seq uint64) error
+
+
+
+const (
+ // maxMapSize represents the largest mmap size supported by Bolt.
+ maxMapSize = 0xFFFFFFFFFFFF // 256TB
+
+ // maxAllocSize is the size used when creating array pointers.
+ maxAllocSize = 0x7FFFFFFF
+
+ // MaxKeySize is the maximum length of a key, in bytes.
+ MaxKeySize = 32768
+
+ // MaxValueSize is the maximum length of a value, in bytes.
+ MaxValueSize = (1 << 31) - 2
+
+ maxUint = ^uint(0) // FIXME: 64?
+ minUint = 0
+ maxInt = int(^uint(0) >> 1)
+ minInt = (-maxInt) - 1
+
+ bucketHeaderSize = int(unsafe.Sizeof(bucket{}))
+
+ minFillPercent = 0.1
+ maxFillPercent = 1.0
+
+ // DefaultFillPercent is the percentage that split pages are filled.
+ // This value can be changed by setting Bucket.FillPercent.
+ DefaultFillPercent = 0.5
+
+ // The largest step that can be taken when remapping the mmap.
+ maxMmapStep = 1 << 30 // 1GB
+
+ // The data file format version.
+ version = 2
+
+ // Represents a marker value to indicate that a file is a Bolt DB.
+ magic uint32 = 0xED0CDAED
+
+ // Default values if not set in a DB instance.
+ DefaultMaxBatchSize int = 1000
+ DefaultMaxBatchDelay = 10 * time.Millisecond
+ DefaultAllocSize = 16 * 1024 * 1024
+
+ pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr))
+
+ minKeysPerPage = 2
+
+ branchPageElementSize = int(unsafe.Sizeof(branchPageElement{}))
+ leafPageElementSize = int(unsafe.Sizeof(leafPageElement{}))
+
+ branchPageFlag = 0x01
+ leafPageFlag = 0x02
+ metaPageFlag = 0x04
+ freelistPageFlag = 0x10
+
+ bucketLeafFlag = 0x01
+
+ // PageHeaderSize represents the size of the bolt.page header.
+ PageHeaderSize = 16
+)
+
+var (
+ // default page size for db is set to the OS page size.
+ defaultPageSize = os.Getpagesize()
+
+ // Are unaligned load/stores broken on this arch?
+ brokenUnaligned = false
+
+ // trySolo is a special sentinel error value used for signaling that a
+ // transaction function should be re-run. It should never be seen by
+ // callers.
+ trySolo = errors.New("batch function returned an error and should be re-run solo")
+
+ // DefaultOptions represent the options used if nil options are passed into Open().
+ // No timeout is used which will cause Bolt to wait indefinitely for a lock.
+ DefaultOptions = &Options{
+ Timeout: 0,
+ }
+
+
+ //
+ // These errors can be returned when opening or calling methods on a DB.
+ //
+
+ // ErrDatabaseNotOpen is returned when a DB instance is accessed before it
+ // is opened or after it is closed.
+ ErrDatabaseNotOpen = errors.New("database not open")
+
+ // ErrDatabaseOpen is returned when opening a database that is
+ // already open.
+ ErrDatabaseOpen = errors.New("database already open")
+
+ // ErrInvalid is returned when both meta pages on a database are invalid.
+ // This typically occurs when a file is not a bolt database.
+ ErrInvalid = errors.New("invalid database")
+
+ // ErrVersionMismatch is returned when the data file was created with a
+ // different version of Bolt.
+ ErrVersionMismatch = errors.New("version mismatch")
+
+ // ErrChecksum is returned when either meta page checksum does not match.
+ ErrChecksum = errors.New("checksum error")
+
+ // ErrTimeout is returned when a database cannot obtain an exclusive lock
+ // on the data file after the timeout passed to Open().
+ ErrTimeout = errors.New("timeout")
+
+
+ //
+ // These errors can occur when beginning or committing a Tx.
+ //
+
+ // ErrTxNotWritable is returned when performing a write operation on a
+ // read-only transaction.
+ ErrTxNotWritable = errors.New("tx not writable")
+
+ // ErrTxClosed is returned when committing or rolling back a transaction
+ // that has already been committed or rolled back.
+ ErrTxClosed = errors.New("tx closed")
+
+ // ErrDatabaseReadOnly is returned when a mutating transaction is started on a
+ // read-only database.
+ ErrDatabaseReadOnly = errors.New("database is in read-only mode")
+
+
+ //
+ // These errors can occur when putting or deleting a value or a bucket.
+ //
+
+ // ErrBucketNotFound is returned when trying to access a bucket that has
+ // not been created yet.
+ ErrBucketNotFound = errors.New("bucket not found")
+
+ // ErrBucketExists is returned when creating a bucket that already exists.
+ ErrBucketExists = errors.New("bucket already exists")
+
+ // ErrBucketNameRequired is returned when creating a bucket with a blank name.
+ ErrBucketNameRequired = errors.New("bucket name required")
+
+ // ErrKeyRequired is returned when inserting a zero-length key.
+ ErrKeyRequired = errors.New("key required")
+
+ // ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize.
+ ErrKeyTooLarge = errors.New("key too large")
+
+ // ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize.
+ ErrValueTooLarge = errors.New("value too large")
+
+ // ErrIncompatibleValue is returned when trying create or delete a bucket
+ // on an existing non-bucket key or when trying to create or delete a
+ // non-bucket key on an existing bucket key.
+ ErrIncompatibleValue = errors.New("incompatible value")
+
+
+ //
+ //
+ //
+
+ // ErrUsage is returned when a usage message was printed and the process
+ // should simply exit with an error.
+ ErrUsage = errors.New("usage")
+
+ // ErrUnknownCommand is returned when a CLI command is not specified.
+ ErrUnknownCommand = errors.New("unknown command")
+
+ // ErrPathRequired is returned when the path to a Bolt database is not specified.
+ ErrPathRequired = errors.New("path required")
+
+ // ErrFileNotFound is returned when a Bolt database does not exist.
+ ErrFileNotFound = errors.New("file not found")
+
+ // ErrInvalidValue is returned when a benchmark reads an unexpected value.
+ ErrInvalidValue = errors.New("invalid value")
+
+ // ErrCorrupt is returned when a checking a data file finds errors.
+ ErrCorrupt = errors.New("invalid value")
+
+ // ErrNonDivisibleBatchSize is returned when the batch size can't be evenly
+ // divided by the iteration count.
+ ErrNonDivisibleBatchSize = errors.New("number of iterations must be divisible by the batch size")
+
+ // ErrPageIDRequired is returned when a required page id is not specified.
+ ErrPageIDRequired = errors.New("page id required")
+
+ // ErrPageNotFound is returned when specifying a page above the high water mark.
+ ErrPageNotFound = errors.New("page not found")
+
+ // ErrPageFreed is returned when reading a page that has already been freed.
+ ErrPageFreed = errors.New("page freed")
+
+ benchBucketName = []byte("bench")
+
+ // File handlers for the various profiles.
+ cpuprofile *os.File = nil
+ memprofile *os.File = nil
+ blockprofile *os.File = nil
+)
-// Are unaligned load/stores broken on this arch?
-var brokenUnaligned = false
// fdatasync flushes written data to a file descriptor.
@@ -122,58 +761,6 @@ func madvise(b []byte, advice int) (err error) {
return
}
-const (
- // MaxKeySize is the maximum length of a key, in bytes.
- MaxKeySize = 32768
-
- // MaxValueSize is the maximum length of a value, in bytes.
- MaxValueSize = (1 << 31) - 2
-)
-
-const (
- maxUint = ^uint(0)
- minUint = 0
- maxInt = int(^uint(0) >> 1)
- minInt = -maxInt - 1
-)
-
-const bucketHeaderSize = int(unsafe.Sizeof(bucket{}))
-
-const (
- minFillPercent = 0.1
- maxFillPercent = 1.0
-)
-
-// DefaultFillPercent is the percentage that split pages are filled.
-// This value can be changed by setting Bucket.FillPercent.
-const DefaultFillPercent = 0.5
-
-// Bucket represents a collection of key/value pairs inside the database.
-type Bucket struct {
- *bucket
- tx *Tx // the associated transaction
- buckets map[string]*Bucket // subbucket cache
- page *page // inline page reference
- rootNode *node // materialized node for the root page.
- nodes map[pgid]*node // node cache
-
- // Sets the threshold for filling nodes when they split. By default,
- // the bucket will fill to 50% but it can be useful to increase this
- // amount if you know that your write workloads are mostly append-only.
- //
- // This is non-persisted across transactions so it must be set in every Tx.
- FillPercent float64
-}
-
-// bucket represents the on-file representation of a bucket.
-// This is stored as the "value" of a bucket key. If the bucket is small enough,
-// then its root page can be stored inline in the "value", after the bucket
-// header. In the case of inline buckets, the "root" will be 0.
-type bucket struct {
- root pgid // page id of the bucket's root-level page
- sequence uint64 // monotonically incrementing, used by NextSequence()
-}
-
// newBucket returns a new bucket associated with a transaction.
func newBucket(tx *Tx) Bucket {
var b = Bucket{tx: tx, FillPercent: DefaultFillPercent}
@@ -191,7 +778,7 @@ func (b *Bucket) Tx() *Tx {
// Root returns the root of the bucket.
func (b *Bucket) Root() pgid {
- return b.root
+ return b.ref.root
}
// Writable returns whether the bucket is writable.
@@ -257,14 +844,14 @@ func (b *Bucket) openBucket(value []byte) *Bucket {
// If this is a writable transaction then we need to copy the bucket entry.
// Read-only transactions can point directly at the mmap entry.
if b.tx.writable && !unaligned {
- child.bucket = &bucket{}
- *child.bucket = *(*bucket)(unsafe.Pointer(&value[0]))
+ child.ref = &bucket{}
+ *child.ref = *(*bucket)(unsafe.Pointer(&value[0]))
} else {
- child.bucket = (*bucket)(unsafe.Pointer(&value[0]))
+ child.ref = (*bucket)(unsafe.Pointer(&value[0]))
}
// Save a reference to the inline page if the bucket is inline.
- if child.root == 0 {
+ if child.ref.root == 0 {
child.page = (*page)(unsafe.Pointer(&value[bucketHeaderSize]))
}
@@ -297,7 +884,7 @@ func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) {
// Create empty, inline bucket.
var bucket = Bucket{
- bucket: &bucket{},
+ ref: &bucket{},
rootNode: &node{isLeaf: true},
FillPercent: DefaultFillPercent,
}
@@ -453,7 +1040,9 @@ func (b *Bucket) Delete(key []byte) error {
}
// Sequence returns the current integer for the bucket without incrementing it.
-func (b *Bucket) Sequence() uint64 { return b.bucket.sequence }
+func (b *Bucket) Sequence() uint64 {
+ return b.ref.sequence
+}
// SetSequence updates the sequence number for the bucket.
func (b *Bucket) SetSequence(v uint64) error {
@@ -466,11 +1055,11 @@ func (b *Bucket) SetSequence(v uint64) error {
// Materialize the root node if it hasn't been already so that the
// bucket will be saved during commit.
if b.rootNode == nil {
- _ = b.node(b.root, nil)
+ _ = b.node(b.ref.root, nil)
}
// Increment and return the sequence.
- b.bucket.sequence = v
+ b.ref.sequence = v
return nil
}
@@ -485,12 +1074,12 @@ func (b *Bucket) NextSequence() (uint64, error) {
// Materialize the root node if it hasn't been already so that the
// bucket will be saved during commit.
if b.rootNode == nil {
- _ = b.node(b.root, nil)
+ _ = b.node(b.ref.root, nil)
}
// Increment and return the sequence.
- b.bucket.sequence++
- return b.bucket.sequence, nil
+ b.ref.sequence++
+ return b.ref.sequence, nil
}
// ForEach executes a function for each key/value pair in a bucket.
@@ -515,7 +1104,7 @@ func (b *Bucket) Stats() BucketStats {
var s, subStats BucketStats
pageSize := b.tx.db.pageSize
s.BucketN += 1
- if b.root == 0 {
+ if b.ref.root == 0 {
s.InlineBucketN += 1
}
b.forEachPage(func(p *page, depth int) {
@@ -538,7 +1127,7 @@ func (b *Bucket) Stats() BucketStats {
used += int(lastElement.pos + lastElement.ksize + lastElement.vsize)
}
- if b.root == 0 {
+ if b.ref.root == 0 {
// For inlined bucket just update the inline stats
s.InlineBucketInuse += used
} else {
@@ -601,7 +1190,7 @@ func (b *Bucket) forEachPage(fn func(*page, int)) {
}
// Otherwise traverse the page hierarchy.
- b.tx.forEachPage(b.root, 0, fn)
+ b.tx.forEachPage(b.ref.root, 0, fn)
}
// forEachPageNode iterates over every page (or node) in a bucket.
@@ -612,7 +1201,7 @@ func (b *Bucket) forEachPageNode(fn func(*page, *node, int)) {
fn(b.page, nil, 0)
return
}
- b._forEachPageNode(b.root, 0, fn)
+ b._forEachPageNode(b.ref.root, 0, fn)
}
func (b *Bucket) _forEachPageNode(pgid pgid, depth int, fn func(*page, *node, int)) {
@@ -657,7 +1246,7 @@ func (b *Bucket) spill() error {
// Update the child bucket header in this bucket.
value = make([]byte, unsafe.Sizeof(bucket{}))
var bucket = (*bucket)(unsafe.Pointer(&value[0]))
- *bucket = *child.bucket
+ *bucket = *child.ref
}
// Skip writing the bucket if there are no materialized nodes.
@@ -692,7 +1281,7 @@ func (b *Bucket) spill() error {
if b.rootNode.pgid >= b.tx.meta.pgid {
panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", b.rootNode.pgid, b.tx.meta.pgid))
}
- b.root = b.rootNode.pgid
+ b.ref.root = b.rootNode.pgid
return nil
}
@@ -736,7 +1325,7 @@ func (b *Bucket) write() []byte {
// Write a bucket header.
var bucket = (*bucket)(unsafe.Pointer(&value[0]))
- *bucket = *b.bucket
+ *bucket = *b.ref
// Convert byte slice to a fake page and write the root node.
var p = (*page)(unsafe.Pointer(&value[bucketHeaderSize]))
@@ -790,7 +1379,7 @@ func (b *Bucket) node(pgid pgid, parent *node) *node {
// free recursively frees all pages in the bucket.
func (b *Bucket) free() {
- if b.root == 0 {
+ if b.ref.root == 0 {
return
}
@@ -802,7 +1391,7 @@ func (b *Bucket) free() {
n.free()
}
})
- b.root = 0
+ b.ref.root = 0
}
// dereference removes all references to the old mmap.
@@ -821,7 +1410,7 @@ func (b *Bucket) dereference() {
func (b *Bucket) pageNode(id pgid) (*page, *node) {
// Inline buckets have a fake page embedded in their value so treat them
// differently. We'll return the rootNode (if available) or the fake page.
- if b.root == 0 {
+ if b.ref.root == 0 {
if id != 0 {
panic(fmt.Sprintf("inline bucket non-zero page access(2): %d != 0", id))
}
@@ -842,30 +1431,6 @@ func (b *Bucket) pageNode(id pgid) (*page, *node) {
return b.tx.page(id), nil
}
-// BucketStats records statistics about resources used by a bucket.
-type BucketStats struct {
- // Page count statistics.
- BranchPageN int // number of logical branch pages
- BranchOverflowN int // number of physical branch overflow pages
- LeafPageN int // number of logical leaf pages
- LeafOverflowN int // number of physical leaf overflow pages
-
- // Tree statistics.
- KeyN int // number of keys/value pairs
- Depth int // number of levels in B+tree
-
- // Page size utilization.
- BranchAlloc int // bytes allocated for physical branch pages
- BranchInuse int // bytes actually used for branch data
- LeafAlloc int // bytes allocated for physical leaf pages
- LeafInuse int // bytes actually used for leaf data
-
- // Bucket statistics
- BucketN int // total number of buckets including the top bucket
- InlineBucketN int // total number on inlined buckets
- InlineBucketInuse int // bytes used for inlined buckets (also accounted for in LeafInuse)
-}
-
func (s *BucketStats) Add(other BucketStats) {
s.BranchPageN += other.BranchPageN
s.BranchOverflowN += other.BranchOverflowN
@@ -892,20 +1457,6 @@ func cloneBytes(v []byte) []byte {
return clone
}
-// Cursor represents an iterator that can traverse over all key/value pairs in a bucket in sorted order.
-// Cursors see nested buckets with value == nil.
-// Cursors can be obtained from a transaction and are valid as long as the transaction is open.
-//
-// Keys and values returned from the cursor are only valid for the life of the transaction.
-//
-// Changing data while traversing with a cursor may cause it to be invalidated
-// and return unexpected keys and/or values. You must reposition your cursor
-// after mutating data.
-type Cursor struct {
- bucket *Bucket
- stack []elemRef
-}
-
// Bucket returns the bucket that this cursor was created from.
func (c *Cursor) Bucket() *Bucket {
return c.bucket
@@ -917,7 +1468,7 @@ func (c *Cursor) Bucket() *Bucket {
func (c *Cursor) First() (key []byte, value []byte) {
_assert(c.bucket.tx.db != nil, "tx closed")
c.stack = c.stack[:0]
- p, n := c.bucket.pageNode(c.bucket.root)
+ p, n := c.bucket.pageNode(c.bucket.ref.root)
c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
c.first()
@@ -941,7 +1492,7 @@ func (c *Cursor) First() (key []byte, value []byte) {
func (c *Cursor) Last() (key []byte, value []byte) {
_assert(c.bucket.tx.db != nil, "tx closed")
c.stack = c.stack[:0]
- p, n := c.bucket.pageNode(c.bucket.root)
+ p, n := c.bucket.pageNode(c.bucket.ref.root)
ref := elemRef{page: p, node: n}
ref.index = ref.count() - 1
c.stack = append(c.stack, ref)
@@ -1042,7 +1593,7 @@ func (c *Cursor) seek(seek []byte) (key []byte, value []byte, flags uint32) {
// Start from root page/node and traverse to correct page.
c.stack = c.stack[:0]
- c.search(seek, c.bucket.root)
+ c.search(seek, c.bucket.ref.root)
ref := &c.stack[len(c.stack)-1]
// If the cursor is pointing to the end of page/node then return nil.
@@ -1262,13 +1813,6 @@ func (c *Cursor) node() *node {
return n
}
-// elemRef represents a reference to an element on a given page/node.
-type elemRef struct {
- page *page
- node *node
- index int
-}
-
// isLeaf returns whether the ref is pointing at a leaf page/node.
func (r *elemRef) isLeaf() bool {
if r.node != nil {
@@ -1285,95 +1829,6 @@ func (r *elemRef) count() int {
return int(r.page.count)
}
-// The largest step that can be taken when remapping the mmap.
-const maxMmapStep = 1 << 30 // 1GB
-
-// The data file format version.
-const version = 2
-
-// Represents a marker value to indicate that a file is a Bolt DB.
-const magic uint32 = 0xED0CDAED
-
-// Default values if not set in a DB instance.
-const (
- DefaultMaxBatchSize int = 1000
- DefaultMaxBatchDelay = 10 * time.Millisecond
- DefaultAllocSize = 16 * 1024 * 1024
-)
-
-// default page size for db is set to the OS page size.
-var defaultPageSize = os.Getpagesize()
-
-// DB represents a collection of buckets persisted to a file on disk.
-// All data access is performed through transactions which can be obtained through the DB.
-// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
-type DB struct {
- // When enabled, the database will perform a Check() after every commit.
- // A panic is issued if the database is in an inconsistent state. This
- // flag has a large performance impact so it should only be used for
- // debugging purposes.
- StrictMode bool
-
- // If you want to read the entire database fast, you can set MmapFlag to
- // syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead.
- MmapFlags int
-
- // MaxBatchSize is the maximum size of a batch. Default value is
- // copied from DefaultMaxBatchSize in Open.
- //
- // If <=0, disables batching.
- //
- // Do not change concurrently with calls to Batch.
- MaxBatchSize int
-
- // MaxBatchDelay is the maximum delay before a batch starts.
- // Default value is copied from DefaultMaxBatchDelay in Open.
- //
- // If <=0, effectively disables batching.
- //
- // Do not change concurrently with calls to Batch.
- MaxBatchDelay time.Duration
-
- // AllocSize is the amount of space allocated when the database
- // needs to create new pages. This is done to amortize the cost
- // of truncate() and fsync() when growing the data file.
- AllocSize int
-
- path string
- file *os.File
- lockfile *os.File // windows only
- dataref []byte // mmap'ed readonly, write throws SEGV
- data *[maxMapSize]byte
- datasz int
- filesz int // current on disk file size
- meta0 *meta
- meta1 *meta
- pageSize int
- opened bool
- rwtx *Tx
- txs []*Tx
- freelist *freelist
- stats Stats
-
- pagePool sync.Pool
-
- batchMu sync.Mutex
- batch *batch
-
- rwlock sync.Mutex // Allows only one writer at a time.
- metalock sync.Mutex // Protects meta page access.
- mmaplock sync.RWMutex // Protects mmap access during remapping.
- statlock sync.RWMutex // Protects stats access.
-
- ops struct {
- writeAt func(b []byte, off int64) (n int, err error)
- }
-
- // Read only mode.
- // When true, Update() and Begin(true) return ErrDatabaseReadOnly immediately.
- readOnly bool
-}
-
// Path returns the path to currently open database file.
func (db *DB) Path() string {
return db.path
@@ -1926,18 +2381,6 @@ func (db *DB) Batch(fn func(*Tx) error) error {
return err
}
-type call struct {
- fn func(*Tx) error
- err chan<- error
-}
-
-type batch struct {
- db *DB
- timer *time.Timer
- start sync.Once
- calls []call
-}
-
// trigger runs the batch if it hasn't already been run.
func (b *batch) trigger() {
b.start.Do(b.run)
@@ -1987,15 +2430,6 @@ retry:
}
}
-// trySolo is a special sentinel error value used for signaling that a
-// transaction function should be re-run. It should never be seen by
-// callers.
-var trySolo = errors.New("batch function returned an error and should be re-run solo")
-
-type panicked struct {
- reason interface{}
-}
-
func (p panicked) Error() string {
if err, ok := p.reason.(error); ok {
return err.Error()
@@ -2129,52 +2563,6 @@ func (db *DB) IsReadOnly() bool {
return db.readOnly
}
-// Options represents the options that can be set when opening a database.
-type Options struct {
- // Timeout is the amount of time to wait to obtain a file lock.
- // When set to zero it will wait indefinitely. This option is only
- // available on Darwin and Linux.
- Timeout time.Duration
-
- // Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to
- // grab a shared lock (UNIX).
- ReadOnly bool
-
- // Sets the DB.MmapFlags flag before memory mapping the file.
- MmapFlags int
-
- // InitialMmapSize is the initial mmap size of the database
- // in bytes. Read transactions won't block write transaction
- // if the InitialMmapSize is large enough to hold database mmap
- // size. (See DB.Begin for more information)
- //
- // If <=0, the initial map size is 0.
- // If initialMmapSize is smaller than the previous database size,
- // it takes no effect.
- InitialMmapSize int
-}
-
-// DefaultOptions represent the options used if nil options are passed into Open().
-// No timeout is used which will cause Bolt to wait indefinitely for a lock.
-var DefaultOptions = &Options{
- Timeout: 0,
-}
-
-// Stats represents statistics about the database.
-type Stats struct {
- // Freelist stats
- FreePageN int // total number of free pages on the freelist
- PendingPageN int // total number of pending pages on the freelist
- FreeAlloc int // total bytes allocated in free pages
- FreelistInuse int // total bytes used by the freelist
-
- // Transaction stats
- TxN int // total number of started read transactions
- OpenTxN int // number of currently open read transactions
-
- TxStats TxStats // global, ongoing stats.
-}
-
// Sub calculates and returns the difference between two sets of database stats.
// This is useful when obtaining stats at two different points and time and
// you need the performance counters that occurred within that time span.
@@ -2196,23 +2584,6 @@ func (s *Stats) add(other *Stats) {
s.TxStats.add(&other.TxStats)
}
-type Info struct {
- Data uintptr
- PageSize int
-}
-
-type meta struct {
- magic uint32
- version uint32
- pageSize uint32
- flags uint32
- root bucket
- freelist pgid
- pgid pgid
- txid txid
- checksum uint64
-}
-
// validate checks the marker bytes and version of the meta page to ensure it matches this binary.
func (m *meta) validate() error {
if m.magic != magic {
@@ -2313,82 +2684,6 @@ point to different data or can point to invalid memory which will cause a panic.
*/
-// These errors can be returned when opening or calling methods on a DB.
-var (
- // ErrDatabaseNotOpen is returned when a DB instance is accessed before it
- // is opened or after it is closed.
- ErrDatabaseNotOpen = errors.New("database not open")
-
- // ErrDatabaseOpen is returned when opening a database that is
- // already open.
- ErrDatabaseOpen = errors.New("database already open")
-
- // ErrInvalid is returned when both meta pages on a database are invalid.
- // This typically occurs when a file is not a bolt database.
- ErrInvalid = errors.New("invalid database")
-
- // ErrVersionMismatch is returned when the data file was created with a
- // different version of Bolt.
- ErrVersionMismatch = errors.New("version mismatch")
-
- // ErrChecksum is returned when either meta page checksum does not match.
- ErrChecksum = errors.New("checksum error")
-
- // ErrTimeout is returned when a database cannot obtain an exclusive lock
- // on the data file after the timeout passed to Open().
- ErrTimeout = errors.New("timeout")
-)
-
-// These errors can occur when beginning or committing a Tx.
-var (
- // ErrTxNotWritable is returned when performing a write operation on a
- // read-only transaction.
- ErrTxNotWritable = errors.New("tx not writable")
-
- // ErrTxClosed is returned when committing or rolling back a transaction
- // that has already been committed or rolled back.
- ErrTxClosed = errors.New("tx closed")
-
- // ErrDatabaseReadOnly is returned when a mutating transaction is started on a
- // read-only database.
- ErrDatabaseReadOnly = errors.New("database is in read-only mode")
-)
-
-// These errors can occur when putting or deleting a value or a bucket.
-var (
- // ErrBucketNotFound is returned when trying to access a bucket that has
- // not been created yet.
- ErrBucketNotFound = errors.New("bucket not found")
-
- // ErrBucketExists is returned when creating a bucket that already exists.
- ErrBucketExists = errors.New("bucket already exists")
-
- // ErrBucketNameRequired is returned when creating a bucket with a blank name.
- ErrBucketNameRequired = errors.New("bucket name required")
-
- // ErrKeyRequired is returned when inserting a zero-length key.
- ErrKeyRequired = errors.New("key required")
-
- // ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize.
- ErrKeyTooLarge = errors.New("key too large")
-
- // ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize.
- ErrValueTooLarge = errors.New("value too large")
-
- // ErrIncompatibleValue is returned when trying create or delete a bucket
- // on an existing non-bucket key or when trying to create or delete a
- // non-bucket key on an existing bucket key.
- ErrIncompatibleValue = errors.New("incompatible value")
-)
-
-// freelist represents a list of all pages that are available for allocation.
-// It also tracks pages that have been freed but are still in use by open transactions.
-type freelist struct {
- ids []pgid // all free and available free page ids.
- pending map[txid][]pgid // mapping of soon-to-be free page ids by tx.
- cache map[pgid]bool // fast lookup of all free and pending page ids.
-}
-
// newFreelist returns an empty, initialized freelist.
func newFreelist() *freelist {
return &freelist{
@@ -2626,19 +2921,6 @@ func (f *freelist) reindex() {
}
}
-// node represents an in-memory, deserialized page.
-type node struct {
- bucket *Bucket
- isLeaf bool
- unbalanced bool
- spilled bool
- key []byte
- pgid pgid
- parent *node
- children nodes
- inodes inodes
-}
-
// root returns the top-level node this node is attached to.
func (n *node) root() *node {
if n.parent == nil {
@@ -2897,12 +3179,11 @@ func (n *node) splitTwo(pageSize int) (*node, *node) {
}
// Determine the threshold before starting a new node.
- var fillPercent = n.bucket.FillPercent
- if fillPercent < minFillPercent {
- fillPercent = minFillPercent
- } else if fillPercent > maxFillPercent {
- fillPercent = maxFillPercent
- }
+ fillPercent := g.Clamp(
+ n.bucket.FillPercent,
+ minFillPercent,
+ maxFillPercent,
+ )
threshold := int(float64(pageSize) * fillPercent)
// Determine split position and sizes of the two pages.
@@ -3204,52 +3485,10 @@ func (n *node) dump() {
}
*/
-type nodes []*node
-
func (s nodes) Len() int { return len(s) }
func (s nodes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s nodes) Less(i, j int) bool { return bytes.Compare(s[i].inodes[0].key, s[j].inodes[0].key) == -1 }
-// inode represents an internal node inside of a node.
-// It can be used to point to elements in a page or point
-// to an element which hasn't been added to a page yet.
-type inode struct {
- flags uint32
- pgid pgid
- key []byte
- value []byte
-}
-
-type inodes []inode
-
-const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr))
-
-const minKeysPerPage = 2
-
-const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{}))
-const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{}))
-
-const (
- branchPageFlag = 0x01
- leafPageFlag = 0x02
- metaPageFlag = 0x04
- freelistPageFlag = 0x10
-)
-
-const (
- bucketLeafFlag = 0x01
-)
-
-type pgid uint64
-
-type page struct {
- id pgid
- flags uint16
- count uint16
- overflow uint32
- ptr uintptr
-}
-
// typ returns a human readable page type string used for debugging.
func (p *page) typ() string {
if (p.flags & branchPageFlag) != 0 {
@@ -3302,33 +3541,16 @@ func (p *page) hexdump(n int) string {
return fmt.Sprintf("%x\n", buf)
}
-type pages []*page
-
func (s pages) Len() int { return len(s) }
func (s pages) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s pages) Less(i, j int) bool { return s[i].id < s[j].id }
-// branchPageElement represents a node on a branch page.
-type branchPageElement struct {
- pos uint32
- ksize uint32
- pgid pgid
-}
-
// key returns a byte slice of the node key.
func (n *branchPageElement) key() []byte {
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize]
}
-// leafPageElement represents a node on a leaf page.
-type leafPageElement struct {
- flags uint32
- pos uint32
- ksize uint32
- vsize uint32
-}
-
// key returns a byte slice of the node key.
func (n *leafPageElement) key() []byte {
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
@@ -3341,16 +3563,6 @@ func (n *leafPageElement) value() []byte {
return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
}
-// PageInfo represents human readable information about a page.
-type PageInfo struct {
- ID int
- Type string
- Count int
- OverflowCount int
-}
-
-type pgids []pgid
-
func (s pgids) Len() int { return len(s) }
func (s pgids) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s pgids) Less(i, j int) bool { return s[i] < s[j] }
@@ -3411,36 +3623,6 @@ func mergepgids(dst, a, b pgids) {
_ = append(merged, follow...)
}
-// txid represents the internal transaction identifier.
-type txid uint64
-
-// Tx represents a read-only or read/write transaction on the database.
-// Read-only transactions can be used for retrieving values for keys and creating cursors.
-// Read/write transactions can create and remove buckets and create and remove keys.
-//
-// IMPORTANT: You must commit or rollback transactions when you are done with
-// them. Pages can not be reclaimed by the writer until no more transactions
-// are using them. A long running read transaction can cause the database to
-// quickly grow.
-type Tx struct {
- writable bool
- managed bool
- db *DB
- meta *meta
- root Bucket
- pages map[pgid]*page
- stats TxStats
- commitHandlers []func()
-
- // WriteFlag specifies the flag for write-related methods like WriteTo().
- // Tx opens the database file with the specified flag to copy the data.
- //
- // By default, the flag is unset, which works well for mostly in-memory
- // workloads. For databases that are much larger than available RAM,
- // set the flag to syscall.O_DIRECT to avoid trashing the page cache.
- WriteFlag int
-}
-
// init initializes the transaction.
func (tx *Tx) init(db *DB) {
tx.db = db
@@ -3452,8 +3634,8 @@ func (tx *Tx) init(db *DB) {
// Copy over the root bucket.
tx.root = newBucket(tx)
- tx.root.bucket = &bucket{}
- *tx.root.bucket = tx.meta.root
+ tx.root.ref = &bucket{}
+ *tx.root.ref = tx.meta.root
// Increment the transaction id and add a page cache for writable transactions.
if tx.writable {
@@ -3568,7 +3750,7 @@ func (tx *Tx) Commit() error {
tx.stats.SpillTime += time.Since(startTime)
// Free the old root bucket.
- tx.meta.root.root = tx.root.root
+ tx.meta.root.root = tx.root.ref.root
opgid := tx.meta.pgid
@@ -3818,12 +4000,12 @@ func (tx *Tx) check(ch chan error) {
func (tx *Tx) checkBucket(b *Bucket, reachable map[pgid]*page, freed map[pgid]bool, ch chan error) {
// Ignore inline buckets.
- if b.root == 0 {
+ if b.ref.root == 0 {
return
}
// Check every page used by this bucket.
- b.tx.forEachPage(b.root, 0, func(p *page, _ int) {
+ b.tx.forEachPage(b.ref.root, 0, func(p *page, _ int) {
if p.id > tx.meta.pgid {
ch <- fmt.Errorf("page %d: out of bounds: %d", int(p.id), int(b.tx.meta.pgid))
}
@@ -4020,33 +4202,6 @@ func (tx *Tx) Page(id int) (*PageInfo, error) {
return info, nil
}
-// TxStats represents statistics about the actions performed by the transaction.
-type TxStats struct {
- // Page statistics.
- PageCount int // number of page allocations
- PageAlloc int // total bytes allocated
-
- // Cursor statistics.
- CursorCount int // number of cursors created
-
- // Node statistics
- NodeCount int // number of node allocations
- NodeDeref int // number of node dereferences
-
- // Rebalance statistics.
- Rebalance int // number of node rebalances
- RebalanceTime time.Duration // total time spent rebalancing
-
- // Split/Spill statistics.
- Split int // number of nodes split
- Spill int // number of nodes spilled
- SpillTime time.Duration // total time spent spilling
-
- // Write statistics.
- Write int // number of writes performed
- WriteTime time.Duration // total time spent writing to disk
-}
-
func (s *TxStats) add(other *TxStats) {
s.PageCount += other.PageCount
s.PageAlloc += other.PageAlloc
@@ -4082,43 +4237,6 @@ func (s *TxStats) Sub(other *TxStats) TxStats {
return diff
}
-var (
- // ErrUsage is returned when a usage message was printed and the process
- // should simply exit with an error.
- ErrUsage = errors.New("usage")
-
- // ErrUnknownCommand is returned when a CLI command is not specified.
- ErrUnknownCommand = errors.New("unknown command")
-
- // ErrPathRequired is returned when the path to a Bolt database is not specified.
- ErrPathRequired = errors.New("path required")
-
- // ErrFileNotFound is returned when a Bolt database does not exist.
- ErrFileNotFound = errors.New("file not found")
-
- // ErrInvalidValue is returned when a benchmark reads an unexpected value.
- ErrInvalidValue = errors.New("invalid value")
-
- // ErrCorrupt is returned when a checking a data file finds errors.
- ErrCorrupt = errors.New("invalid value")
-
- // ErrNonDivisibleBatchSize is returned when the batch size can't be evenly
- // divided by the iteration count.
- ErrNonDivisibleBatchSize = errors.New("number of iterations must be divisible by the batch size")
-
- // ErrPageIDRequired is returned when a required page id is not specified.
- ErrPageIDRequired = errors.New("page id required")
-
- // ErrPageNotFound is returned when specifying a page above the high water mark.
- ErrPageNotFound = errors.New("page not found")
-
- // ErrPageFreed is returned when reading a page that has already been freed.
- ErrPageFreed = errors.New("page freed")
-)
-
-// PageHeaderSize represents the size of the bolt.page header.
-const PageHeaderSize = 16
-
func Main() {
m := NewMain()
if err := m.Run(os.Args[1:]...); err == ErrUsage {
@@ -4129,13 +4247,6 @@ func Main() {
}
}
-// Main represents the main program execution.
-type MainT struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// NewMain returns a new instance of Main connect to the standard input/output.
func NewMain() *MainT {
return &MainT{
@@ -4202,13 +4313,6 @@ Use "bolt [command] -h" for more information about a command.
`, "\n")
}
-// CheckCommand represents the "check" command execution.
-type CheckCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// NewCheckCommand returns a CheckCommand.
func newCheckCommand(m *MainT) *CheckCommand {
return &CheckCommand{
@@ -4287,13 +4391,6 @@ return after all pages have been checked.
`, "\n")
}
-// InfoCommand represents the "info" command execution.
-type InfoCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// NewInfoCommand returns a InfoCommand.
func newInfoCommand(m *MainT) *InfoCommand {
return &InfoCommand{
@@ -4348,13 +4445,6 @@ Info prints basic information about the Bolt database at PATH.
`, "\n")
}
-// DumpCommand represents the "dump" command execution.
-type DumpCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// newDumpCommand returns a DumpCommand.
func newDumpCommand(m *MainT) *DumpCommand {
return &DumpCommand{
@@ -4475,13 +4565,6 @@ Dump prints a hexadecimal dump of a single page.
`, "\n")
}
-// PageCommand represents the "page" command execution.
-type PageCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// newPageCommand returns a PageCommand.
func newPageCommand(m *MainT) *PageCommand {
return &PageCommand{
@@ -4712,13 +4795,6 @@ Page prints one or more pages in human readable format.
`, "\n")
}
-// PagesCommand represents the "pages" command execution.
-type PagesCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// NewPagesCommand returns a PagesCommand.
func newPagesCommand(m *MainT) *PagesCommand {
return &PagesCommand{
@@ -4806,13 +4882,6 @@ a single page to take up multiple blocks.
`, "\n")
}
-// StatsCommand represents the "stats" command execution.
-type StatsCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// NewStatsCommand returns a StatsCommand.
func newStatsCommand(m *MainT) *StatsCommand {
return &StatsCommand{
@@ -4941,15 +5010,6 @@ experience corruption, please submit a ticket to the Bolt project page:
`, "\n")
}
-var benchBucketName = []byte("bench")
-
-// BenchCommand represents the "bench" command execution.
-type BenchCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
// NewBenchCommand returns a BenchCommand using the
func newBenchCommand(m *MainT) *BenchCommand {
return &BenchCommand{
@@ -5271,9 +5331,6 @@ func (cmd *BenchCommand) runReadsSequentialNested(db *DB, options *BenchOptions,
})
}
-// File handlers for the various profiles.
-var cpuprofile, memprofile, blockprofile *os.File
-
// Starts all profiles set on the options.
func (cmd *BenchCommand) startProfiling(options *BenchOptions) {
var err error
@@ -5331,32 +5388,6 @@ func (cmd *BenchCommand) stopProfiling() {
}
}
-// BenchOptions represents the set of options that can be passed to "bolt bench".
-type BenchOptions struct {
- ProfileMode string
- WriteMode string
- ReadMode string
- Iterations int
- BatchSize int
- KeySize int
- ValueSize int
- CPUProfile string
- MemProfile string
- BlockProfile string
- StatsInterval time.Duration
- FillPercent float64
- Work bool
- Path string
-}
-
-// BenchResults represents the performance results of the benchmark.
-type BenchResults struct {
- WriteOps int
- WriteDuration time.Duration
- ReadOps int
- ReadDuration time.Duration
-}
-
// Returns the duration for a single write operation.
func (r *BenchResults) WriteOpDuration() time.Duration {
if r.WriteOps == 0 {
@@ -5391,11 +5422,6 @@ func (r *BenchResults) ReadOpsPerSecond() int {
return int(time.Second) / int(op)
}
-type PageError struct {
- ID int
- Err error
-}
-
func (e *PageError) Error() string {
return fmt.Sprintf("page error: id=%d, err=%s", e.ID, e.Err)
}
@@ -5501,17 +5527,6 @@ func (p *page) Type() string {
return fmt.Sprintf("unknown<%02x>", p.flags)
}
-// CompactCommand represents the "compact" command execution.
-type CompactCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-
- SrcPath string
- DstPath string
- TxMaxSize int64
-}
-
// newCompactCommand returns a CompactCommand.
func newCompactCommand(m *MainT) *CompactCommand {
return &CompactCommand{
@@ -5652,11 +5667,6 @@ func (cmd *CompactCommand) compact(dst, src *DB) error {
return tx.Commit()
}
-// walkFunc is the type of the function called for keys (buckets and "normal"
-// values) discovered by Walk. keys is the list of keys to descend to the bucket
-// owning the discovered key/value pair k/v.
-type walkFunc func(keys [][]byte, k, v []byte, seq uint64) error
-
// walk walks recursively the bolt database db, calling walkFn for each key it finds.
func (cmd *CompactCommand) walk(db *DB, walkFn walkFunc) error {
return db.View(func(tx *Tx) error {