From 7c8e064216cc672557cbf3892ff090490505e408 Mon Sep 17 00:00:00 2001 From: Yves Fischer Date: Thu, 18 Apr 2013 15:42:54 +0200 Subject: leveldb: size restricted range query --- datastore-leveldb/src/web.cpp | 128 +++++++++++++++++++++++++++++++----------- 1 file changed, 95 insertions(+), 33 deletions(-) (limited to 'datastore-leveldb/src/web.cpp') diff --git a/datastore-leveldb/src/web.cpp b/datastore-leveldb/src/web.cpp index 4898451..2adf8eb 100644 --- a/datastore-leveldb/src/web.cpp +++ b/datastore-leveldb/src/web.cpp @@ -1,8 +1,12 @@ #include "web.h" #include "db.h" +#include +#include #include #include +static const leveldb::Comparator *cmp = leveldb::BytewiseComparator(); + static inline std::string make_key(uint64_t timestamp) { std::stringstream key; key << "ts-"; @@ -10,9 +14,17 @@ static inline std::string make_key(uint64_t timestamp) { return key.str(); } -void web_handle_api_value(const boost::cmatch &match, struct mg_connection *conn) { -// const struct mg_request_info *request_info = mg_get_request_info(conn); +static inline bool parse_key(leveldb::Slice &&key, uint64_t *value) { + if (key.size() != 20+3) + return false; + *value = std::stoul(key.data()+3); + return true; +} + +const boost::regex web_handle_api_value_R( + "/api/value/([a-zA-Z0-9]+)/([0-9]+)"); +void web_handle_api_value(const boost::cmatch &match, struct mg_connection *conn) { std::string sensor(match[1].str()); uint64_t timestamp = std::stoul(match[2].str()); char buf[1024]; @@ -26,14 +38,39 @@ void web_handle_api_value(const boost::cmatch &match, struct mg_connection *conn return; } - std::cout << "sensor=" << sensor << " key=" << make_key(timestamp) << std::endl; db->Put(leveldb::WriteOptions(), make_key(timestamp), value); mg_printf(conn, "HTTP/1.1 200 Value received\r\n\r\n"); } -void web_handle_api_range(const boost::cmatch &match, struct mg_connection *conn) { - static const leveldb::Comparator *cmp = leveldb::BytewiseComparator(); +static inline void print_json_tuple(struct mg_connection *conn, + std::ostringstream &outbuf, + leveldb::Slice &&key, + leveldb::Slice &&value) { + + size_t key_size = key.size(); + if (key_size != 20+3) { + std::cerr << "invalid key" << std::endl; + return; + } + + unsigned int offset = 3; // "ts-" + // skip zeros in timestamp + while (offset < key_size-1 and *(key.data()+offset) == '0') + offset++; + + outbuf << '['; + outbuf.write(key.data()+offset, key_size-offset); + outbuf << ','; + outbuf.write(value.data(), value.size()); + outbuf << ']'; + mg_write(conn, outbuf.str().c_str(), outbuf.tellp()); +} + + +const boost::regex web_handle_api_range_R( + "/api/range/([a-zA-Z0-9]+)/([0-9]+)/([0-9]+)"); +void web_handle_api_range(const boost::cmatch &match, struct mg_connection *conn) { std::string sensor(match[1].str()); uint64_t start = std::stoul(match[2].str()); uint64_t end = std::stoul(match[3].str()); @@ -42,17 +79,16 @@ void web_handle_api_range(const boost::cmatch &match, struct mg_connection *conn leveldb::DB *db = getDB(sensor); if (db == nullptr) { - mg_printf(conn, "HTTP/1.1 500 Internal Error\r\n\r\n"); + mg_printf(conn, "HTTP/1.1 500 Internal Error\r\n" + "\r\n"); return; } mg_printf(conn, - "HTTP/1.1 200 Value received\r\n" + "HTTP/1.1 200 OK\r\n" "Content-Type: application/json; encoding=UTF-8\r\n" "\r\n"); - std::cout << "sensor=" << sensor << " start=" << start << " end=" << end << std::endl; - std::ostringstream out; out << "{'sensor':'" << sensor << "', 'error':null, 'data':["; mg_write(conn, out.str().c_str(), out.str().size()); @@ -63,33 +99,59 @@ void web_handle_api_range(const boost::cmatch &match, struct mg_connection *conn for (it->Seek(key_start); it->Valid() && cmp->Compare(it->key(), key_end) < 0; it->Next()) { - const char *key = it->key().data(); - size_t key_size = it->key().size(); - if (key_size != 20+3) { - std::cerr << "invalid key" << std::endl; - return; - } - - unsigned int offset = 3; // "ts-" - // skip zeros in timestamp - while (offset < key_size-1 and *(key+offset) == '0') - offset++; - - if (first) - first = false; - else - outbuf << ','; - - outbuf << '['; - outbuf.write(key+offset, key_size-offset); - outbuf << ','; - outbuf.write(it->value().data(), it->value().size()); - outbuf << ']'; - - mg_write(conn, outbuf.str().c_str(), outbuf.tellp()); + if (first) first = false; + else outbuf << ","; + print_json_tuple(conn, outbuf, it->key(), it->value()); outbuf.seekp(0); } mg_printf(conn, "]}\r\n"); delete it; } +const boost::regex web_handle_api_range_size_R( + "/api/range/([a-zA-Z0-9]+)/([0-9]+)/([0-9]+)/([0-9]+)"); +void web_handle_api_range_size(const boost::cmatch &match, struct mg_connection *conn) { + std::string sensor(match[1].str()); + uint64_t start = std::stoul(match[2].str()); + uint64_t end = std::stoul(match[3].str()); + uint64_t size = std::stoul(match[4].str()); + + leveldb::DB *db = getDB(sensor); + if (db == nullptr) { + mg_printf(conn, "HTTP/1.1 500 Internal Error\r\n" + "\r\n"); + return; + } + + mg_printf(conn, + "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json; encoding=UTF-8\r\n" + "\r\n"); + + uint64_t step = std::max((uint64_t)1, (end-start) / size); + + std::ostringstream out; + out << "{'sensor':'" << sensor << "', " + << "'error':null, " + << "'size':" << size << ", " + << "'step':" << step << ", " + << "'data':["; + mg_write(conn, out.str().c_str(), out.str().size()); + + bool first = true; + uint64_t actual_size = 0; + std::ostringstream outbuf; + leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); + for (uint64_t key = start; key <= end; key += step) { + it->Seek(make_key(key)); + + if (first) first = false; + else outbuf << ","; + + print_json_tuple(conn, outbuf, it->key(), it->value()); + outbuf.seekp(0); + actual_size++; + } + mg_printf(conn, "], 'actual_size':%ld}\r\n", actual_size); + delete it; +} -- cgit v1.2.1