mirror of https://github.com/etcd-io/bbolt.git
Merge branch 'fix-crash'
commit
2c5801bedd
13
node.go
13
node.go
|
@ -221,11 +221,20 @@ 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)
|
copy(b[0:], item.key)
|
||||||
b = b[len(item.key):]
|
b = b[klen:]
|
||||||
copy(b[0:], item.value)
|
copy(b[0:], item.value)
|
||||||
b = b[len(item.value):]
|
b = b[vlen:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG ONLY: n.dump()
|
// DEBUG ONLY: n.dump()
|
||||||
|
|
6
page.go
6
page.go
|
@ -96,7 +96,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))
|
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
||||||
return buf[n.pos : n.pos+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.
|
||||||
|
@ -110,13 +110,13 @@ 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))
|
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
||||||
return buf[n.pos : n.pos+n.ksize]
|
return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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))
|
buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
|
||||||
return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize]
|
return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize]
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageInfo represents human readable information about a page.
|
// PageInfo represents human readable information about a page.
|
||||||
|
|
26
tx.go
26
tx.go
|
@ -423,15 +423,39 @@ 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
|
size := (int(p.overflow) + 1) * tx.db.pageSize
|
||||||
buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:size]
|
|
||||||
offset := int64(p.id) * int64(tx.db.pageSize)
|
offset := int64(p.id) * int64(tx.db.pageSize)
|
||||||
|
|
||||||
|
// Write out page in "max allocation" sized chunks.
|
||||||
|
ptr := (*[maxAllocSize]byte)(unsafe.Pointer(p))
|
||||||
|
for {
|
||||||
|
// Limit our write to our max allocation size.
|
||||||
|
sz := size
|
||||||
|
if sz > maxAllocSize-1 {
|
||||||
|
sz = maxAllocSize - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update statistics.
|
// Update statistics.
|
||||||
tx.stats.Write++
|
tx.stats.Write++
|
||||||
|
|
||||||
|
// Exit inner for loop if we've written all the chunks.
|
||||||
|
size -= sz
|
||||||
|
if size == 0 {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise move offset forward and move pointer to next chunk.
|
||||||
|
offset += int64(sz)
|
||||||
|
ptr = (*[maxAllocSize]byte)(unsafe.Pointer(&ptr[sz]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore file sync if flag is set on DB.
|
||||||
if !tx.db.NoSync || IgnoreNoSync {
|
if !tx.db.NoSync || IgnoreNoSync {
|
||||||
if err := fdatasync(tx.db); err != nil {
|
if err := fdatasync(tx.db); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in New Issue