Skip to content

Commit 6d0fe44

Browse files
committed
Naive iterator
1 parent 328a227 commit 6d0fe44

File tree

6 files changed

+303
-4
lines changed

6 files changed

+303
-4
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: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
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 allow_next = true);
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();
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 allow_next) {
95+
key_indexed_position kx;
96+
int keylenx;
97+
char suffixbuf[MASSTREE_MAXKEYLEN];
98+
Str suffix;
99+
leafvalue_type entry;
100+
leaf_type* n;
101+
nodeversion_type v;
102+
permuter_type perm;
103+
bool found = false;
104+
node_type* root;
105+
106+
retry:
107+
keylenx = 0;
108+
root = table_->root();
109+
ka_.unshift_all();
110+
111+
// Find initial.
112+
// XXX The control flow of this loop is incomprehensible.
113+
while (!found) {
114+
n = root->reach_leaf(ka_, v, *ti_);
115+
116+
if (v.deleted())
117+
goto retry;
118+
n->prefetch();
119+
perm = n->permutation();
120+
121+
kx = bound_type::lower(ka_, *n);
122+
if (kx.p >= 0) {
123+
keylenx = n->keylenx_[kx.p];
124+
fence();
125+
entry = n->lv_[kx.p];
126+
entry.prefetch(keylenx);
127+
if (n->keylenx_has_ksuf(keylenx)) {
128+
suffix = n->ksuf(kx.p);
129+
memcpy(suffixbuf, suffix.s, suffix.len);
130+
suffix.s = suffixbuf;
131+
}
132+
}
133+
if (n->has_changed(v)) {
134+
ti_->mark(tc_leaf_retry);
135+
n = n->advance_to_key(ka_, v, *ti_);
136+
goto retry;
137+
}
138+
139+
if (kx.p >= 0) {
140+
if (n->keylenx_is_layer(keylenx)) {
141+
root = entry.layer();
142+
ka_.shift();
143+
continue;
144+
} else if (n->keylenx_has_ksuf(keylenx)) {
145+
int ksuf_compare = suffix.compare(ka_.suffix());
146+
if (ksuf_compare > 0 || (ksuf_compare == 0 && emit_equal_)) {
147+
int keylen = ka_.assign_store_suffix(suffix);
148+
ka_.assign_store_length(keylen);
149+
found = true;
150+
}
151+
}
152+
found = emit_equal_;
153+
}
154+
break;
155+
}
156+
157+
// Find next.
158+
int kp;
159+
int ki = kx.i + 1;
160+
while (!found) {
161+
if (v.deleted())
162+
goto retry;
163+
164+
kp = unsigned(ki) < unsigned(perm.size()) ? perm[ki] : -1;
165+
if (kp >= 0) {
166+
ikey_type ikey = n->ikey0_[kp];
167+
int keylenx = n->keylenx_[kp];
168+
int keylen = keylenx;
169+
fence();
170+
entry = n->lv_[kp];
171+
entry.prefetch(keylenx);
172+
if (n->keylenx_has_ksuf(keylenx))
173+
keylen = ka_.assign_store_suffix(n->ksuf(kp));
174+
175+
if (n->has_changed(v))
176+
goto retry;
177+
else if (ka_.compare(ikey, keylenx) >= 0) {
178+
ki++;
179+
continue;
180+
}
181+
182+
ka_.assign_store_ikey(ikey);
183+
if (n->keylenx_is_layer(keylenx)) {
184+
root = entry.layer();
185+
n = root->reach_leaf(ka_, v, *ti_);
186+
ka_.shift();
187+
goto changed;
188+
} else {
189+
ka_.assign_store_length(keylen);
190+
found = true;
191+
break;
192+
}
193+
}
194+
195+
if (!n->has_changed(v)) {
196+
n = n->safe_next();
197+
if (!n) {
198+
if (allow_next) {
199+
ka_.unshift();
200+
ka_.assign_store_length(ka_.ikey_size);
201+
emit_equal_ = true;
202+
advance(false);
203+
return;
204+
} else {
205+
end_ = true;
206+
return;
207+
}
208+
}
209+
}
210+
211+
changed:
212+
n->prefetch();
213+
v = n->stable();
214+
perm = n->permutation();
215+
ki = bound_type::lower(ka_, *n).i;
216+
}
217+
218+
pair_ = itvalue_type(ka_, entry.value());
219+
emit_equal_ = false;
220+
}
221+
222+
template <typename P>
223+
typename basic_table<P>::iterator
224+
basic_table<P>::begin(threadinfo& ti) {
225+
return iterator(this, &ti);
226+
}
227+
228+
template <typename P>
229+
typename basic_table<P>::iterator
230+
basic_table<P>::end(threadinfo& ti) {
231+
return iterator::make_end(this, &ti);
232+
}
233+
234+
template <typename P>
235+
typename basic_table<P>::iterator
236+
basic_table<P>::iterate_from(Str firstkey, threadinfo& ti) {
237+
return iterator(this, &ti, firstkey);
238+
}
239+
}
240+
#endif

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)