From 79b0f8d6fb207a9caceca121bb65356a95711aae Mon Sep 17 00:00:00 2001
From: twmht <qrnnis2623891@gmail.com>
Date: Sun, 23 Apr 2017 19:32:41 +0800
Subject: [PATCH] add seekForPrev

---
 README.rst               |  2 +-
 docs/installation.rst    |  4 ++--
 docs/tutorial/index.rst  | 19 +++++++++++++++++
 rocksdb/_rocksdb.pyx     | 16 ++++++++++++++
 rocksdb/iterator.pxd     |  1 +
 rocksdb/tests/test_db.py | 46 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 85 insertions(+), 3 deletions(-)

diff --git a/README.rst b/README.rst
index 3eecd93..af0b318 100644
--- a/README.rst
+++ b/README.rst
@@ -7,7 +7,7 @@ pyrocksdb
 =========
 
 Python bindings for RocksDB.
-See http://pyrocksdb.readthedocs.org for a more comprehensive install and usage description.
+See http://python-rocksdb.readthedocs.io/en/latest/ for a more comprehensive install and usage description.
 
 
 Quick Install
diff --git a/docs/installation.rst b/docs/installation.rst
index 91daa54..114f3ad 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -40,7 +40,7 @@ These varialbes are picked up by the compiler, linker and loader
     export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:`pwd`
     export LIBRARY_PATH=${LIBRARY_PATH}:`pwd`
 
-Building pyrocksdb
+Building python-rocksdb
 ------------------
 
 .. code-block:: bash
@@ -50,4 +50,4 @@ Building pyrocksdb
     cd pyrocks_test
     . bin/active
     pip install "Cython>=0.20"
-    pip install git+git://github.com/stephan-hof/pyrocksdb.git
+    pip install git+git://github.com/twmht/python-rocksdb.git
diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst
index d7a326e..e804300 100644
--- a/docs/tutorial/index.rst
+++ b/docs/tutorial/index.rst
@@ -137,6 +137,25 @@ Reversed iteration ::
     # prints [(b'key3', b'v3'), (b'key2', b'v2'), (b'key1', b'v1')]
     print list(reversed(it))
 
+SeekForPrev (Take the example from `https://github.com/facebook/rocksdb/wiki/SeekForPrev`)::
+
+    db.put(b'a1', b'a1_value')
+    db.put(b'a3', b'a3_value')
+    db.put(b'b1', b'b1_value')
+    db.put(b'b2', b'b2_value')
+    db.put(b'c2', b'c2_value')
+    db.put(b'c4', b'c4_value')
+
+    it = db.iteritems()
+    it.seek(b'a1')
+    assertEqual(it.get(), (b'a1', b'a1_value'))
+    it.seek(b'a3')
+    assertEqual(it.get(), (b'a3', b'a3_value'))
+    it.seek_for_prev(b'c4')
+    assertEqual(it.get(), (b'c4', b'c4_value'))
+    it.seek_for_prev(b'c3')
+    assertEqual(it.get(), (b'c2', b'c2_value'))
+
 
 Snapshots
 =========
diff --git a/rocksdb/_rocksdb.pyx b/rocksdb/_rocksdb.pyx
index 4c23328..670faae 100644
--- a/rocksdb/_rocksdb.pyx
+++ b/rocksdb/_rocksdb.pyx
@@ -1766,6 +1766,10 @@ cdef class BaseIterator(object):
         check_status(self.ptr.status())
         return ret
 
+    def get(self):
+        cdef object ret = self.get_ob()
+        return ret
+
     def __reversed__(self):
         return ReversedIterator(self)
 
@@ -1785,6 +1789,12 @@ cdef class BaseIterator(object):
             self.ptr.Seek(c_key)
         check_status(self.ptr.status())
 
+    cpdef seek_for_prev(self, key):
+        cdef Slice c_key = bytes_to_slice(key)
+        with nogil:
+            self.ptr.SeekForPrev(c_key)
+        check_status(self.ptr.status())
+
     cdef object get_ob(self):
         return None
 
@@ -1833,6 +1843,12 @@ cdef class ReversedIterator(object):
     def seek(self, key):
         self.it.seek(key)
 
+    def seek_for_prev(self, key):
+        self.it.seek_for_prev(key)
+
+    def get(self):
+        return self.it.get()
+
     def __iter__(self):
         return self
 
diff --git a/rocksdb/iterator.pxd b/rocksdb/iterator.pxd
index 5cfc24b..5cd34a8 100644
--- a/rocksdb/iterator.pxd
+++ b/rocksdb/iterator.pxd
@@ -10,6 +10,7 @@ cdef extern from "rocksdb/iterator.h" namespace "rocksdb":
         void Seek(const Slice&) nogil except+
         void Next() nogil except+
         void Prev() nogil except+
+        void SeekForPrev(const Slice&) nogil except+
         Slice key() nogil except+
         Slice value() nogil except+
         Status status() nogil except+
diff --git a/rocksdb/tests/test_db.py b/rocksdb/tests/test_db.py
index 7eebd27..c180e4f 100644
--- a/rocksdb/tests/test_db.py
+++ b/rocksdb/tests/test_db.py
@@ -106,6 +106,52 @@ class TestDB(unittest.TestCase, TestHelper):
         self.assertEqual((True, None), self.db.key_may_exist(b'a'))
         self.assertEqual((True, b'1'), self.db.key_may_exist(b'a', True))
 
+    def test_seek_for_prev(self):
+        self.db.put(b'a1', b'a1_value')
+        self.db.put(b'a3', b'a3_value')
+        self.db.put(b'b1', b'b1_value')
+        self.db.put(b'b2', b'b2_value')
+        self.db.put(b'c2', b'c2_value')
+        self.db.put(b'c4', b'c4_value')
+
+        self.assertEqual(self.db.get(b'a1'), b'a1_value')
+
+        it = self.db.iterkeys()
+
+        it.seek(b'a1')
+        self.assertEqual(it.get(), b'a1')
+        it.seek(b'a3')
+        self.assertEqual(it.get(), b'a3')
+        it.seek_for_prev(b'c4')
+        self.assertEqual(it.get(), b'c4')
+        it.seek_for_prev(b'c3')
+        self.assertEqual(it.get(), b'c2')
+
+        it = self.db.itervalues()
+        it.seek(b'a1')
+        self.assertEqual(it.get(), b'a1_value')
+        it.seek(b'a3')
+        self.assertEqual(it.get(), b'a3_value')
+        it.seek_for_prev(b'c4')
+        self.assertEqual(it.get(), b'c4_value')
+        it.seek_for_prev(b'c3')
+        self.assertEqual(it.get(), b'c2_value')
+
+        it = self.db.iteritems()
+        it.seek(b'a1')
+        self.assertEqual(it.get(), (b'a1', b'a1_value'))
+        it.seek(b'a3')
+        self.assertEqual(it.get(), (b'a3', b'a3_value'))
+        it.seek_for_prev(b'c4')
+        self.assertEqual(it.get(), (b'c4', b'c4_value'))
+        it.seek_for_prev(b'c3')
+        self.assertEqual(it.get(), (b'c2', b'c2_value'))
+
+        reverse_it = reversed(it)
+        it.seek_for_prev(b'c3')
+        self.assertEqual(it.get(), (b'c2', b'c2_value'))
+
+
     def test_iter_keys(self):
         for x in range(300):
             self.db.put(int_to_bytes(x), int_to_bytes(x))
-- 
GitLab