rocksdb/thrift/openhandles.h
Dhruba Borthakur 80c663882a Create leveldb server via Thrift.
Summary:
First draft.
Unit tests pass.

Test Plan: unit tests attached

Reviewers: heyongqiang

Reviewed By: heyongqiang

Differential Revision: https://reviews.facebook.net/D3969
2012-07-07 09:42:39 -07:00

228 lines
6.1 KiB
C++

/**
* Thrift server for leveldb
* @author Dhruba Borthakur (dhruba@gmail.com)
* Copyright 2012 Facebook
*/
#include <unordered_map>
#include <atomic>
#include "DB.h"
#include <protocol/TBinaryProtocol.h>
#include <server/TSimpleServer.h>
#include <server/TConnectionContext.h>
#include <transport/TServerSocket.h>
#include <transport/TBufferTransports.h>
#include "leveldb/db.h"
#include "util/random.h"
using boost::shared_ptr;
using std::unordered_map;
using namespace ::Tleveldb;
// List of snapshots. Each entry has a unique snapshot id.
struct snapshotEntry {
int64_t snapshotid;
const leveldb::Snapshot* lsnap;
snapshotEntry() : snapshotid(-1), lsnap(NULL) {
}
private:
snapshotEntry(const snapshotEntry&);
snapshotEntry& operator= (const snapshotEntry&);
};
// List of iterators. Each entry has a unique iterator id.
struct iteratorEntry {
int64_t iteratorid;
leveldb::Iterator* liter;
iteratorEntry() : iteratorid(-1), liter(NULL) {
}
private:
iteratorEntry(const iteratorEntry&);
iteratorEntry& operator= (const iteratorEntry&);
};
//
// This is the information stored for each open database. Each open instance
// of the database has a list of snapshots and a list of iterators that are
// currenty open
//
struct onehandle {
Text name;
leveldb::DB* onedb; // locate the localleveldb instance
int refcount; // currently not used
int64_t uniqueid; // unique identifier
std::atomic<uint64_t> currentSnapshotId; // valid snapshotids > 0
std::atomic<uint64_t> currentIteratorId; // valid iterators > 0
unordered_map<uint64_t, struct snapshotEntry*> snaplist;
// list of snapshots for this database
unordered_map<uint64_t, struct iteratorEntry*> iterlist;
// list of iterators for this database
onehandle() : currentSnapshotId(1), currentIteratorId(1) {
}
// stores a new leveldb snapshot and returns an unique id
int64_t addSnapshot(const leveldb::Snapshot* l) {
struct snapshotEntry* news = new snapshotEntry;
news->snapshotid = currentSnapshotId++;
news->lsnap = l;
snaplist[news->snapshotid] = news;
return news->snapshotid;
}
// lookup a snapshot from its ids
const leveldb::Snapshot* lookupSnapshot(int64_t id) {
auto p = snaplist.find(id);
if (p == snaplist.end()) {
fprintf(stderr, "get:No snaphot with id %d\n", id);
return NULL;
}
return p->second->lsnap;
}
// remove a snapshot from this database
const leveldb::Snapshot* removeSnapshot(int64_t id) {
const leveldb::Snapshot* l = lookupSnapshot(id);
if (l != NULL) {
int numRemoved = snaplist.erase(id);
assert(numRemoved == 1);
return l;
}
return NULL; // not found
}
// stores a new leveldb iterator and returns an unique id
int64_t addIterator(leveldb::Iterator* l) {
struct iteratorEntry* news = new iteratorEntry;
news->iteratorid = currentIteratorId++;
news->liter = l;
iterlist[news->iteratorid] = news;
return news->iteratorid;
}
// lookup a iterator from its ids
leveldb::Iterator* lookupIterator(int64_t id) {
auto p = iterlist.find(id);
if (p == iterlist.end()) {
fprintf(stderr, "lookupIterator:No iterator with id %d\n", id);
return NULL;
}
return p->second->liter;
}
// remove a iterator from this database
leveldb::Iterator* removeIterator(int64_t id) {
leveldb::Iterator* i = lookupIterator(id);
if (i != NULL) {
int numRemoved = iterlist.erase(id);
assert(numRemoved == 1);
return i;
}
return NULL; // not found
}
private:
onehandle(const onehandle&);
onehandle& operator= (const onehandle&);
};
class OpenHandles {
public:
OpenHandles() : dbnum_(1) {
}
// Inserts a new database into the list.
// If the database is already open, increase refcount.
// If the database is not already open, open and insert into list.
int64_t add(leveldb::Options& options, Text dbname) {
struct onehandle* found = head_[dbname];
if (found == NULL) {
found = new onehandle;
found->name = dbname;
found->uniqueid = dbnum_++;
fprintf(stderr, "openhandle.add: Opening leveldb directory %s\n",
dbname.c_str());
leveldb::Status status = leveldb::DB::Open(options, dbname, &found->onedb);
if (!status.ok()) {
LeveldbException e;
e.errorCode = Code::kIOError;
e.message = "Unable to open database";
fprintf(stderr, "openhandle.add: Unable to open database %s\n",
dbname.c_str());
throw e;
}
assert(found->onedb != NULL);
head_[dbname] = found;
}
found->refcount++;
return found->uniqueid;
}
leveldb::DB* get(Text dbname, int64_t uniqueid, struct onehandle** f) {
auto p = head_.find(dbname);
if (p == head_.end()) {
fprintf(stderr, "get:No db with name\n");
return NULL;
}
struct onehandle* found = p->second;
if (found->uniqueid != uniqueid) {
fprintf(stderr, "get:Uniqueid does not match\n.");
return NULL;
}
if (found->refcount <= 0) {
fprintf(stderr, "get:bad refcount\n.");
return NULL;
}
// returns the onehandle if asked to do so
if (f != NULL) {
*f = found;
}
return found->onedb;
}
bool remove(Text dbname, int64_t uniqueid) {
auto p = head_.find(dbname);
if (p == head_.end()) {
fprintf(stderr, "get:No db with name\n");
return false;
}
struct onehandle* found = p->second;
if (found->uniqueid != uniqueid) {
fprintf(stderr, "remove:Uniqueid does not match\n.");
return false;
}
if (found->refcount == 1) {
delete found->onedb; // close database
int numRemoved = head_.erase(dbname);
assert (numRemoved == 1);
} else {
found->refcount--; // decrement refcount
}
return true;
}
private:
unordered_map<std::string, struct onehandle*> head_; // all open databases
std::atomic<uint64_t> dbnum_;
struct onehandle* lookup(Text dbname) {
auto p = head_.find(dbname);
if (p == head_.end()) {
fprintf(stderr, "get:No db with name\n");
return NULL;
}
return p->second;
}
};