Skip to content

Commit

Permalink
Naive iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
benesch committed Nov 23, 2015
1 parent 328a227 commit 35f8d0e
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 5 deletions.
2 changes: 1 addition & 1 deletion GNUmakefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
34 changes: 34 additions & 0 deletions kvrow.hh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class query {
void run_scan(T& table, Json& request, threadinfo& ti);
template <typename T>
void run_rscan(T& table, Json& request, threadinfo& ti);
template <typename T>
void run_iscan(T& table, Json& request, threadinfo& ti);

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

template <typename R> template <typename T>
void query<R>::run_iscan(T& table, Json& request, threadinfo& ti) {
assert(request[3].as_i() > 0);
f_.clear();
for (int i = 4; i != request.size(); ++i)
f_.push_back(request[i].as_i());
int nleft = request[3].as_i();
lcdf::String firstkey;
std::swap(request[2].value().as_s(), firstkey);
request.resize(2);
scankeypos_ = 0;
typename T::iterator it = table.iterate_from(firstkey, ti);
for (; nleft != 0 && it != table.end(ti); nleft--) {
Str key = it->first;
R* value = it->second;
if (row_is_marker(value))
break;
// NB the `key` is not stable! We must save space for it.
while (scankeypos_ + key.length() > scankey_.length()) {
scankey_ = lcdf::String::make_uninitialized(scankey_.length() ? scankey_.length() * 2 : 1024);
scankeypos_ = 0;
}
memcpy(const_cast<char*>(scankey_.data() + scankeypos_),
key.data(), key.length());
request.push_back(scankey_.substr(scankeypos_, key.length()));
scankeypos_ += key.length();
request.push_back(lcdf::Json());
emit_fields1(value, request.back(), ti);
it++;
}
}

#endif
77 changes: 77 additions & 0 deletions kvtest.hh
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,83 @@ void kvtest_rscan1(C &client, double writer_quiet)
client.report(result);
}

template <typename C>
void kvtest_iscan1(C &client, double writer_quiet)
{
int n, wq65536 = int(writer_quiet * 65536);
if (client.limit() == ~(uint64_t) 0)
n = 10000;
else
n = std::min(client.limit(), (uint64_t) 97655);
Json result;

if (client.id() % 24 == 0) {
for (int i = 0; i < n; ++i)
client.put_key8(i * 1024, i);
client.wait_all();

int pos = 0, mypos = 0, scansteps = 0;
quick_istr key;
std::vector<Str> keys, values;
Json errj;
while (!client.timeout(0) && errj.size() < 1000) {
key.set(pos, 8);
client.iscan_sync(key.string(), 100, keys, values);
if (keys.size() == 0) {
if (mypos < n * 1024)
errj.push_back("missing " + String(mypos) + " through " + String((n - 1) * 1024));
pos = mypos = 0;
} else {
for (size_t i = 0; i < keys.size(); ++i) {
int val = keys[i].to_i();
if (val < 0) {
errj.push_back("unexpected key " + String(keys[i].s, keys[i].len));
continue;
}
if (val < pos)
errj.push_back("got " + String(keys[i].s, keys[i].len) + ", expected " + String(pos) + " or later");
pos = val + 1;
while (val > mypos) {
errj.push_back("got " + String(keys[i].s, keys[i].len) + ", missing " + String(mypos) + " @" + String(scansteps) + "+" + String(i));
mypos += 1024;
}
if (val == mypos) {
mypos = val + 1024;
++scansteps;
}
}
}
client.rcu_quiesce();
}
if (errj.size() >= 1000)
errj.push_back("too many errors, giving up");
result.set("ok", errj.empty()).set("scansteps", scansteps);
if (errj)
result.set("errors", errj);

} else {
int delta = 1 + (client.id() % 30) * 32, rounds = 0;
while (!client.timeout(0)) {
int first = (client.rand.next() % n) * 1024 + delta;
int rand = client.rand.next() % 65536;
if (rand < wq65536) {
for (int d = 0; d < 31; ++d)
relax_fence();
} else if (rounds > 100 && (rand % 2) == 1) {
for (int d = 0; d < 31; ++d)
client.remove_key8(d + first);
} else {
for (int d = 0; d < 31; ++d)
client.put_key8(d + first, d + first);
}
++rounds;
client.rcu_quiesce();
}
}

client.report(result);
}

// test concurrent splits with removes in lower layers
template <typename C>
void kvtest_splitremove1(C &client)
Expand Down
6 changes: 6 additions & 0 deletions masstree.hh
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class basic_table {
typedef typename P::threadinfo_type threadinfo;
typedef unlocked_tcursor<P> unlocked_cursor_type;
typedef tcursor<P> cursor_type;
typedef std::pair<Str, value_type> itvalue_type;

inline basic_table();

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

class iterator;
iterator begin(threadinfo& ti);
iterator iterate_from(Str firstkey, threadinfo& ti);
iterator end(threadinfo& ti);

template <typename F>
inline int modify(Str key, F& f, threadinfo& ti);
template <typename F>
Expand Down
192 changes: 192 additions & 0 deletions masstree_iterator.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/* Masstree
* Eddie Kohler, Yandong Mao, Robert Morris
* Copyright (c) 2012-2014 President and Fellows of Harvard College
* Copyright (c) 2012-2014 Massachusetts Institute of Technology
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Masstree LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Masstree LICENSE file; the license in that file
* is legally binding.
*/
#ifndef MASSTREE_ITERATOR_HH
#define MASSTREE_ITERATOR_HH
#include "masstree_scan.hh"

namespace Masstree {
template <typename P>
class basic_table<P>::iterator
: std::iterator<std::forward_iterator_tag, itvalue_type> {
typedef typename P::ikey_type ikey_type;
typedef typename node_type::key_type key_type;
typedef typename node_type::leaf_type::leafvalue_type leafvalue_type;
typedef typename node_type::nodeversion_type nodeversion_type;
typedef typename leaf_type::permuter_type permuter_type;
typedef typename leaf_type::bound_type bound_type;

public:
iterator(basic_table<P>* table, threadinfo* ti, Str firstkey = "");
static iterator make_end(basic_table<P>* table, threadinfo *ti);

itvalue_type& operator*() { assert(!end_); return pair_; };
itvalue_type* operator->() { assert(!end_); return &pair_; };
bool operator==(const iterator& rhs) { return (end_ == rhs.end_) && (end_ || ka_.compare(rhs.ka_) == 0); };
bool operator!=(const iterator& rhs) { return !(*this == rhs); };
iterator operator++() { advance(); return *this; };
iterator operator++(int) { iterator it = *this; advance(); return it; };

private:
basic_table<P>* table_;
threadinfo* ti_;
key_type ka_;
value_type value_;
itvalue_type pair_;
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 <typename P> int basic_table<P>::iterator::count_ = 0;

template <typename P>
basic_table<P>::iterator::iterator(basic_table<P>* table, threadinfo* ti, Str firstkey)
: table_(table), ti_(ti), 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 <typename P>
typename basic_table<P>::iterator
basic_table<P>::iterator::make_end(basic_table<P>* table, threadinfo *ti) {
iterator it = iterator(table, ti);
it.end_ = true;
return it;
}

template <typename P>
void
basic_table<P>::iterator::advance(bool emit_equal) {
int ki;
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 (root == table_->root()) {
end_ = true;
return;
}

ka_.unshift();
while (ka_.increment() && ka_.is_shifted())
ka_.unshift();
ka_.assign_store_ikey(ka_.ikey());
ka_.assign_store_length(ka_.ikey_size);
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 &&
(!n->keylenx_has_ksuf(keylenx) || suffix.compare(ka_.suffix()) == 0)) {
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 <typename P>
typename basic_table<P>::iterator
basic_table<P>::begin(threadinfo& ti) {
return iterator(this, &ti);
}

template <typename P>
typename basic_table<P>::iterator
basic_table<P>::end(threadinfo& ti) {
return iterator::make_end(this, &ti);
}

template <typename P>
typename basic_table<P>::iterator
basic_table<P>::iterate_from(Str firstkey, threadinfo& ti) {
return iterator(this, &ti, firstkey);
}
}
#endif
1 change: 0 additions & 1 deletion masstree_key.hh
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ class key {
// Return true iff wrapped.
if (has_suffix()) {
++ikey0_;
len_ = 1;
return unlikely(!ikey0_);
} else {
++len_;
Expand Down
Loading

0 comments on commit 35f8d0e

Please sign in to comment.