Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support All() #32 && Modify Records type && Entries type #34

Merged
merged 2 commits into from
Apr 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions bptree.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ type (
BPTree struct {
root *Node
ValidKeyCount int // the number of the key that not expired or deleted
FirstKey []byte
}

// Records records multi-records as result when is called Range or PrefixScan.
Records map[string]*Record
Records []*Record

// Node records keys and pointers and parent node.
Node struct {
Expand Down Expand Up @@ -126,6 +127,33 @@ func compare(a, b []byte) int {
return bytes.Compare(a, b)
}

func (t *BPTree) getAll() (numFound int, keys [][]byte, pointers []interface{}) {
var (
n *Node
i, j int
)

if n = t.FindLeaf(t.FirstKey); n == nil {
return 0, nil, nil
}

j = 0

for n != nil {
for i = j; i < n.KeysNum; i++ {
keys = append(keys, n.Keys[i])
pointers = append(pointers, n.pointers[i])
numFound++
}

n, _ = n.pointers[order-1].(*Node)

j = 0
}

return
}

// findRange returns numFound,keys and pointers at the given start key and end key.
func (t *BPTree) findRange(start, end []byte) (numFound int, keys [][]byte, pointers []interface{}) {
var (
Expand Down Expand Up @@ -162,6 +190,11 @@ func (t *BPTree) findRange(start, end []byte) (numFound int, keys [][]byte, poin
return
}

// All returns all records in the b+ tree.
func (t *BPTree) All() (records Records, err error) {
return getRecordWrapper(t.getAll())
}

// Range returns records at the given start key and end key.
func (t *BPTree) Range(start, end []byte) (records Records, err error) {
if compare(start, end) > 0 {
Expand All @@ -177,9 +210,9 @@ func getRecordWrapper(numFound int, keys [][]byte, pointers []interface{}) (reco
return nil, ErrScansNoResult
}

records = make(Records)
records = Records{}
for i := 0; i < numFound; i++ {
records[string(keys[i])] = pointers[i].(*Record)
records = append(records, pointers[i].(*Record))
}

return records, nil
Expand Down Expand Up @@ -272,6 +305,10 @@ func (t *BPTree) startNewTree(key []byte, pointer *Record) error {
// Insert inserts record to the b+ tree,
// and if the key exists, update the record and the counter(if countFlag set true,it will start count).
func (t *BPTree) Insert(key []byte, e *Entry, h *Hint, countFlag bool) error {
if compare(key, t.FirstKey) < 0 {
t.FirstKey = key
}

if r, err := t.Find(key); err == nil && r != nil {
if countFlag && h.meta.Flag == DataDeleteFlag && r.H.meta.Flag != DataDeleteFlag && t.ValidKeyCount > 0 {
t.ValidKeyCount--
Expand Down
64 changes: 44 additions & 20 deletions bptree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var (

func setup(t *testing.T, limit int) {
tree = NewTree()
for i := 1; i <= 100; i++ {
for i := 0; i < 100; i++ {
key := []byte("key_" + fmt.Sprintf("%03d", i))
val := []byte("val_" + fmt.Sprintf("%03d", i))
err := tree.Insert(key, &Entry{Key: key, Value: val}, &Hint{key: key, meta: &MetaData{
Expand All @@ -38,13 +38,14 @@ func setup(t *testing.T, limit int) {
}
}

expected = make(Records, limit)
for i := 1; i <= limit; i++ {
expected = Records{}
for i := 0; i < limit; i++ {
key := []byte("key_" + fmt.Sprintf("%03d", i))
val := []byte("val_" + fmt.Sprintf("%03d", i))
expected[string(key)] = &Record{E: &Entry{Key: key, Value: val}, H: &Hint{key: key, meta: &MetaData{

expected = append(expected, &Record{E: &Entry{Key: key, Value: val}, H: &Hint{key: key, meta: &MetaData{
Flag: DataSetFlag,
}}}
}}})
}
}

Expand Down Expand Up @@ -80,8 +81,10 @@ func TestBPTree_PrefixScan(t *testing.T) {
t.Fatal(err)
}

if !reflect.DeepEqual(expected, rs) {
t.Errorf("err prefix Scan. got %v want %v", rs, expected)
for i, e := range rs {
if string(expected[i].E.Key) != string(e.E.Key) {
t.Errorf("err prefix Scan. got %v want %v", string(expected[i].E.Key), string(e.E.Key))
}
}

_, err = tree.PrefixScan([]byte("key_xx"), limit)
Expand All @@ -104,12 +107,28 @@ func TestBPTree_PrefixScan(t *testing.T) {
if err != nil {
t.Error("err prefix Scan")
}
_, err = tree.PrefixScan([]byte("key_100"), limit)
_, err = tree.PrefixScan([]byte("key_099"), limit)
if err != nil {
t.Error("err prefix Scan")
}
}

func TestBPTree_All(t *testing.T) {
tree = NewTree()
_, err := tree.All()
if err == nil {
t.Fatal("err scan all")
}
setup(t, 100)
rs, err := tree.All()
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, rs) {
t.Errorf("err scan all. got %v want %v", rs, expected)
}
}

func TestBPTree_Range(t *testing.T) {
tree = NewTree()
_, err := tree.Range([]byte("key_001"), []byte("key_010"))
Expand All @@ -120,13 +139,15 @@ func TestBPTree_Range(t *testing.T) {
limit := 10
setup(t, limit)
// range scan
rs, err := tree.Range([]byte("key_001"), []byte("key_010"))
rs, err := tree.Range([]byte("key_000"), []byte("key_009"))
if err != nil {
t.Fatal(err)
}

if !reflect.DeepEqual(expected, rs) {
t.Errorf("err range Scan. got %v want %v", rs, expected)
for i, e := range rs {
if string(expected[i].E.Key) != string(e.E.Key) {
t.Errorf("err prefix Scan. got %v want %v", string(expected[i].E.Key), string(e.E.Key))
}
}

_, err = tree.Range([]byte("key_101"), []byte("key_110"))
Expand All @@ -145,7 +166,7 @@ func TestBPTree_FindLeaf(t *testing.T) {
setup(t, limit)

node := tree.FindLeaf([]byte("key_001"))
if string(node.Keys[0]) != "key_001" {
if string(node.Keys[0]) != "key_000" {
t.Error("err TestBPTree_FindLeaf")
}
}
Expand Down Expand Up @@ -174,7 +195,7 @@ func TestBPTree_Update(t *testing.T) {
limit := 10
setup(t, limit)

for i := 1; i <= 100; i++ {
for i := 0; i <= 100; i++ {
key := []byte("key_" + fmt.Sprintf("%03d", i))
val := []byte("val_modify" + fmt.Sprintf("%03d", i))
err := tree.Insert(key, &Entry{Key: key, Value: val}, &Hint{key: key, meta: &MetaData{
Expand All @@ -185,22 +206,25 @@ func TestBPTree_Update(t *testing.T) {
}
}

expected = make(Records, limit)
for i := 1; i <= limit; i++ {
expected = Records{}
for i := 0; i <= limit; i++ {
key := []byte("key_" + fmt.Sprintf("%03d", i))
val := []byte("val_modify" + fmt.Sprintf("%03d", i))
expected[string(key)] = &Record{E: &Entry{Key: key, Value: val}, H: &Hint{key: key, meta: &MetaData{

expected = append(expected, &Record{E: &Entry{Key: key, Value: val}, H: &Hint{key: key, meta: &MetaData{
Flag: DataSetFlag}},
}
})
}

rs, err := tree.Range([]byte("key_001"), []byte("key_010"))
rs, err := tree.Range([]byte("key_000"), []byte("key_009"))
if err != nil {
t.Error("err TestBPTree_Update tree.Range scan")
}

if !reflect.DeepEqual(expected, rs) {
t.Errorf("err TestBPTree_Update range Scan. got %v want %v", rs, expected)
for i, e := range rs {
if string(expected[i].E.Key) != string(e.E.Key) {
t.Errorf("err prefix Scan. got %v want %v", string(expected[i].E.Key), string(e.E.Key))
}
}

//delete
Expand Down
5 changes: 3 additions & 2 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,11 @@ type (
// ListIdx represents the list index
ListIdx map[string]*list.List

// Entries represents entry map
Entries map[string]*Entry
// Entries represents entries
Entries []*Entry
)


// Open returns a newly initialized DB object.
func Open(opt Options) (*DB, error) {
db := &DB{
Expand Down
3 changes: 3 additions & 0 deletions tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ var (
// ErrKeyEmpty is returned if an empty key is passed on an update function.
ErrKeyEmpty = errors.New("key cannot be empty")

// ErrBucketEmpty is returned if bucket is empty.
ErrBucketEmpty = errors.New("bucket is empty")

// ErrRangeScan is returned when range scanning not found the result
ErrRangeScan = errors.New("range scans not found")

Expand Down
37 changes: 32 additions & 5 deletions tx_bptree.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,40 @@ func (tx *Tx) Get(bucket string, key []byte) (e *Entry, err error) {
return nil, errors.New("not found bucket:" + bucket + ",key:" + string(key))
}

//GetAll returns all keys and values of the bucket stored at given bucket.
func (tx *Tx) GetAll(bucket string) (entries Entries, err error) {
if err := tx.checkTxIsClosed(); err != nil {
return nil, err
}

entries = Entries{}

if index, ok := tx.db.BPTreeIdx[bucket]; ok {
records, err := index.All()
if err != nil {
return nil, ErrBucketEmpty
}

entries, err = tx.getHintIdxDataItemsWrapper(records, ScanNoLimit, entries, RangeScan)
if err != nil {
return nil, ErrBucketEmpty
}
}

if len(entries) == 0 {
return nil, ErrBucketEmpty
}

return
}

// RangeScan query a range at given bucket, start and end slice.
func (tx *Tx) RangeScan(bucket string, start, end []byte) (entries Entries, err error) {
if err := tx.checkTxIsClosed(); err != nil {
return nil, err
}

entries = make(Entries)
entries = Entries{}

if index, ok := tx.db.BPTreeIdx[bucket]; ok {
records, err := index.Range(start, end)
Expand Down Expand Up @@ -102,7 +129,7 @@ func (tx *Tx) PrefixScan(bucket string, prefix []byte, limitNum int) (es Entries
return nil, err
}

es = make(Entries)
es = Entries{}

if idx, ok := tx.db.BPTreeIdx[bucket]; ok {
records, err := idx.PrefixScan(prefix, limitNum)
Expand Down Expand Up @@ -134,7 +161,7 @@ func (tx *Tx) Delete(bucket string, key []byte) error {

// getHintIdxDataItemsWrapper returns wrapped entries when prefix scanning or range scanning.
func (tx *Tx) getHintIdxDataItemsWrapper(records Records, limitNum int, es Entries, scanMode string) (Entries, error) {
for k, r := range records {
for _, r := range records {
if r.H.meta.Flag == DataDeleteFlag || r.IsExpired() {
continue
}
Expand All @@ -149,7 +176,7 @@ func (tx *Tx) getHintIdxDataItemsWrapper(records Records, limitNum int, es Entri
return nil, err
}
if item, err := df.ReadAt(int(r.H.dataPos)); err == nil {
es[k] = item
es = append(es, item)
} else {
df.rwManager.Close()
return nil, fmt.Errorf("HintIdx r.Hi.dataPos %d, err %s", r.H.dataPos, err)
Expand All @@ -158,7 +185,7 @@ func (tx *Tx) getHintIdxDataItemsWrapper(records Records, limitNum int, es Entri
}

if idxMode == HintKeyValAndRAMIdxMode {
es[k] = r.E
es = append(es, r.E)
}
}
}
Expand Down
Loading