mirror of https://github.com/etcd-io/bbolt.git
internal: add function ClearElements in surgeon package
Signed-off-by: Benjamin Wang <wachao@vmware.com>pull/417/head
parent
5a7a94e5cc
commit
9832aff38a
|
@ -50,6 +50,10 @@ func ReadPage(path string, pageID uint64) (*common.Page, []byte, error) {
|
|||
return nil, nil, fmt.Errorf("error: %w, Page claims to have %d overflow pages (>=hwm=%d). Interrupting to avoid risky OOM", ErrCorrupt, overflowN, hwm)
|
||||
}
|
||||
|
||||
if overflowN == 0 {
|
||||
return p, buf, nil
|
||||
}
|
||||
|
||||
// Re-read entire Page (with overflow) into buffer.
|
||||
buf = make([]byte, (uint64(overflowN)+1)*pageSize)
|
||||
if n, err := f.ReadAt(buf, int64(pageID*pageSize)); err != nil {
|
||||
|
|
|
@ -2,6 +2,7 @@ package surgeon
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.etcd.io/bbolt/internal/common"
|
||||
"go.etcd.io/bbolt/internal/guts_cli"
|
||||
)
|
||||
|
@ -16,19 +17,105 @@ func CopyPage(path string, srcPage common.Pgid, target common.Pgid) error {
|
|||
}
|
||||
|
||||
func ClearPage(path string, pgId common.Pgid) error {
|
||||
return ClearPageElements(path, pgId, 0, -1)
|
||||
}
|
||||
|
||||
func ClearPageElements(path string, pgId common.Pgid, start, end int) error {
|
||||
// Read the page
|
||||
p, buf, err := guts_cli.ReadPage(path, uint64(pgId))
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadPage failed: %w", err)
|
||||
}
|
||||
|
||||
// Update and rewrite the page
|
||||
p.SetCount(0)
|
||||
p.SetOverflow(0)
|
||||
if !p.IsLeafPage() && !p.IsBranchPage() {
|
||||
return fmt.Errorf("can't clear elements in %q page", p.Typ())
|
||||
}
|
||||
|
||||
elementCnt := int(p.Count())
|
||||
|
||||
if elementCnt == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if start < 0 || start >= elementCnt {
|
||||
return fmt.Errorf("the start index (%d) is out of range [0, %d)", start, elementCnt)
|
||||
}
|
||||
|
||||
if (end < 0 || end > elementCnt) && end != -1 {
|
||||
return fmt.Errorf("the end index (%d) is out of range [0, %d]", end, elementCnt)
|
||||
}
|
||||
|
||||
if start > end && end != -1 {
|
||||
return fmt.Errorf("the start index (%d) is bigger than the end index (%d)", start, end)
|
||||
}
|
||||
|
||||
if start == end {
|
||||
return fmt.Errorf("invalid: the start index (%d) is equal to the end index (%d)", start, end)
|
||||
}
|
||||
|
||||
preOverflow := p.Overflow()
|
||||
|
||||
if end == int(p.Count()) || end == -1 {
|
||||
p.SetCount(uint16(start))
|
||||
p.SetOverflow(0)
|
||||
if preOverflow != 0 || p.IsBranchPage() {
|
||||
if err := clearFreelist(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inodes := common.ReadInodeFromPage(p)
|
||||
inodes = append(inodes[:start], inodes[end:]...)
|
||||
|
||||
p.SetCount(uint16(len(inodes)))
|
||||
dataWritten := common.WriteInodeToPage(inodes, p)
|
||||
|
||||
pageSize, _, err := guts_cli.ReadPageAndHWMSize(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadPageAndHWMSize failed: %w", err)
|
||||
}
|
||||
if dataWritten%uint32(pageSize) == 0 {
|
||||
p.SetOverflow(dataWritten/uint32(pageSize) - 1)
|
||||
} else {
|
||||
p.SetOverflow(dataWritten / uint32(pageSize))
|
||||
}
|
||||
}
|
||||
|
||||
if err := guts_cli.WritePage(path, buf); err != nil {
|
||||
return fmt.Errorf("WritePage failed: %w", err)
|
||||
}
|
||||
|
||||
if preOverflow != p.Overflow() || p.IsBranchPage() {
|
||||
return clearFreelist(path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func clearFreelist(path string) error {
|
||||
if err := clearFreelistAt(path, 0); err != nil {
|
||||
return fmt.Errorf("clearFreelist on meta page 0 failed: %w", err)
|
||||
}
|
||||
if err := clearFreelistAt(path, 1); err != nil {
|
||||
return fmt.Errorf("clearFreelist on meta page 1 failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func clearFreelistAt(path string, pageId uint64) error {
|
||||
_, buf, err := guts_cli.ReadPage(path, pageId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadPage %d failed: %w", pageId, err)
|
||||
}
|
||||
|
||||
meta := common.LoadPageMeta(buf)
|
||||
meta.SetFreelist(common.PgidNoFreelist)
|
||||
meta.SetChecksum(meta.Sum64())
|
||||
|
||||
if err := guts_cli.WritePage(path, buf); err != nil {
|
||||
return fmt.Errorf("WritePage %d failed: %w", pageId, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue