Skip to content

Commit 35f8d0e

Browse files
committed
Naive iterator
1 parent 328a227 commit 35f8d0e

File tree

10 files changed

+381
-5
lines changed

10 files changed

+381
-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)

kvrow.hh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class query {
6666
void run_scan(T& table, Json& request, threadinfo& ti);
6767
template <typename T>
6868
void run_rscan(T& table, Json& request, threadinfo& ti);
69+
template <typename T>
70+
void run_iscan(T& table, Json& request, threadinfo& ti);
6971

7072
const loginfo::query_times& query_times() const {
7173
return qtimes_;
@@ -318,4 +320,36 @@ void query<R>::run_rscan(T& table, Json& request, threadinfo& ti) {
318320
table.rscan(scanf.firstkey(), true, scanf, ti);
319321
}
320322

323+
template <typename R> template <typename T>
324+
void query<R>::run_iscan(T& table, Json& request, threadinfo& ti) {
325+
assert(request[3].as_i() > 0);
326+
f_.clear();
327+
for (int i = 4; i != request.size(); ++i)
328+
f_.push_back(request[i].as_i());
329+
int nleft = request[3].as_i();
330+
lcdf::String firstkey;
331+
std::swap(request[2].value().as_s(), firstkey);
332+
request.resize(2);
333+
scankeypos_ = 0;
334+
typename T::iterator it = table.iterate_from(firstkey, ti);
335+
for (; nleft != 0 && it != table.end(ti); nleft--) {
336+
Str key = it->first;
337+
R* value = it->second;
338+
if (row_is_marker(value))
339+
break;
340+
// NB the `key` is not stable! We must save space for it.
341+
while (scankeypos_ + key.length() > scankey_.length()) {
342+
scankey_ = lcdf::String::make_uninitialized(scankey_.length() ? scankey_.length() * 2 : 1024);
343+
scankeypos_ = 0;
344+
}
345+
memcpy(const_cast<char*>(scankey_.data() + scankeypos_),
346+
key.data(), key.length());
347+
request.push_back(scankey_.substr(scankeypos_, key.length()));
348+
scankeypos_ += key.length();
349+
request.push_back(lcdf::Json());
350+
emit_fields1(value, request.back(), ti);
351+
it++;
352+
}
353+
}
354+
321355
#endif

kvtest.hh

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,83 @@ void kvtest_rscan1(C &client, double writer_quiet)
14861486
client.report(result);
14871487
}
14881488

1489+
template <typename C>
1490+
void kvtest_iscan1(C &client, double writer_quiet)
1491+
{
1492+
int n, wq65536 = int(writer_quiet * 65536);
1493+
if (client.limit() == ~(uint64_t) 0)
1494+
n = 10000;
1495+
else
1496+
n = std::min(client.limit(), (uint64_t) 97655);
1497+
Json result;
1498+
1499+
if (client.id() % 24 == 0) {
1500+
for (int i = 0; i < n; ++i)
1501+
client.put_key8(i * 1024, i);
1502+
client.wait_all();
1503+
1504+
int pos = 0, mypos = 0, scansteps = 0;
1505+
quick_istr key;
1506+
std::vector<Str> keys, values;
1507+
Json errj;
1508+
while (!client.timeout(0) && errj.size() < 1000) {
1509+
key.set(pos, 8);
1510+
client.iscan_sync(key.string(), 100, keys, values);
1511+
if (keys.size() == 0) {
1512+
if (mypos < n * 1024)
1513+
errj.push_back("missing " + String(mypos) + " through " + String((n - 1) * 1024));
1514+
pos = mypos = 0;
1515+
} else {
1516+
for (size_t i = 0; i < keys.size(); ++i) {
1517+
int val = keys[i].to_i();
1518+
if (val < 0) {
1519+
errj.push_back("unexpected key " + String(keys[i].s, keys[i].len));
1520+
continue;
1521+
}
1522+
if (val < pos)
1523+
errj.push_back("got " + String(keys[i].s, keys[i].len) + ", expected " + String(pos) + " or later");
1524+
pos = val + 1;
1525+
while (val > mypos) {
1526+
errj.push_back("got " + String(keys[i].s, keys[i].len) + ", missing " + String(mypos) + " @" + String(scansteps) + "+" + String(i));
1527+
mypos += 1024;
1528+
}
1529+
if (val == mypos) {
1530+
mypos = val + 1024;
1531+
++scansteps;
1532+
}
1533+
}
1534+
}
1535+
client.rcu_quiesce();
1536+
}
1537+
if (errj.size() >= 1000)
1538+
errj.push_back("too many errors, giving up");
1539+
result.set("ok", errj.empty()).set("scansteps", scansteps);
1540+
if (errj)
1541+
result.set("errors", errj);
1542+
1543+
} else {
1544+
int delta = 1 + (client.id() % 30) * 32, rounds = 0;
1545+
while (!client.timeout(0)) {
1546+
int first = (client.rand.next() % n) * 1024 + delta;
1547+
int rand = client.rand.next() % 65536;
1548+
if (rand < wq65536) {
1549+
for (int d = 0; d < 31; ++d)
1550+
relax_fence();
1551+
} else if (rounds > 100 && (rand % 2) == 1) {
1552+
for (int d = 0; d < 31; ++d)
1553+
client.remove_key8(d + first);
1554+
} else {
1555+
for (int d = 0; d < 31; ++d)
1556+
client.put_key8(d + first, d + first);
1557+
}
1558+
++rounds;
1559+
client.rcu_quiesce();
1560+
}
1561+
}
1562+
1563+
client.report(result);
1564+
}
1565+
14891566
// test concurrent splits with removes in lower layers
14901567
template <typename C>
14911568
void kvtest_splitremove1(C &client)

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: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
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*() { assert(!end_); return pair_; };
36+
itvalue_type* operator->() { assert(!end_); return &pair_; };
37+
bool operator==(const iterator& rhs) { return (end_ == rhs.end_) && (end_ || ka_.compare(rhs.ka_) == 0); };
38+
bool operator!=(const iterator& rhs) { return !(*this == rhs); };
39+
iterator operator++() { advance(); return *this; };
40+
iterator operator++(int) { iterator it = *this; advance(); return it; };
41+
42+
private:
43+
basic_table<P>* table_;
44+
threadinfo* ti_;
45+
key_type ka_;
46+
value_type value_;
47+
itvalue_type pair_;
48+
bool end_;
49+
union {
50+
ikey_type x[(MASSTREE_MAXKEYLEN + sizeof(ikey_type) - 1)/sizeof(ikey_type)];
51+
char s[MASSTREE_MAXKEYLEN];
52+
} keybuf_;
53+
54+
void advance(bool emit_equal = false);
55+
56+
57+
// Debugging support.
58+
int id_;
59+
static int count_;
60+
61+
void dprintf(const char *format, ...) {
62+
va_list args;
63+
va_start(args, format);
64+
fprintf(stderr, "it%d: ", id_);
65+
vfprintf(stderr, format, args);
66+
va_end(args);
67+
}
68+
};
69+
70+
template <typename P> int basic_table<P>::iterator::count_ = 0;
71+
72+
template <typename P>
73+
basic_table<P>::iterator::iterator(basic_table<P>* table, threadinfo* ti, Str firstkey)
74+
: table_(table), ti_(ti), end_(false), id_(count_++) {
75+
masstree_precondition(firstkey.len <= (int) sizeof(keybuf_));
76+
memcpy(keybuf_.s, firstkey.s, firstkey.len);
77+
ka_ = key_type(keybuf_.s, firstkey.len);
78+
79+
advance(true);
80+
};
81+
82+
template <typename P>
83+
typename basic_table<P>::iterator
84+
basic_table<P>::iterator::make_end(basic_table<P>* table, threadinfo *ti) {
85+
iterator it = iterator(table, ti);
86+
it.end_ = true;
87+
return it;
88+
}
89+
90+
template <typename P>
91+
void
92+
basic_table<P>::iterator::advance(bool emit_equal) {
93+
int ki;
94+
bool try_next_index = true;
95+
leaf_type* n;
96+
nodeversion_type v;
97+
node_type* root;
98+
permuter_type perm;
99+
Str suffix;
100+
char suffixbuf[MASSTREE_MAXKEYLEN];
101+
102+
retry_root:
103+
ka_.unshift_all();
104+
root = table_->root();
105+
n = root->reach_leaf(ka_, v, *ti_);
106+
perm = n->permutation();
107+
ki = bound_type::lower(ka_, *n).i;
108+
109+
retry:
110+
if (v.deleted())
111+
goto retry_root;
112+
113+
int kp = (unsigned(ki) < unsigned(perm.size())) ? perm[ki] : -1;
114+
if (kp < 0) {
115+
n = n->safe_next();
116+
if (!n) {
117+
if (root == table_->root()) {
118+
end_ = true;
119+
return;
120+
}
121+
122+
ka_.unshift();
123+
while (ka_.increment() && ka_.is_shifted())
124+
ka_.unshift();
125+
ka_.assign_store_ikey(ka_.ikey());
126+
ka_.assign_store_length(ka_.ikey_size);
127+
goto retry_root;
128+
}
129+
perm = n->permutation();
130+
v = n->stable();
131+
ki = bound_type::lower(ka_, *n).i;
132+
goto retry;
133+
}
134+
135+
int keylenx = n->keylenx_[kp];
136+
ikey_type ikey = n->ikey0_[kp];
137+
leafvalue_type entry = n->lv_[kp];
138+
if (n->keylenx_has_ksuf(keylenx)) {
139+
suffix = n->ksuf(kp);
140+
memcpy(suffixbuf, suffix.s, suffix.len);
141+
suffix.s = suffixbuf;
142+
}
143+
144+
if (n->has_changed(v))
145+
goto retry_root;
146+
147+
ka_.assign_store_ikey(ikey);
148+
if (n->keylenx_is_layer(keylenx)) {
149+
ka_.shift();
150+
root = entry.layer();
151+
n = root->reach_leaf(ka_, v, *ti_);
152+
perm = n->permutation();
153+
ki = bound_type::lower(ka_, *n).i;
154+
goto retry;
155+
}
156+
157+
// XXX This condition is suspect.
158+
if (!emit_equal && try_next_index &&
159+
(!n->keylenx_has_ksuf(keylenx) || suffix.compare(ka_.suffix()) == 0)) {
160+
try_next_index = false;
161+
ki++;
162+
goto retry;
163+
}
164+
165+
int keylen = keylenx;
166+
if (n->keylenx_has_ksuf(keylenx)) {
167+
keylen = ka_.assign_store_suffix(suffix);
168+
}
169+
ka_.assign_store_length(keylen);
170+
ka_.unshift_all();
171+
pair_ = itvalue_type(ka_, entry.value());
172+
}
173+
174+
template <typename P>
175+
typename basic_table<P>::iterator
176+
basic_table<P>::begin(threadinfo& ti) {
177+
return iterator(this, &ti);
178+
}
179+
180+
template <typename P>
181+
typename basic_table<P>::iterator
182+
basic_table<P>::end(threadinfo& ti) {
183+
return iterator::make_end(this, &ti);
184+
}
185+
186+
template <typename P>
187+
typename basic_table<P>::iterator
188+
basic_table<P>::iterate_from(Str firstkey, threadinfo& ti) {
189+
return iterator(this, &ti, firstkey);
190+
}
191+
}
192+
#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_;

0 commit comments

Comments
 (0)