Skip to content

Commit db7457b

Browse files
committed
Naive iterator
1 parent 328a227 commit db7457b

File tree

7 files changed

+258
-5
lines changed

7 files changed

+258
-5
lines changed

GNUmakefile.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ stamp-h: config.h.in config.status
8888
echo > stamp-h
8989

9090
clean:
91-
rm -f mtd mtclient mttest test_string test_atomics *.o libjson.a
91+
rm -f mtd mtclient mttest scantest test_string test_atomics *.o libjson.a
9292
rm -rf .deps
9393

9494
DEPFILES := $(wildcard $(DEPSDIR)/*.d)

masstree.hh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class basic_table {
6060
typedef typename P::threadinfo_type threadinfo;
6161
typedef unlocked_tcursor<P> unlocked_cursor_type;
6262
typedef tcursor<P> cursor_type;
63+
typedef std::pair<Str, value_type> itvalue_type;
6364

6465
inline basic_table();
6566

@@ -76,6 +77,11 @@ class basic_table {
7677
template <typename F>
7778
int rscan(Str firstkey, bool matchfirst, F& scanner, threadinfo& ti) const;
7879

80+
class iterator;
81+
iterator begin(threadinfo& ti);
82+
iterator iterate_from(Str firstkey, threadinfo& ti);
83+
iterator end(threadinfo& ti);
84+
7985
template <typename F>
8086
inline int modify(Str key, F& f, threadinfo& ti);
8187
template <typename F>

masstree_iterator.hh

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/* Masstree
2+
* Eddie Kohler, Yandong Mao, Robert Morris
3+
* Copyright (c) 2012-2014 President and Fellows of Harvard College
4+
* Copyright (c) 2012-2014 Massachusetts Institute of Technology
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a
7+
* copy of this software and associated documentation files (the "Software"),
8+
* to deal in the Software without restriction, subject to the conditions
9+
* listed in the Masstree LICENSE file. These conditions include: you must
10+
* preserve this copyright notice, and you cannot mention the copyright
11+
* holders in advertising related to the Software without their permission.
12+
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
13+
* notice is a summary of the Masstree LICENSE file; the license in that file
14+
* is legally binding.
15+
*/
16+
#ifndef MASSTREE_ITERATOR_HH
17+
#define MASSTREE_ITERATOR_HH
18+
#include "masstree_scan.hh"
19+
20+
namespace Masstree {
21+
template <typename P>
22+
class basic_table<P>::iterator
23+
: std::iterator<std::forward_iterator_tag, itvalue_type> {
24+
typedef typename P::ikey_type ikey_type;
25+
typedef typename node_type::key_type key_type;
26+
typedef typename node_type::leaf_type::leafvalue_type leafvalue_type;
27+
typedef typename node_type::nodeversion_type nodeversion_type;
28+
typedef typename leaf_type::permuter_type permuter_type;
29+
typedef typename leaf_type::bound_type bound_type;
30+
31+
public:
32+
iterator(basic_table<P>* table, threadinfo* ti, Str firstkey = "");
33+
static iterator make_end(basic_table<P>* table, threadinfo *ti);
34+
35+
itvalue_type& operator*() { return pair_; };
36+
itvalue_type* operator->() { return &pair_; };
37+
bool operator==(iterator& rhs) { return (end_ == rhs.end_) && (end_ || ka_.compare(rhs.ka_) == 0); };
38+
bool operator!=(iterator& rhs) { return !(*this == rhs); };
39+
bool operator<(iterator& rhs) { return (!end_ && rhs.end_) || ka_.compare(rhs.ka_) < 0; };
40+
bool operator<=(iterator& rhs) { return *this < rhs || *this == rhs; };
41+
iterator operator++() { advance(); return *this; };
42+
iterator operator++(int) { iterator it = *this; advance(); return it; };
43+
44+
private:
45+
basic_table<P>* table_;
46+
threadinfo* ti_;
47+
key_type ka_;
48+
itvalue_type pair_;
49+
bool emit_equal_;
50+
bool end_;
51+
union {
52+
ikey_type x[(MASSTREE_MAXKEYLEN + sizeof(ikey_type) - 1)/sizeof(ikey_type)];
53+
char s[MASSTREE_MAXKEYLEN];
54+
} keybuf_;
55+
56+
void advance(bool emit_equal = false);
57+
58+
59+
// Debugging support.
60+
int id_;
61+
static int count_;
62+
63+
void dprintf(const char *format, ...) {
64+
va_list args;
65+
va_start(args, format);
66+
fprintf(stderr, "it%d: ", id_);
67+
vfprintf(stderr, format, args);
68+
va_end(args);
69+
}
70+
};
71+
72+
template <typename P> int basic_table<P>::iterator::count_ = 0;
73+
74+
template <typename P>
75+
basic_table<P>::iterator::iterator(basic_table<P>* table, threadinfo* ti, Str firstkey)
76+
: table_(table), ti_(ti), emit_equal_(true), end_(false), id_(count_++) {
77+
masstree_precondition(firstkey.len <= (int) sizeof(keybuf_));
78+
memcpy(keybuf_.s, firstkey.s, firstkey.len);
79+
ka_ = key_type(keybuf_.s, firstkey.len);
80+
81+
advance(true);
82+
};
83+
84+
template <typename P>
85+
typename basic_table<P>::iterator
86+
basic_table<P>::iterator::make_end(basic_table<P>* table, threadinfo *ti) {
87+
iterator it = iterator(table, ti);
88+
it.end_ = true;
89+
return it;
90+
}
91+
92+
template <typename P>
93+
void
94+
basic_table<P>::iterator::advance(bool emit_equal) {
95+
int ki;
96+
bool try_next_key = true;
97+
bool try_next_index = true;
98+
leaf_type* n;
99+
nodeversion_type v;
100+
node_type* root;
101+
permuter_type perm;
102+
Str suffix;
103+
char suffixbuf[MASSTREE_MAXKEYLEN];
104+
105+
retry_root:
106+
ka_.unshift_all();
107+
root = table_->root();
108+
n = root->reach_leaf(ka_, v, *ti_);
109+
perm = n->permutation();
110+
ki = bound_type::lower(ka_, *n).i;
111+
112+
retry:
113+
if (v.deleted())
114+
goto retry_root;
115+
116+
int kp = (unsigned(ki) < unsigned(perm.size())) ? perm[ki] : -1;
117+
if (kp < 0) {
118+
n = n->safe_next();
119+
if (!n) {
120+
if (!try_next_key) {
121+
end_ = true;
122+
return;
123+
}
124+
125+
if (ka_.is_shifted())
126+
ka_.unshift();
127+
while (ka_.increment() && ka_.is_shifted())
128+
ka_.unshift();
129+
ka_.assign_store_ikey(ka_.ikey());
130+
try_next_key = false;
131+
goto retry_root;
132+
}
133+
perm = n->permutation();
134+
v = n->stable();
135+
ki = bound_type::lower(ka_, *n).i;
136+
goto retry;
137+
}
138+
139+
int keylenx = n->keylenx_[kp];
140+
ikey_type ikey = n->ikey0_[kp];
141+
leafvalue_type entry = n->lv_[kp];
142+
if (n->keylenx_has_ksuf(keylenx)) {
143+
suffix = n->ksuf(kp);
144+
memcpy(suffixbuf, suffix.s, suffix.len);
145+
suffix.s = suffixbuf;
146+
}
147+
148+
if (n->has_changed(v))
149+
goto retry_root;
150+
151+
ka_.assign_store_ikey(ikey);
152+
if (n->keylenx_is_layer(keylenx)) {
153+
ka_.shift();
154+
root = entry.layer();
155+
n = root->reach_leaf(ka_, v, *ti_);
156+
perm = n->permutation();
157+
ki = bound_type::lower(ka_, *n).i;
158+
goto retry;
159+
}
160+
161+
// XXX This condition is suspect.
162+
if (!emit_equal && try_next_index) {
163+
try_next_index = false;
164+
ki++;
165+
goto retry;
166+
}
167+
168+
int keylen = keylenx;
169+
if (n->keylenx_has_ksuf(keylenx)) {
170+
keylen = ka_.assign_store_suffix(suffix);
171+
}
172+
ka_.assign_store_length(keylen);
173+
ka_.unshift_all();
174+
pair_ = itvalue_type(ka_, entry.value());
175+
}
176+
177+
template <typename P>
178+
typename basic_table<P>::iterator
179+
basic_table<P>::begin(threadinfo& ti) {
180+
return iterator(this, &ti);
181+
}
182+
183+
template <typename P>
184+
typename basic_table<P>::iterator
185+
basic_table<P>::end(threadinfo& ti) {
186+
return iterator::make_end(this, &ti);
187+
}
188+
189+
template <typename P>
190+
typename basic_table<P>::iterator
191+
basic_table<P>::iterate_from(Str firstkey, threadinfo& ti) {
192+
return iterator(this, &ti, firstkey);
193+
}
194+
}
195+
#endif

masstree_key.hh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ class key {
185185
// Return true iff wrapped.
186186
if (has_suffix()) {
187187
++ikey0_;
188-
len_ = 1;
189188
return unlikely(!ikey0_);
190189
} else {
191190
++len_;

query_masstree.cc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "masstree_tcursor.hh"
2020
#include "masstree_get.hh"
2121
#include "masstree_insert.hh"
22+
#include "masstree_iterator.hh"
2223
#include "masstree_split.hh"
2324
#include "masstree_remove.hh"
2425
#include "masstree_scan.hh"
@@ -413,6 +414,45 @@ void query_table<P>::test(threadinfo& ti) {
413414
// XXX destroy tree
414415
}
415416

417+
template <typename P>
418+
void query_table<P>::iterator_test(threadinfo& ti) {
419+
typedef typename basic_table<P>::iterator iterator;
420+
421+
query_table<P> t;
422+
t.initialize(ti);
423+
query<row_type> q;
424+
425+
const char * const values[] = {
426+
"", "0", "1", "10", "100000000", // 0-4
427+
"1000000001", "1000000002", "2", "20", "200000000", // 5-9
428+
"aaaaaaaaaaaaaaaaaaaaaaaaaa", // 10
429+
"aaaaaaaaaaaaaaabbbb", "aaaaaaaaaaaaaaabbbc", "aaaaaaaaaxaaaaabbbc", "b", "c", "d", "e", "f", "g", "h", "i", "j",
430+
"kkkkkkkk\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "a",
431+
"kkkkkkkk\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "b",
432+
"xxxxxxxxy"
433+
};
434+
const char *values_copy[arraysize(values)];
435+
memcpy(values_copy, values, sizeof(values));
436+
437+
for (int i = arraysize(values); i > 0; --i) {
438+
int x = rand() % i;
439+
q.run_replace(t.table(), Str(values_copy[x]), Str(values_copy[x]), ti);
440+
values_copy[x] = values_copy[i - 1];
441+
}
442+
443+
const char * const * pos = values;
444+
iterator itend = t.table_.end(ti);
445+
for (iterator it = t.table_.begin(ti); it != itend; it++) {
446+
Str key = it->first;
447+
if ((int) strlen(*pos) != key.len || memcmp(*pos, key.s, key.len) != 0) {
448+
fprintf(stderr, "scan encountered \"%.*s\", expected \"%s\"\n", key.len, key.s, *pos);
449+
assert((int) strlen(*pos) == key.len && memcmp(*pos, key.s, key.len) == 0);
450+
}
451+
fprintf(stderr, "scan %.*s\n", key.len, key.s);
452+
pos++;
453+
}
454+
}
455+
416456
template <typename P>
417457
void query_table<P>::print(FILE *f, int indent) const {
418458
table_.print(f, indent);

query_masstree.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class query_table {
6161
void print(FILE* f, int indent) const;
6262

6363
static void test(threadinfo& ti);
64+
static void iterator_test(threadinfo& ti);
6465

6566
static const char* name() {
6667
return "mb";

scantest.cc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,21 @@ kvtimestamp_t initial_timestamp;
1010
int
1111
main(int argc, char *argv[])
1212
{
13-
(void) argc;
14-
(void) argv;
13+
if (argc != 2) {
14+
fprintf(stderr, "usage: %s <callback|iterator>\n", argv[0]);
15+
return 1;
16+
}
1517

1618
threadinfo* ti = threadinfo::make(threadinfo::TI_MAIN, -1);
17-
default_table::test(*ti);
19+
20+
if (strcmp(argv[1], "callback") == 0)
21+
default_table::test(*ti);
22+
else if (strcmp(argv[1], "iterator") == 0)
23+
default_table::iterator_test(*ti);
24+
else {
25+
fprintf(stderr, "fatal: unknown test\n");
26+
return 1;
27+
}
28+
29+
return 0;
1830
}

0 commit comments

Comments
 (0)