Skip to content

Commit ff745de

Browse files
committed
Add item copy
1 parent bc74fea commit ff745de

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

iterator.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,30 @@ func (item *Item) String() string {
6363
return fmt.Sprintf("key=%q, version=%d, meta=%x", item.Key(), item.Version(), item.meta)
6464
}
6565

66+
// Copy returns a new copy of item that can be safely used outside of a
67+
// iterator loop but before a transaction is commited/discarded.
68+
func (item *Item) SafeCopy() *Item {
69+
i := &Item{}
70+
i.key = y.SafeCopy(nil, item.key)
71+
i.vptr = y.SafeCopy(nil, item.vptr)
72+
i.txn = item.txn
73+
i.meta = item.meta
74+
i.status = item.status
75+
76+
return i
77+
}
78+
79+
func (item *Item) Copy() *Item {
80+
i := &Item{}
81+
i.key = y.Copy(item.key)
82+
i.vptr = y.Copy(item.vptr)
83+
i.txn = item.txn
84+
i.meta = item.meta
85+
i.status = item.status
86+
87+
return i
88+
}
89+
6690
// Key returns the key.
6791
//
6892
// Key is only valid as long as item is valid, or transaction is valid. If you need to use it

iterator_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,55 @@ func BenchmarkIteratePrefixSingleKey(b *testing.B) {
415415
}
416416
})
417417
}
418+
419+
func TestItemCopyDuringIterator(t *testing.T) {
420+
dir, err := ioutil.TempDir(".", "badger-test")
421+
y.Check(err)
422+
defer removeDir(dir)
423+
opts := getTestOptions(dir)
424+
db, err := Open(opts)
425+
y.Check(err)
426+
defer db.Close()
427+
428+
N := 100 // Should generate around 80 SSTables.
429+
val := "OK"
430+
bkey := func(i int) []byte {
431+
return []byte(fmt.Sprintf("%06d", i))
432+
}
433+
434+
batch := db.NewWriteBatch()
435+
testItems := make([][2][]byte, N)
436+
for i := 0; i < N; i++ {
437+
k := bkey(i)
438+
v := []byte(fmt.Sprintf("%s%d", val, i))
439+
testItems[i] = [2][]byte{k, v}
440+
y.Check(batch.Set(k, v))
441+
}
442+
y.Check(batch.Flush())
443+
444+
txn := db.NewTransaction(false)
445+
opt := DefaultIteratorOptions
446+
opt.PrefetchValues = false
447+
itr := txn.NewIterator(opt)
448+
449+
items := make([]*Item, N)
450+
i := 0
451+
// collect copied items
452+
for itr.Rewind(); itr.Valid(); itr.Next() {
453+
item := itr.Item()
454+
items[i] = item.Copy()
455+
y.Check(err)
456+
i++
457+
}
458+
459+
for i, item := range items {
460+
key := item.Key()
461+
val, err := item.ValueCopy(nil)
462+
y.Check(err)
463+
if !bytes.Equal(key, testItems[i][0]) {
464+
t.Error("Expected:", testItems[i][0], ", got:", key)
465+
} else if !bytes.Equal(val, testItems[i][1]) {
466+
t.Error("Expected:", testItems[i][1], ", got:", val)
467+
}
468+
}
469+
}

0 commit comments

Comments
 (0)