diff --git a/GNUmakefile.in b/GNUmakefile.in index 746a1f9..0c75368 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -88,7 +88,7 @@ stamp-h: config.h.in config.status echo > stamp-h clean: - rm -f mtd mtclient mttest test_string test_atomics *.o libjson.a + rm -f mtd mtclient mttest scantest test_string test_atomics *.o libjson.a rm -rf .deps DEPFILES := $(wildcard $(DEPSDIR)/*.d) diff --git a/masstree.hh b/masstree.hh index ea7d5c0..b08fafc 100644 --- a/masstree.hh +++ b/masstree.hh @@ -60,6 +60,7 @@ class basic_table { typedef typename P::threadinfo_type threadinfo; typedef unlocked_tcursor
unlocked_cursor_type; typedef tcursor
cursor_type;
+ typedef std::pair ::iterator
+ : std::iterator * table, threadinfo* ti, Str firstkey = "");
+ static iterator make_end(basic_table * table, threadinfo *ti);
+
+ itvalue_type& operator*() { return pair_; };
+ itvalue_type* operator->() { return &pair_; };
+ bool operator==(iterator& rhs) { return (end_ == rhs.end_) && (end_ || ka_.compare(rhs.ka_) == 0); };
+ bool operator!=(iterator& rhs) { return !(*this == rhs); };
+ bool operator<(iterator& rhs) { return (!end_ && rhs.end_) || ka_.compare(rhs.ka_) < 0; };
+ bool operator<=(iterator& rhs) { return *this < rhs || *this == rhs; };
+ iterator operator++() { advance(); return *this; };
+ iterator operator++(int) { iterator it = *this; advance(); return it; };
+
+ private:
+ basic_table * table_;
+ threadinfo* ti_;
+ key_type ka_;
+ itvalue_type pair_;
+ bool emit_equal_;
+ bool end_;
+ union {
+ ikey_type x[(MASSTREE_MAXKEYLEN + sizeof(ikey_type) - 1)/sizeof(ikey_type)];
+ char s[MASSTREE_MAXKEYLEN];
+ } keybuf_;
+
+ void advance(bool emit_equal = false);
+
+
+ // Debugging support.
+ int id_;
+ static int count_;
+
+ void dprintf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ fprintf(stderr, "it%d: ", id_);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ }
+};
+
+template ::iterator::count_ = 0;
+
+template ::iterator::iterator(basic_table * table, threadinfo* ti, Str firstkey)
+ : table_(table), ti_(ti), emit_equal_(true), end_(false), id_(count_++) {
+ masstree_precondition(firstkey.len <= (int) sizeof(keybuf_));
+ memcpy(keybuf_.s, firstkey.s, firstkey.len);
+ ka_ = key_type(keybuf_.s, firstkey.len);
+
+ advance(true);
+};
+
+template ::iterator
+basic_table ::iterator::make_end(basic_table * table, threadinfo *ti) {
+ iterator it = iterator(table, ti);
+ it.end_ = true;
+ return it;
+}
+
+template ::iterator::advance(bool emit_equal) {
+ int ki;
+ bool try_next_key = true;
+ bool try_next_index = true;
+ leaf_type* n;
+ nodeversion_type v;
+ node_type* root;
+ permuter_type perm;
+ Str suffix;
+ char suffixbuf[MASSTREE_MAXKEYLEN];
+
+ retry_root:
+ ka_.unshift_all();
+ root = table_->root();
+ n = root->reach_leaf(ka_, v, *ti_);
+ perm = n->permutation();
+ ki = bound_type::lower(ka_, *n).i;
+
+ retry:
+ if (v.deleted())
+ goto retry_root;
+
+ int kp = (unsigned(ki) < unsigned(perm.size())) ? perm[ki] : -1;
+ if (kp < 0) {
+ n = n->safe_next();
+ if (!n) {
+ if (!try_next_key) {
+ end_ = true;
+ return;
+ }
+
+ if (ka_.is_shifted())
+ ka_.unshift();
+ while (ka_.increment() && ka_.is_shifted())
+ ka_.unshift();
+ ka_.assign_store_ikey(ka_.ikey());
+ try_next_key = false;
+ goto retry_root;
+ }
+ perm = n->permutation();
+ v = n->stable();
+ ki = bound_type::lower(ka_, *n).i;
+ goto retry;
+ }
+
+ int keylenx = n->keylenx_[kp];
+ ikey_type ikey = n->ikey0_[kp];
+ leafvalue_type entry = n->lv_[kp];
+ if (n->keylenx_has_ksuf(keylenx)) {
+ suffix = n->ksuf(kp);
+ memcpy(suffixbuf, suffix.s, suffix.len);
+ suffix.s = suffixbuf;
+ }
+
+ if (n->has_changed(v))
+ goto retry_root;
+
+ ka_.assign_store_ikey(ikey);
+ if (n->keylenx_is_layer(keylenx)) {
+ ka_.shift();
+ root = entry.layer();
+ n = root->reach_leaf(ka_, v, *ti_);
+ perm = n->permutation();
+ ki = bound_type::lower(ka_, *n).i;
+ goto retry;
+ }
+
+ // XXX This condition is suspect.
+ if (!emit_equal && try_next_index) {
+ try_next_index = false;
+ ki++;
+ goto retry;
+ }
+
+ int keylen = keylenx;
+ if (n->keylenx_has_ksuf(keylenx)) {
+ keylen = ka_.assign_store_suffix(suffix);
+ }
+ ka_.assign_store_length(keylen);
+ ka_.unshift_all();
+ pair_ = itvalue_type(ka_, entry.value());
+}
+
+template ::iterator
+basic_table ::begin(threadinfo& ti) {
+ return iterator(this, &ti);
+}
+
+template ::iterator
+basic_table ::end(threadinfo& ti) {
+ return iterator::make_end(this, &ti);
+}
+
+template ::iterator
+basic_table ::iterate_from(Str firstkey, threadinfo& ti) {
+ return iterator(this, &ti, firstkey);
+}
+}
+#endif
diff --git a/masstree_key.hh b/masstree_key.hh
index 4d1e8a7..f003348 100644
--- a/masstree_key.hh
+++ b/masstree_key.hh
@@ -185,7 +185,6 @@ class key {
// Return true iff wrapped.
if (has_suffix()) {
++ikey0_;
- len_ = 1;
return unlikely(!ikey0_);
} else {
++len_;
diff --git a/query_masstree.cc b/query_masstree.cc
index 5c88402..4e3a18a 100644
--- a/query_masstree.cc
+++ b/query_masstree.cc
@@ -19,6 +19,7 @@
#include "masstree_tcursor.hh"
#include "masstree_get.hh"
#include "masstree_insert.hh"
+#include "masstree_iterator.hh"
#include "masstree_split.hh"
#include "masstree_remove.hh"
#include "masstree_scan.hh"
@@ -413,6 +414,45 @@ void query_table ::test(threadinfo& ti) {
// XXX destroy tree
}
+template ::iterator_test(threadinfo& ti) {
+ typedef typename basic_table ::iterator iterator;
+
+ query_table t;
+ t.initialize(ti);
+ query ::print(FILE *f, int indent) const {
table_.print(f, indent);
diff --git a/query_masstree.hh b/query_masstree.hh
index eb99899..98434e6 100644
--- a/query_masstree.hh
+++ b/query_masstree.hh
@@ -61,6 +61,7 @@ class query_table {
void print(FILE* f, int indent) const;
static void test(threadinfo& ti);
+ static void iterator_test(threadinfo& ti);
static const char* name() {
return "mb";
diff --git a/scantest.cc b/scantest.cc
index 7a30549..04b3afe 100644
--- a/scantest.cc
+++ b/scantest.cc
@@ -10,9 +10,21 @@ kvtimestamp_t initial_timestamp;
int
main(int argc, char *argv[])
{
- (void) argc;
- (void) argv;
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s