dgraph-io / badger

Fast key-value DB in Go.

Home Page:https://dgraph.io/badger

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Iterating in reverse Order - Empty Content

rebootcode opened this issue · comments

I am trying to Iterate in Reverse Order, but every time, I set Reverse to true. It gives empty value.

Below is code -

txn := db.NewTransaction(false)
defer txn.Discard()
err = db.View(func(txn *badger.Txn) error {
	DefaultIteratorOptions := badger.DefaultIteratorOptions
	DefaultIteratorOptions.Reverse = true
	it = txn.NewIterator(DefaultIteratorOptions)
	key := strconv.Itoa(t.Year()) + "-" + strconv.Itoa(int(t.Month())) + "-" + strconv.Itoa(int(t.Day()))
	prefix := []byte(key)
	for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
		item := it.Item()
		k := item.Key()
		v, err := item.ValueCopy([]byte(k))
		if err != nil {
			ctx.WriteString("Content not available")
			return err
		}
		blogList, err := decodeBlog(v)
		if err != nil {
			fmt.Println("Error: decode: " + err.Error())
		}
		buffer.WriteString("My Content First")
	}
})

When you seek for a key in reverse iterator, we find first key which is less than or equal to the seek key.
Say you have a list of keys

  1. "a:key1"
  2. "b:key2"
  3. "b:key3"
  4. "b:key4"
    when you seek for "b:" in reverse mode and iterate you will see only key "a:key1" and since you are doing validForPrefix check you won't see any data.

If you want all values for that prefix in reverse mode you should seek for
prefixKey := append([]byte("prefix"), 0xFF)

Just be careful of the case where you have keys of the form "prefix", 0xff, ... some other bytes ....

When seeking to the initial iterator position, it would be more correct to seek to the prefix but with the last byte incremented. So if your prefix is "prefix", then you should seek to "prefiy". (Watch out for the case where the last byte in the prefix is 0xff... you'll have to do something a bit tricker to avoid edge cases then).

This whole thing seems a bit tricky for users to get right. Maybe we need a SeekAfter method?

When you seek for a key in reverse iterator, we find first key which is less than or equal to the seek key.
Say you have a list of keys

"a:key1"
"b:key2"
"b:key3"
"b:key4"
when you seek for "b:" in reverse mode and iterate you will see only key "a:key1" and since you are doing validForPrefix check you won't see any data.
If you want all values for that prefix in reverse mode you should seek for
prefixKey := append([]byte("prefix"), 0xFF)

Wow, I just missed the whole context. Isn't reverse suppose to iterate the value for key b in reverse order like b:key4, b:key3, b:key2 ?

I tried, prefixing 0xFF too like below, yet i see empty results.

txn := db.NewTransaction(false)
		defer txn.Discard()
		err = db.View(func(txn *badger.Txn) error {
			DefaultIteratorOptions := badger.DefaultIteratorOptions
			DefaultIteratorOptions.Reverse = true
			it = txn.NewIterator(DefaultIteratorOptions)

			key := strconv.Itoa(t.Year()) + "-" + strconv.Itoa(int(t.Month())) + "-" + strconv.Itoa(int(t.Day()))

			prefix := append([]byte(key), 0xFF)
			for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
				item := it.Item()
				k := item.Key()
				v, err := item.ValueCopy([]byte(k))
				if err != nil {
					ctx.WriteString("Content not available")
					return err
				}
				blogList, err := decodeBlog(v)
				if err != nil {
					fmt.Println("Error: decode: " + err.Error())
				}
				buffer.WriteString("My Content First")
			}
                })

Just right out of bat, I find this strange:

				k := item.Key()
				v, err := item.ValueCopy([]byte(k))

Reusing an internal byte slice from item would cause weird issues -- and the one you're seeing might be related. So, fix that, and then re-run the iterator. Also, have a look at the tests which do reverse iteration, and see how they achieve the same results.

@manishrjain, Ok, the only other option I see is:-

k := item.Key()
v, err := item.Value()

But I read in FAQ https://github.com/dgraph-io/badger#frequently-asked-questions, where it says, If writes are getting stuck, then it's better to use Use Item::ValueCopy instead of Item::Value when retrieving a value.

Is there any other hack around available where reuse can be fixed.

Update: Even after using item.Value() the results are empty.

The new GetSequence method is more easy to adopt for my requirement, I am switching my option to nextSequence approach like an update here #346

Thanks