mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
vendor bbolt v1.3.5
Signed-off-by: Jintao Zhang <zhangjintao9020@gmail.com>
This commit is contained in:
parent
9ad35b7e69
commit
e58a00211d
25 changed files with 251 additions and 148 deletions
|
@ -66,7 +66,7 @@ github.com/ugorji/go b4c50a2b199d93b13dc15e78929c
|
||||||
github.com/hashicorp/consul 9a9cc9341bb487651a0399e3fc5e1e8a42e62dd9 # v0.5.2
|
github.com/hashicorp/consul 9a9cc9341bb487651a0399e3fc5e1e8a42e62dd9 # v0.5.2
|
||||||
github.com/miekg/dns 6c0c4e6581f8e173cc562c8b3363ab984e4ae071 # v1.1.27
|
github.com/miekg/dns 6c0c4e6581f8e173cc562c8b3363ab984e4ae071 # v1.1.27
|
||||||
github.com/ishidawataru/sctp 6e2cb1366111dcf547c13531e3a263a067715847
|
github.com/ishidawataru/sctp 6e2cb1366111dcf547c13531e3a263a067715847
|
||||||
go.etcd.io/bbolt a0458a2b35708eef59eb5f620ceb3cd1c01a824d # v1.3.3
|
go.etcd.io/bbolt 232d8fc87f50244f9c808f4745759e08a304c029 # v1.3.5
|
||||||
|
|
||||||
# get graph and distribution packages
|
# get graph and distribution packages
|
||||||
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
||||||
|
|
15
vendor/go.etcd.io/bbolt/README.md
generated
vendored
15
vendor/go.etcd.io/bbolt/README.md
generated
vendored
|
@ -152,11 +152,12 @@ are not thread safe. To work with data in multiple goroutines you must start
|
||||||
a transaction for each one or use locking to ensure only one goroutine accesses
|
a transaction for each one or use locking to ensure only one goroutine accesses
|
||||||
a transaction at a time. Creating transaction from the `DB` is thread safe.
|
a transaction at a time. Creating transaction from the `DB` is thread safe.
|
||||||
|
|
||||||
Read-only transactions and read-write transactions should not depend on one
|
Transactions should not depend on one another and generally shouldn't be opened
|
||||||
another and generally shouldn't be opened simultaneously in the same goroutine.
|
simultaneously in the same goroutine. This can cause a deadlock as the read-write
|
||||||
This can cause a deadlock as the read-write transaction needs to periodically
|
transaction needs to periodically re-map the data file but it cannot do so while
|
||||||
re-map the data file but it cannot do so while a read-only transaction is open.
|
any read-only transaction is open. Even a nested read-only transaction can cause
|
||||||
|
a deadlock, as the child transaction can block the parent transaction from releasing
|
||||||
|
its resources.
|
||||||
|
|
||||||
#### Read-write transactions
|
#### Read-write transactions
|
||||||
|
|
||||||
|
@ -275,7 +276,7 @@ should be writable.
|
||||||
### Using buckets
|
### Using buckets
|
||||||
|
|
||||||
Buckets are collections of key/value pairs within the database. All keys in a
|
Buckets are collections of key/value pairs within the database. All keys in a
|
||||||
bucket must be unique. You can create a bucket using the `DB.CreateBucket()`
|
bucket must be unique. You can create a bucket using the `Tx.CreateBucket()`
|
||||||
function:
|
function:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -923,6 +924,7 @@ Below is a list of public, open source projects that use Bolt:
|
||||||
* [GoWebApp](https://github.com/josephspurrier/gowebapp) - A basic MVC web application in Go using BoltDB.
|
* [GoWebApp](https://github.com/josephspurrier/gowebapp) - A basic MVC web application in Go using BoltDB.
|
||||||
* [GoShort](https://github.com/pankajkhairnar/goShort) - GoShort is a URL shortener written in Golang and BoltDB for persistent key/value storage and for routing it's using high performent HTTPRouter.
|
* [GoShort](https://github.com/pankajkhairnar/goShort) - GoShort is a URL shortener written in Golang and BoltDB for persistent key/value storage and for routing it's using high performent HTTPRouter.
|
||||||
* [gopherpit](https://github.com/gopherpit/gopherpit) - A web service to manage Go remote import paths with custom domains
|
* [gopherpit](https://github.com/gopherpit/gopherpit) - A web service to manage Go remote import paths with custom domains
|
||||||
|
* [gokv](https://github.com/philippgille/gokv) - Simple key-value store abstraction and implementations for Go (Redis, Consul, etcd, bbolt, BadgerDB, LevelDB, Memcached, DynamoDB, S3, PostgreSQL, MongoDB, CockroachDB and many more)
|
||||||
* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin".
|
* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin".
|
||||||
* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics.
|
* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics.
|
||||||
* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters.
|
* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters.
|
||||||
|
@ -935,6 +937,7 @@ Below is a list of public, open source projects that use Bolt:
|
||||||
* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets.
|
* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets.
|
||||||
* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite.
|
* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite.
|
||||||
* [MuLiFS](https://github.com/dankomiocevic/mulifs) - Music Library Filesystem creates a filesystem to organise your music files.
|
* [MuLiFS](https://github.com/dankomiocevic/mulifs) - Music Library Filesystem creates a filesystem to organise your music files.
|
||||||
|
* [NATS](https://github.com/nats-io/nats-streaming-server) - NATS Streaming uses bbolt for message and metadata storage.
|
||||||
* [Operation Go: A Routine Mission](http://gocode.io) - An online programming game for Golang using Bolt for user accounts and a leaderboard.
|
* [Operation Go: A Routine Mission](http://gocode.io) - An online programming game for Golang using Bolt for user accounts and a leaderboard.
|
||||||
* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site.
|
* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site.
|
||||||
* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system.
|
* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system.
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_386.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_386.go
generated
vendored
|
@ -5,6 +5,3 @@ const maxMapSize = 0x7FFFFFFF // 2GB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0xFFFFFFF
|
const maxAllocSize = 0xFFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_amd64.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_amd64.go
generated
vendored
|
@ -5,6 +5,3 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0x7FFFFFFF
|
const maxAllocSize = 0x7FFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
21
vendor/go.etcd.io/bbolt/bolt_arm.go
generated
vendored
21
vendor/go.etcd.io/bbolt/bolt_arm.go
generated
vendored
|
@ -1,28 +1,7 @@
|
||||||
package bbolt
|
package bbolt
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
// maxMapSize represents the largest mmap size supported by Bolt.
|
// maxMapSize represents the largest mmap size supported by Bolt.
|
||||||
const maxMapSize = 0x7FFFFFFF // 2GB
|
const maxMapSize = 0x7FFFFFFF // 2GB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0xFFFFFFF
|
const maxAllocSize = 0xFFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Simple check to see whether this arch handles unaligned load/stores
|
|
||||||
// correctly.
|
|
||||||
|
|
||||||
// ARM9 and older devices require load/stores to be from/to aligned
|
|
||||||
// addresses. If not, the lower 2 bits are cleared and that address is
|
|
||||||
// read in a jumbled up order.
|
|
||||||
|
|
||||||
// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
|
|
||||||
|
|
||||||
raw := [6]byte{0xfe, 0xef, 0x11, 0x22, 0x22, 0x11}
|
|
||||||
val := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&raw)) + 2))
|
|
||||||
|
|
||||||
brokenUnaligned = val != 0x11222211
|
|
||||||
}
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_arm64.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_arm64.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0x7FFFFFFF
|
const maxAllocSize = 0x7FFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_mips64x.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_mips64x.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0x8000000000 // 512GB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0x7FFFFFFF
|
const maxAllocSize = 0x7FFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_mipsx.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_mipsx.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0x40000000 // 1GB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0xFFFFFFF
|
const maxAllocSize = 0xFFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_ppc.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_ppc.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0x7FFFFFFF // 2GB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0xFFFFFFF
|
const maxAllocSize = 0xFFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_ppc64.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_ppc64.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0x7FFFFFFF
|
const maxAllocSize = 0x7FFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_ppc64le.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_ppc64le.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0x7FFFFFFF
|
const maxAllocSize = 0x7FFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_riscv64.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_riscv64.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0x7FFFFFFF
|
const maxAllocSize = 0x7FFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = true
|
|
||||||
|
|
3
vendor/go.etcd.io/bbolt/bolt_s390x.go
generated
vendored
3
vendor/go.etcd.io/bbolt/bolt_s390x.go
generated
vendored
|
@ -7,6 +7,3 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
|
||||||
|
|
||||||
// maxAllocSize is the size used when creating array pointers.
|
// maxAllocSize is the size used when creating array pointers.
|
||||||
const maxAllocSize = 0x7FFFFFFF
|
const maxAllocSize = 0x7FFFFFFF
|
||||||
|
|
||||||
// Are unaligned load/stores broken on this arch?
|
|
||||||
var brokenUnaligned = false
|
|
||||||
|
|
2
vendor/go.etcd.io/bbolt/bolt_unix.go
generated
vendored
2
vendor/go.etcd.io/bbolt/bolt_unix.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// +build !windows,!plan9,!solaris
|
// +build !windows,!plan9,!solaris,!aix
|
||||||
|
|
||||||
package bbolt
|
package bbolt
|
||||||
|
|
||||||
|
|
90
vendor/go.etcd.io/bbolt/bolt_unix_aix.go
generated
vendored
Normal file
90
vendor/go.etcd.io/bbolt/bolt_unix_aix.go
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
// +build aix
|
||||||
|
|
||||||
|
package bbolt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// flock acquires an advisory lock on a file descriptor.
|
||||||
|
func flock(db *DB, exclusive bool, timeout time.Duration) error {
|
||||||
|
var t time.Time
|
||||||
|
if timeout != 0 {
|
||||||
|
t = time.Now()
|
||||||
|
}
|
||||||
|
fd := db.file.Fd()
|
||||||
|
var lockType int16
|
||||||
|
if exclusive {
|
||||||
|
lockType = syscall.F_WRLCK
|
||||||
|
} else {
|
||||||
|
lockType = syscall.F_RDLCK
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
// Attempt to obtain an exclusive lock.
|
||||||
|
lock := syscall.Flock_t{Type: lockType}
|
||||||
|
err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
} else if err != syscall.EAGAIN {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we timed out then return an error.
|
||||||
|
if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
|
||||||
|
return ErrTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for a bit and try again.
|
||||||
|
time.Sleep(flockRetryTimeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// funlock releases an advisory lock on a file descriptor.
|
||||||
|
func funlock(db *DB) error {
|
||||||
|
var lock syscall.Flock_t
|
||||||
|
lock.Start = 0
|
||||||
|
lock.Len = 0
|
||||||
|
lock.Type = syscall.F_UNLCK
|
||||||
|
lock.Whence = 0
|
||||||
|
return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mmap memory maps a DB's data file.
|
||||||
|
func mmap(db *DB, sz int) error {
|
||||||
|
// Map the data file to memory.
|
||||||
|
b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advise the kernel that the mmap is accessed randomly.
|
||||||
|
if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
|
||||||
|
return fmt.Errorf("madvise: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the original byte slice and convert to a byte array pointer.
|
||||||
|
db.dataref = b
|
||||||
|
db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
|
||||||
|
db.datasz = sz
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// munmap unmaps a DB's data file from memory.
|
||||||
|
func munmap(db *DB) error {
|
||||||
|
// Ignore the unmap if we have no mapped data.
|
||||||
|
if db.dataref == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap using the original byte slice.
|
||||||
|
err := unix.Munmap(db.dataref)
|
||||||
|
db.dataref = nil
|
||||||
|
db.data = nil
|
||||||
|
db.datasz = 0
|
||||||
|
return err
|
||||||
|
}
|
34
vendor/go.etcd.io/bbolt/bucket.go
generated
vendored
34
vendor/go.etcd.io/bbolt/bucket.go
generated
vendored
|
@ -123,10 +123,12 @@ func (b *Bucket) Bucket(name []byte) *Bucket {
|
||||||
func (b *Bucket) openBucket(value []byte) *Bucket {
|
func (b *Bucket) openBucket(value []byte) *Bucket {
|
||||||
var child = newBucket(b.tx)
|
var child = newBucket(b.tx)
|
||||||
|
|
||||||
// If unaligned load/stores are broken on this arch and value is
|
// Unaligned access requires a copy to be made.
|
||||||
// unaligned simply clone to an aligned byte array.
|
const unalignedMask = unsafe.Alignof(struct {
|
||||||
unaligned := brokenUnaligned && uintptr(unsafe.Pointer(&value[0]))&3 != 0
|
bucket
|
||||||
|
page
|
||||||
|
}{}) - 1
|
||||||
|
unaligned := uintptr(unsafe.Pointer(&value[0]))&unalignedMask != 0
|
||||||
if unaligned {
|
if unaligned {
|
||||||
value = cloneBytes(value)
|
value = cloneBytes(value)
|
||||||
}
|
}
|
||||||
|
@ -206,7 +208,7 @@ func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBucket deletes a bucket at the given key.
|
// DeleteBucket deletes a bucket at the given key.
|
||||||
// Returns an error if the bucket does not exists, or if the key represents a non-bucket value.
|
// Returns an error if the bucket does not exist, or if the key represents a non-bucket value.
|
||||||
func (b *Bucket) DeleteBucket(key []byte) error {
|
func (b *Bucket) DeleteBucket(key []byte) error {
|
||||||
if b.tx.db == nil {
|
if b.tx.db == nil {
|
||||||
return ErrTxClosed
|
return ErrTxClosed
|
||||||
|
@ -228,7 +230,7 @@ func (b *Bucket) DeleteBucket(key []byte) error {
|
||||||
// Recursively delete all child buckets.
|
// Recursively delete all child buckets.
|
||||||
child := b.Bucket(key)
|
child := b.Bucket(key)
|
||||||
err := child.ForEach(func(k, v []byte) error {
|
err := child.ForEach(func(k, v []byte) error {
|
||||||
if v == nil {
|
if _, _, childFlags := child.Cursor().seek(k); (childFlags & bucketLeafFlag) != 0 {
|
||||||
if err := child.DeleteBucket(k); err != nil {
|
if err := child.DeleteBucket(k); err != nil {
|
||||||
return fmt.Errorf("delete bucket: %s", err)
|
return fmt.Errorf("delete bucket: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -409,7 +411,7 @@ func (b *Bucket) Stats() BucketStats {
|
||||||
|
|
||||||
if p.count != 0 {
|
if p.count != 0 {
|
||||||
// If page has any elements, add all element headers.
|
// If page has any elements, add all element headers.
|
||||||
used += leafPageElementSize * int(p.count-1)
|
used += leafPageElementSize * uintptr(p.count-1)
|
||||||
|
|
||||||
// Add all element key, value sizes.
|
// Add all element key, value sizes.
|
||||||
// The computation takes advantage of the fact that the position
|
// The computation takes advantage of the fact that the position
|
||||||
|
@ -417,16 +419,16 @@ func (b *Bucket) Stats() BucketStats {
|
||||||
// of all previous elements' keys and values.
|
// of all previous elements' keys and values.
|
||||||
// It also includes the last element's header.
|
// It also includes the last element's header.
|
||||||
lastElement := p.leafPageElement(p.count - 1)
|
lastElement := p.leafPageElement(p.count - 1)
|
||||||
used += int(lastElement.pos + lastElement.ksize + lastElement.vsize)
|
used += uintptr(lastElement.pos + lastElement.ksize + lastElement.vsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.root == 0 {
|
if b.root == 0 {
|
||||||
// For inlined bucket just update the inline stats
|
// For inlined bucket just update the inline stats
|
||||||
s.InlineBucketInuse += used
|
s.InlineBucketInuse += int(used)
|
||||||
} else {
|
} else {
|
||||||
// For non-inlined bucket update all the leaf stats
|
// For non-inlined bucket update all the leaf stats
|
||||||
s.LeafPageN++
|
s.LeafPageN++
|
||||||
s.LeafInuse += used
|
s.LeafInuse += int(used)
|
||||||
s.LeafOverflowN += int(p.overflow)
|
s.LeafOverflowN += int(p.overflow)
|
||||||
|
|
||||||
// Collect stats from sub-buckets.
|
// Collect stats from sub-buckets.
|
||||||
|
@ -447,13 +449,13 @@ func (b *Bucket) Stats() BucketStats {
|
||||||
|
|
||||||
// used totals the used bytes for the page
|
// used totals the used bytes for the page
|
||||||
// Add header and all element headers.
|
// Add header and all element headers.
|
||||||
used := pageHeaderSize + (branchPageElementSize * int(p.count-1))
|
used := pageHeaderSize + (branchPageElementSize * uintptr(p.count-1))
|
||||||
|
|
||||||
// Add size of all keys and values.
|
// Add size of all keys and values.
|
||||||
// Again, use the fact that last element's position equals to
|
// Again, use the fact that last element's position equals to
|
||||||
// the total of key, value sizes of all previous elements.
|
// the total of key, value sizes of all previous elements.
|
||||||
used += int(lastElement.pos + lastElement.ksize)
|
used += uintptr(lastElement.pos + lastElement.ksize)
|
||||||
s.BranchInuse += used
|
s.BranchInuse += int(used)
|
||||||
s.BranchOverflowN += int(p.overflow)
|
s.BranchOverflowN += int(p.overflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +595,7 @@ func (b *Bucket) inlineable() bool {
|
||||||
// our threshold for inline bucket size.
|
// our threshold for inline bucket size.
|
||||||
var size = pageHeaderSize
|
var size = pageHeaderSize
|
||||||
for _, inode := range n.inodes {
|
for _, inode := range n.inodes {
|
||||||
size += leafPageElementSize + len(inode.key) + len(inode.value)
|
size += leafPageElementSize + uintptr(len(inode.key)) + uintptr(len(inode.value))
|
||||||
|
|
||||||
if inode.flags&bucketLeafFlag != 0 {
|
if inode.flags&bucketLeafFlag != 0 {
|
||||||
return false
|
return false
|
||||||
|
@ -606,8 +608,8 @@ func (b *Bucket) inlineable() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the maximum total size of a bucket to make it a candidate for inlining.
|
// Returns the maximum total size of a bucket to make it a candidate for inlining.
|
||||||
func (b *Bucket) maxInlineBucketSize() int {
|
func (b *Bucket) maxInlineBucketSize() uintptr {
|
||||||
return b.tx.db.pageSize / 4
|
return uintptr(b.tx.db.pageSize / 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write allocates and writes a bucket to a byte slice.
|
// write allocates and writes a bucket to a byte slice.
|
||||||
|
|
2
vendor/go.etcd.io/bbolt/cursor.go
generated
vendored
2
vendor/go.etcd.io/bbolt/cursor.go
generated
vendored
|
@ -366,7 +366,7 @@ func (c *Cursor) node() *node {
|
||||||
}
|
}
|
||||||
for _, ref := range c.stack[:len(c.stack)-1] {
|
for _, ref := range c.stack[:len(c.stack)-1] {
|
||||||
_assert(!n.isLeaf, "expected branch node")
|
_assert(!n.isLeaf, "expected branch node")
|
||||||
n = n.childAt(int(ref.index))
|
n = n.childAt(ref.index)
|
||||||
}
|
}
|
||||||
_assert(n.isLeaf, "expected leaf node")
|
_assert(n.isLeaf, "expected leaf node")
|
||||||
return n
|
return n
|
||||||
|
|
4
vendor/go.etcd.io/bbolt/db.go
generated
vendored
4
vendor/go.etcd.io/bbolt/db.go
generated
vendored
|
@ -206,12 +206,12 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open data file and separate sync handler for metadata writes.
|
// Open data file and separate sync handler for metadata writes.
|
||||||
db.path = path
|
|
||||||
var err error
|
var err error
|
||||||
if db.file, err = db.openFile(db.path, flag|os.O_CREATE, mode); err != nil {
|
if db.file, err = db.openFile(path, flag|os.O_CREATE, mode); err != nil {
|
||||||
_ = db.close()
|
_ = db.close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
db.path = db.file.Name()
|
||||||
|
|
||||||
// Lock file so that other processes using Bolt in read-write mode cannot
|
// Lock file so that other processes using Bolt in read-write mode cannot
|
||||||
// use the database at the same time. This would cause corruption since
|
// use the database at the same time. This would cause corruption since
|
||||||
|
|
38
vendor/go.etcd.io/bbolt/freelist.go
generated
vendored
38
vendor/go.etcd.io/bbolt/freelist.go
generated
vendored
|
@ -71,7 +71,7 @@ func (f *freelist) size() int {
|
||||||
// The first element will be used to store the count. See freelist.write.
|
// The first element will be used to store the count. See freelist.write.
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
return pageHeaderSize + (int(unsafe.Sizeof(pgid(0))) * n)
|
return int(pageHeaderSize) + (int(unsafe.Sizeof(pgid(0))) * n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// count returns count of pages on the freelist
|
// count returns count of pages on the freelist
|
||||||
|
@ -93,7 +93,7 @@ func (f *freelist) pending_count() int {
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyall copies into dst a list of all free ids and all pending ids in one sorted list.
|
// copyall copies a list of all free ids and all pending ids in one sorted list.
|
||||||
// f.count returns the minimum length required for dst.
|
// f.count returns the minimum length required for dst.
|
||||||
func (f *freelist) copyall(dst []pgid) {
|
func (f *freelist) copyall(dst []pgid) {
|
||||||
m := make(pgids, 0, f.pending_count())
|
m := make(pgids, 0, f.pending_count())
|
||||||
|
@ -267,17 +267,23 @@ func (f *freelist) read(p *page) {
|
||||||
}
|
}
|
||||||
// If the page.count is at the max uint16 value (64k) then it's considered
|
// If the page.count is at the max uint16 value (64k) then it's considered
|
||||||
// an overflow and the size of the freelist is stored as the first element.
|
// an overflow and the size of the freelist is stored as the first element.
|
||||||
idx, count := 0, int(p.count)
|
var idx, count = 0, int(p.count)
|
||||||
if count == 0xFFFF {
|
if count == 0xFFFF {
|
||||||
idx = 1
|
idx = 1
|
||||||
count = int(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0])
|
c := *(*pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))
|
||||||
|
count = int(c)
|
||||||
|
if count < 0 {
|
||||||
|
panic(fmt.Sprintf("leading element count %d overflows int", c))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the list of page ids from the freelist.
|
// Copy the list of page ids from the freelist.
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
f.ids = nil
|
f.ids = nil
|
||||||
} else {
|
} else {
|
||||||
ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx : idx+count]
|
var ids []pgid
|
||||||
|
data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(ids[0]), idx)
|
||||||
|
unsafeSlice(unsafe.Pointer(&ids), data, count)
|
||||||
|
|
||||||
// copy the ids, so we don't modify on the freelist page directly
|
// copy the ids, so we don't modify on the freelist page directly
|
||||||
idsCopy := make([]pgid, count)
|
idsCopy := make([]pgid, count)
|
||||||
|
@ -310,16 +316,22 @@ func (f *freelist) write(p *page) error {
|
||||||
|
|
||||||
// The page.count can only hold up to 64k elements so if we overflow that
|
// The page.count can only hold up to 64k elements so if we overflow that
|
||||||
// number then we handle it by putting the size in the first element.
|
// number then we handle it by putting the size in the first element.
|
||||||
lenids := f.count()
|
l := f.count()
|
||||||
if lenids == 0 {
|
if l == 0 {
|
||||||
p.count = uint16(lenids)
|
p.count = uint16(l)
|
||||||
} else if lenids < 0xFFFF {
|
} else if l < 0xFFFF {
|
||||||
p.count = uint16(lenids)
|
p.count = uint16(l)
|
||||||
f.copyall(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:])
|
var ids []pgid
|
||||||
|
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
|
||||||
|
unsafeSlice(unsafe.Pointer(&ids), data, l)
|
||||||
|
f.copyall(ids)
|
||||||
} else {
|
} else {
|
||||||
p.count = 0xFFFF
|
p.count = 0xFFFF
|
||||||
((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0] = pgid(lenids)
|
var ids []pgid
|
||||||
f.copyall(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[1:])
|
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
|
||||||
|
unsafeSlice(unsafe.Pointer(&ids), data, l+1)
|
||||||
|
ids[0] = pgid(l)
|
||||||
|
f.copyall(ids[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
2
vendor/go.etcd.io/bbolt/freelist_hmap.go
generated
vendored
2
vendor/go.etcd.io/bbolt/freelist_hmap.go
generated
vendored
|
@ -27,7 +27,7 @@ func (f *freelist) hashmapAllocate(txid txid, n int) pgid {
|
||||||
f.allocs[pid] = txid
|
f.allocs[pid] = txid
|
||||||
|
|
||||||
for i := pgid(0); i < pgid(n); i++ {
|
for i := pgid(0); i < pgid(n); i++ {
|
||||||
delete(f.cache, pid+pgid(i))
|
delete(f.cache, pid+i)
|
||||||
}
|
}
|
||||||
return pid
|
return pid
|
||||||
}
|
}
|
||||||
|
|
5
vendor/go.etcd.io/bbolt/go.mod
generated
vendored
Normal file
5
vendor/go.etcd.io/bbolt/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module go.etcd.io/bbolt
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5
|
52
vendor/go.etcd.io/bbolt/node.go
generated
vendored
52
vendor/go.etcd.io/bbolt/node.go
generated
vendored
|
@ -41,19 +41,19 @@ func (n *node) size() int {
|
||||||
sz, elsz := pageHeaderSize, n.pageElementSize()
|
sz, elsz := pageHeaderSize, n.pageElementSize()
|
||||||
for i := 0; i < len(n.inodes); i++ {
|
for i := 0; i < len(n.inodes); i++ {
|
||||||
item := &n.inodes[i]
|
item := &n.inodes[i]
|
||||||
sz += elsz + len(item.key) + len(item.value)
|
sz += elsz + uintptr(len(item.key)) + uintptr(len(item.value))
|
||||||
}
|
}
|
||||||
return sz
|
return int(sz)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sizeLessThan returns true if the node is less than a given size.
|
// sizeLessThan returns true if the node is less than a given size.
|
||||||
// This is an optimization to avoid calculating a large node when we only need
|
// This is an optimization to avoid calculating a large node when we only need
|
||||||
// to know if it fits inside a certain page size.
|
// to know if it fits inside a certain page size.
|
||||||
func (n *node) sizeLessThan(v int) bool {
|
func (n *node) sizeLessThan(v uintptr) bool {
|
||||||
sz, elsz := pageHeaderSize, n.pageElementSize()
|
sz, elsz := pageHeaderSize, n.pageElementSize()
|
||||||
for i := 0; i < len(n.inodes); i++ {
|
for i := 0; i < len(n.inodes); i++ {
|
||||||
item := &n.inodes[i]
|
item := &n.inodes[i]
|
||||||
sz += elsz + len(item.key) + len(item.value)
|
sz += elsz + uintptr(len(item.key)) + uintptr(len(item.value))
|
||||||
if sz >= v {
|
if sz >= v {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func (n *node) sizeLessThan(v int) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// pageElementSize returns the size of each page element based on the type of node.
|
// pageElementSize returns the size of each page element based on the type of node.
|
||||||
func (n *node) pageElementSize() int {
|
func (n *node) pageElementSize() uintptr {
|
||||||
if n.isLeaf {
|
if n.isLeaf {
|
||||||
return leafPageElementSize
|
return leafPageElementSize
|
||||||
}
|
}
|
||||||
|
@ -207,10 +207,17 @@ func (n *node) write(p *page) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over each item and write it to the page.
|
// Loop over each item and write it to the page.
|
||||||
b := (*[maxAllocSize]byte)(unsafe.Pointer(&p.ptr))[n.pageElementSize()*len(n.inodes):]
|
// off tracks the offset into p of the start of the next data.
|
||||||
|
off := unsafe.Sizeof(*p) + n.pageElementSize()*uintptr(len(n.inodes))
|
||||||
for i, item := range n.inodes {
|
for i, item := range n.inodes {
|
||||||
_assert(len(item.key) > 0, "write: zero-length inode key")
|
_assert(len(item.key) > 0, "write: zero-length inode key")
|
||||||
|
|
||||||
|
// Create a slice to write into of needed size and advance
|
||||||
|
// byte pointer for next iteration.
|
||||||
|
sz := len(item.key) + len(item.value)
|
||||||
|
b := unsafeByteSlice(unsafe.Pointer(p), off, 0, sz)
|
||||||
|
off += uintptr(sz)
|
||||||
|
|
||||||
// Write the page element.
|
// Write the page element.
|
||||||
if n.isLeaf {
|
if n.isLeaf {
|
||||||
elem := p.leafPageElement(uint16(i))
|
elem := p.leafPageElement(uint16(i))
|
||||||
|
@ -226,20 +233,9 @@ func (n *node) write(p *page) {
|
||||||
_assert(elem.pgid != p.id, "write: circular dependency occurred")
|
_assert(elem.pgid != p.id, "write: circular dependency occurred")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the length of key+value is larger than the max allocation size
|
|
||||||
// then we need to reallocate the byte array pointer.
|
|
||||||
//
|
|
||||||
// See: https://github.com/boltdb/bolt/pull/335
|
|
||||||
klen, vlen := len(item.key), len(item.value)
|
|
||||||
if len(b) < klen+vlen {
|
|
||||||
b = (*[maxAllocSize]byte)(unsafe.Pointer(&b[0]))[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write data for the element to the end of the page.
|
// Write data for the element to the end of the page.
|
||||||
copy(b[0:], item.key)
|
l := copy(b, item.key)
|
||||||
b = b[klen:]
|
copy(b[l:], item.value)
|
||||||
copy(b[0:], item.value)
|
|
||||||
b = b[vlen:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG ONLY: n.dump()
|
// DEBUG ONLY: n.dump()
|
||||||
|
@ -247,7 +243,7 @@ func (n *node) write(p *page) {
|
||||||
|
|
||||||
// split breaks up a node into multiple smaller nodes, if appropriate.
|
// split breaks up a node into multiple smaller nodes, if appropriate.
|
||||||
// This should only be called from the spill() function.
|
// This should only be called from the spill() function.
|
||||||
func (n *node) split(pageSize int) []*node {
|
func (n *node) split(pageSize uintptr) []*node {
|
||||||
var nodes []*node
|
var nodes []*node
|
||||||
|
|
||||||
node := n
|
node := n
|
||||||
|
@ -270,7 +266,7 @@ func (n *node) split(pageSize int) []*node {
|
||||||
|
|
||||||
// splitTwo breaks up a node into two smaller nodes, if appropriate.
|
// splitTwo breaks up a node into two smaller nodes, if appropriate.
|
||||||
// This should only be called from the split() function.
|
// This should only be called from the split() function.
|
||||||
func (n *node) splitTwo(pageSize int) (*node, *node) {
|
func (n *node) splitTwo(pageSize uintptr) (*node, *node) {
|
||||||
// Ignore the split if the page doesn't have at least enough nodes for
|
// Ignore the split if the page doesn't have at least enough nodes for
|
||||||
// two pages or if the nodes can fit in a single page.
|
// two pages or if the nodes can fit in a single page.
|
||||||
if len(n.inodes) <= (minKeysPerPage*2) || n.sizeLessThan(pageSize) {
|
if len(n.inodes) <= (minKeysPerPage*2) || n.sizeLessThan(pageSize) {
|
||||||
|
@ -312,18 +308,18 @@ func (n *node) splitTwo(pageSize int) (*node, *node) {
|
||||||
// splitIndex finds the position where a page will fill a given threshold.
|
// splitIndex finds the position where a page will fill a given threshold.
|
||||||
// It returns the index as well as the size of the first page.
|
// It returns the index as well as the size of the first page.
|
||||||
// This is only be called from split().
|
// This is only be called from split().
|
||||||
func (n *node) splitIndex(threshold int) (index, sz int) {
|
func (n *node) splitIndex(threshold int) (index, sz uintptr) {
|
||||||
sz = pageHeaderSize
|
sz = pageHeaderSize
|
||||||
|
|
||||||
// Loop until we only have the minimum number of keys required for the second page.
|
// Loop until we only have the minimum number of keys required for the second page.
|
||||||
for i := 0; i < len(n.inodes)-minKeysPerPage; i++ {
|
for i := 0; i < len(n.inodes)-minKeysPerPage; i++ {
|
||||||
index = i
|
index = uintptr(i)
|
||||||
inode := n.inodes[i]
|
inode := n.inodes[i]
|
||||||
elsize := n.pageElementSize() + len(inode.key) + len(inode.value)
|
elsize := n.pageElementSize() + uintptr(len(inode.key)) + uintptr(len(inode.value))
|
||||||
|
|
||||||
// If we have at least the minimum number of keys and adding another
|
// If we have at least the minimum number of keys and adding another
|
||||||
// node would put us over the threshold then exit and return.
|
// node would put us over the threshold then exit and return.
|
||||||
if i >= minKeysPerPage && sz+elsize > threshold {
|
if index >= minKeysPerPage && sz+elsize > uintptr(threshold) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +352,7 @@ func (n *node) spill() error {
|
||||||
n.children = nil
|
n.children = nil
|
||||||
|
|
||||||
// Split nodes into appropriate sizes. The first node will always be n.
|
// Split nodes into appropriate sizes. The first node will always be n.
|
||||||
var nodes = n.split(tx.db.pageSize)
|
var nodes = n.split(uintptr(tx.db.pageSize))
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
// Add node's page to the freelist if it's not new.
|
// Add node's page to the freelist if it's not new.
|
||||||
if node.pgid > 0 {
|
if node.pgid > 0 {
|
||||||
|
@ -589,7 +585,9 @@ type nodes []*node
|
||||||
|
|
||||||
func (s nodes) Len() int { return len(s) }
|
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) 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 }
|
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.
|
// inode represents an internal node inside of a node.
|
||||||
// It can be used to point to elements in a page or point
|
// It can be used to point to elements in a page or point
|
||||||
|
|
41
vendor/go.etcd.io/bbolt/page.go
generated
vendored
41
vendor/go.etcd.io/bbolt/page.go
generated
vendored
|
@ -7,12 +7,12 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr))
|
const pageHeaderSize = unsafe.Sizeof(page{})
|
||||||
|
|
||||||
const minKeysPerPage = 2
|
const minKeysPerPage = 2
|
||||||
|
|
||||||
const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{}))
|
const branchPageElementSize = unsafe.Sizeof(branchPageElement{})
|
||||||
const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{}))
|
const leafPageElementSize = unsafe.Sizeof(leafPageElement{})
|
||||||
|
|
||||||
const (
|
const (
|
||||||
branchPageFlag = 0x01
|
branchPageFlag = 0x01
|
||||||
|
@ -32,7 +32,6 @@ type page struct {
|
||||||
flags uint16
|
flags uint16
|
||||||
count uint16
|
count uint16
|
||||||
overflow uint32
|
overflow uint32
|
||||||
ptr uintptr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// typ returns a human readable page type string used for debugging.
|
// typ returns a human readable page type string used for debugging.
|
||||||
|
@ -51,13 +50,13 @@ func (p *page) typ() string {
|
||||||
|
|
||||||
// meta returns a pointer to the metadata section of the page.
|
// meta returns a pointer to the metadata section of the page.
|
||||||
func (p *page) meta() *meta {
|
func (p *page) meta() *meta {
|
||||||
return (*meta)(unsafe.Pointer(&p.ptr))
|
return (*meta)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// leafPageElement retrieves the leaf node by index
|
// leafPageElement retrieves the leaf node by index
|
||||||
func (p *page) leafPageElement(index uint16) *leafPageElement {
|
func (p *page) leafPageElement(index uint16) *leafPageElement {
|
||||||
n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
|
return (*leafPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p),
|
||||||
return n
|
leafPageElementSize, int(index)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// leafPageElements retrieves a list of leaf nodes.
|
// leafPageElements retrieves a list of leaf nodes.
|
||||||
|
@ -65,12 +64,16 @@ func (p *page) leafPageElements() []leafPageElement {
|
||||||
if p.count == 0 {
|
if p.count == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
|
var elems []leafPageElement
|
||||||
|
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
|
||||||
|
unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
|
||||||
|
return elems
|
||||||
}
|
}
|
||||||
|
|
||||||
// branchPageElement retrieves the branch node by index
|
// branchPageElement retrieves the branch node by index
|
||||||
func (p *page) branchPageElement(index uint16) *branchPageElement {
|
func (p *page) branchPageElement(index uint16) *branchPageElement {
|
||||||
return &((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[index]
|
return (*branchPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p),
|
||||||
|
unsafe.Sizeof(branchPageElement{}), int(index)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// branchPageElements retrieves a list of branch nodes.
|
// branchPageElements retrieves a list of branch nodes.
|
||||||
|
@ -78,12 +81,15 @@ func (p *page) branchPageElements() []branchPageElement {
|
||||||
if p.count == 0 {
|
if p.count == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:]
|
var elems []branchPageElement
|
||||||
|
data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
|
||||||
|
unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
|
||||||
|
return elems
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump writes n bytes of the page to STDERR as hex output.
|
// dump writes n bytes of the page to STDERR as hex output.
|
||||||
func (p *page) hexdump(n int) {
|
func (p *page) hexdump(n int) {
|
||||||
buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:n]
|
buf := unsafeByteSlice(unsafe.Pointer(p), 0, 0, n)
|
||||||
fmt.Fprintf(os.Stderr, "%x\n", buf)
|
fmt.Fprintf(os.Stderr, "%x\n", buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,8 +108,7 @@ type branchPageElement struct {
|
||||||
|
|
||||||
// key returns a byte slice of the node key.
|
// key returns a byte slice of the node key.
|
||||||
func (n *branchPageElement) key() []byte {
|
func (n *branchPageElement) key() []byte {
|
||||||
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
return unsafeByteSlice(unsafe.Pointer(n), 0, int(n.pos), int(n.pos)+int(n.ksize))
|
||||||
return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// leafPageElement represents a node on a leaf page.
|
// leafPageElement represents a node on a leaf page.
|
||||||
|
@ -116,14 +121,16 @@ type leafPageElement struct {
|
||||||
|
|
||||||
// key returns a byte slice of the node key.
|
// key returns a byte slice of the node key.
|
||||||
func (n *leafPageElement) key() []byte {
|
func (n *leafPageElement) key() []byte {
|
||||||
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
i := int(n.pos)
|
||||||
return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize]
|
j := i + int(n.ksize)
|
||||||
|
return unsafeByteSlice(unsafe.Pointer(n), 0, i, j)
|
||||||
}
|
}
|
||||||
|
|
||||||
// value returns a byte slice of the node value.
|
// value returns a byte slice of the node value.
|
||||||
func (n *leafPageElement) value() []byte {
|
func (n *leafPageElement) value() []byte {
|
||||||
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
i := int(n.pos) + int(n.ksize)
|
||||||
return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
|
j := i + int(n.vsize)
|
||||||
|
return unsafeByteSlice(unsafe.Pointer(n), 0, i, j)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageInfo represents human readable information about a page.
|
// PageInfo represents human readable information about a page.
|
||||||
|
|
18
vendor/go.etcd.io/bbolt/tx.go
generated
vendored
18
vendor/go.etcd.io/bbolt/tx.go
generated
vendored
|
@ -523,20 +523,18 @@ func (tx *Tx) write() error {
|
||||||
|
|
||||||
// Write pages to disk in order.
|
// Write pages to disk in order.
|
||||||
for _, p := range pages {
|
for _, p := range pages {
|
||||||
size := (int(p.overflow) + 1) * tx.db.pageSize
|
rem := (uint64(p.overflow) + 1) * uint64(tx.db.pageSize)
|
||||||
offset := int64(p.id) * int64(tx.db.pageSize)
|
offset := int64(p.id) * int64(tx.db.pageSize)
|
||||||
|
var written uintptr
|
||||||
|
|
||||||
// Write out page in "max allocation" sized chunks.
|
// Write out page in "max allocation" sized chunks.
|
||||||
ptr := (*[maxAllocSize]byte)(unsafe.Pointer(p))
|
|
||||||
for {
|
for {
|
||||||
// Limit our write to our max allocation size.
|
sz := rem
|
||||||
sz := size
|
|
||||||
if sz > maxAllocSize-1 {
|
if sz > maxAllocSize-1 {
|
||||||
sz = maxAllocSize - 1
|
sz = maxAllocSize - 1
|
||||||
}
|
}
|
||||||
|
buf := unsafeByteSlice(unsafe.Pointer(p), written, 0, int(sz))
|
||||||
|
|
||||||
// Write chunk to disk.
|
|
||||||
buf := ptr[:sz]
|
|
||||||
if _, err := tx.db.ops.writeAt(buf, offset); err != nil {
|
if _, err := tx.db.ops.writeAt(buf, offset); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -545,14 +543,14 @@ func (tx *Tx) write() error {
|
||||||
tx.stats.Write++
|
tx.stats.Write++
|
||||||
|
|
||||||
// Exit inner for loop if we've written all the chunks.
|
// Exit inner for loop if we've written all the chunks.
|
||||||
size -= sz
|
rem -= sz
|
||||||
if size == 0 {
|
if rem == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise move offset forward and move pointer to next chunk.
|
// Otherwise move offset forward and move pointer to next chunk.
|
||||||
offset += int64(sz)
|
offset += int64(sz)
|
||||||
ptr = (*[maxAllocSize]byte)(unsafe.Pointer(&ptr[sz]))
|
written += uintptr(sz)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,7 +569,7 @@ func (tx *Tx) write() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:tx.db.pageSize]
|
buf := unsafeByteSlice(unsafe.Pointer(p), 0, 0, tx.db.pageSize)
|
||||||
|
|
||||||
// See https://go.googlesource.com/go/+/f03c9202c43e0abb130669852082117ca50aa9b1
|
// See https://go.googlesource.com/go/+/f03c9202c43e0abb130669852082117ca50aa9b1
|
||||||
for i := range buf {
|
for i := range buf {
|
||||||
|
|
39
vendor/go.etcd.io/bbolt/unsafe.go
generated
vendored
Normal file
39
vendor/go.etcd.io/bbolt/unsafe.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package bbolt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func unsafeAdd(base unsafe.Pointer, offset uintptr) unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(uintptr(base) + offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsafeIndex(base unsafe.Pointer, offset uintptr, elemsz uintptr, n int) unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(uintptr(base) + offset + uintptr(n)*elemsz)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsafeByteSlice(base unsafe.Pointer, offset uintptr, i, j int) []byte {
|
||||||
|
// See: https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
|
||||||
|
//
|
||||||
|
// This memory is not allocated from C, but it is unmanaged by Go's
|
||||||
|
// garbage collector and should behave similarly, and the compiler
|
||||||
|
// should produce similar code. Note that this conversion allows a
|
||||||
|
// subslice to begin after the base address, with an optional offset,
|
||||||
|
// while the URL above does not cover this case and only slices from
|
||||||
|
// index 0. However, the wiki never says that the address must be to
|
||||||
|
// the beginning of a C allocation (or even that malloc was used at
|
||||||
|
// all), so this is believed to be correct.
|
||||||
|
return (*[maxAllocSize]byte)(unsafeAdd(base, offset))[i:j:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafeSlice modifies the data, len, and cap of a slice variable pointed to by
|
||||||
|
// the slice parameter. This helper should be used over other direct
|
||||||
|
// manipulation of reflect.SliceHeader to prevent misuse, namely, converting
|
||||||
|
// from reflect.SliceHeader to a Go slice type.
|
||||||
|
func unsafeSlice(slice, data unsafe.Pointer, len int) {
|
||||||
|
s := (*reflect.SliceHeader)(slice)
|
||||||
|
s.Data = uintptr(data)
|
||||||
|
s.Cap = len
|
||||||
|
s.Len = len
|
||||||
|
}
|
Loading…
Reference in a new issue