examples folder has been removed; src/test folder has been removed; the existing tests were moved to tests folder; StacktraceException has been introduced; query_plan_templated has been moved to query folder; hazard pointers have been deleted because they are not used any more

This commit is contained in:
Marko Budiselic 2017-02-18 18:03:48 +01:00
parent 0198b37f21
commit 3642fb1312
91 changed files with 620 additions and 2117 deletions

View File

@ -86,14 +86,16 @@ set(antlr_static_lib ${CMAKE_SOURCE_DIR}/dist/libantlr4-runtime.a)
# prepare template and destination folders for query engine (tests)
# and memgraph server binary
# copy query_engine's templates file
FILE(COPY ${src_dir}/query_engine/template
DESTINATION ${CMAKE_BINARY_DIR}/tests)
FILE(COPY ${src_dir}/query_engine/template
DESTINATION ${CMAKE_BINARY_DIR}/tests/integration)
FILE(COPY ${src_dir}/query_engine/template
DESTINATION ${CMAKE_BINARY_DIR}/tests/manual)
FILE(COPY ${src_dir}/query_engine/template DESTINATION ${CMAKE_BINARY_DIR})
# copy query_engine template file
set(query_engine_template_file ${src_dir}/query/plan_template_cpp)
FILE(COPY ${query_engine_template_file}
DESTINATION ${CMAKE_BINARY_DIR}/tests/template)
FILE(COPY ${query_engine_template_file}
DESTINATION ${CMAKE_BINARY_DIR}/tests/integration/template)
FILE(COPY ${query_engine_template_file}
DESTINATION ${CMAKE_BINARY_DIR}/tests/manual/template)
FILE(COPY ${query_engine_template_file}
DESTINATION ${CMAKE_BINARY_DIR}/template)
# create destination folder for compiled queries
FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/tests/integration/compiled)
FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/tests/manual/compiled)

View File

@ -9,7 +9,7 @@
compile_path: "./compiled/"
# path to the template (cpp) for codes generation
template_cpp_path: "./template/template_code_cpp"
template_cpp_path: "./template/plan_template_cpp"
# path to the folder with snapshots
snapshots_path: "snapshots"

1
example/.gitignore vendored
View File

@ -1 +0,0 @@
*.out

View File

@ -1,67 +0,0 @@
/* Plots the distribution histogram of the fast_binomial algorithm
* (spoiler alert: it's pleasingly (1/2)^N all the way :D)
*/
#include <iostream>
#include <array>
#include <atomic>
#include <thread>
#include <iomanip>
#include <sys/ioctl.h>
#include <unistd.h>
#include "utils/random/fast_binomial.hpp"
static constexpr unsigned B = 24;
static thread_local FastBinomial<B> rnd;
static constexpr unsigned M = 4;
static constexpr size_t N = 1ULL << 34;
static constexpr size_t per_thread_iters = N / M;
std::array<std::atomic<uint64_t>, B> buckets;
void generate()
{
for(size_t i = 0; i < per_thread_iters; ++i)
buckets[rnd() - 1].fetch_add(1);
}
int main(void)
{
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
auto bar_len = w.ws_col - 20;
std::array<std::thread, M> threads;
for(auto& bucket : buckets)
bucket.store(0);
for(auto& t : threads)
t = std::thread([]() { generate(); });
for(auto& t : threads)
t.join();
auto max = std::accumulate(buckets.begin(), buckets.end(), (uint64_t)0,
[](auto& acc, auto& x) { return std::max(acc, x.load()); });
std::cout << std::fixed;
for(size_t i = 0; i < buckets.size(); ++i)
{
auto x = buckets[i].load();
auto rel = bar_len * x / max;
std::cout << std::setw(2) << i + 1 << " ";
for(size_t i = 0; i < rel; ++i)
std::cout << "=";
std::cout << " " << 100 * (double)x / N << "%" << std::endl;
}
return 0;
}

View File

@ -1,293 +0,0 @@
#include <functional>
#include <algorithm>
#include <iostream>
#include <random>
#include <vector>
#include <thread>
#include <chrono>
#include <atomic>
#include <future>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "debug/log.hpp"
#include "io/network/epoll.hpp"
#include "io/network/socket.hpp"
#include "io/network/tcp/stream.hpp"
#include "io/network/stream_reader.hpp"
#include "memory/literals.hpp"
using namespace memory::literals;
class RandomString
{
static constexpr char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
public:
template <class Rg>
std::string operator()(Rg&& gen, size_t len)
{
auto str = std::string();
str.reserve(len + 2);
str.push_back('\'');
while(str.size() < len)
str.push_back(charset[rnd(std::forward<Rg>(gen))]);
str.push_back('\'');
return str;
}
private:
std::uniform_int_distribution<> rnd {0, sizeof(charset) - 1};
};
constexpr char RandomString::charset[];
static std::mt19937 mt {std::random_device{}()};
class CypherPost
{
static std::string templ;
public:
CypherPost()
{
request.reserve(64_kB);
}
void set(const std::string& query)
{
request.clear();
request += "POST /db/data/transaction/commit HTTP/1.1\r\n" \
"Host: localhost:7474\r\n" \
"Authorization: Basic bmVvNGo6cGFzcw==\r\n" \
"Accept: application/json; charset=UTF-8\r\n" \
"Content-Type: application/json\r\n" \
"Content-Length: ";
request += std::to_string(query.size() + templ.size() + 4);
request += "\r\n\r\n";
request += templ;
request += query;
request += "\"}]}";
}
operator const std::string&() const { return request; }
private:
std::string request;
};
std::string CypherPost::templ = "{\"statements\":[{\"statement\":\"";
struct Result
{
std::chrono::high_resolution_clock::time_point start, end;
uint64_t requests;
};
class Worker : public io::StreamReader<Worker, io::tcp::Stream>
{
char buf[65535];
CypherPost post;
std::uniform_int_distribution<> random_int;
RandomString random_string;
Replacer replacer;
public:
Worker()
{
replacer.replace("#", [&]() { return std::to_string(random_int(mt)); })
.replace("^", [&]() { return random_string(mt, 15); });
}
io::tcp::Stream& on_connect(io::Socket&&)
{
// DUMMY, refactor StreamReader to be more generic
return *streams.back();
}
bool connect(const char* name, const char* port)
{
auto socket = io::Socket::connect(name, port);
if(!socket.is_open())
return false;
socket.set_non_blocking();
streams.push_back(std::make_unique<io::tcp::Stream>(std::move(socket)));
auto& stream = streams.back();
stream->event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
this->add(*stream);
return true;
}
void on_error(io::tcp::Stream& conn)
{
LOG_DEBUG("error on socket " << conn.id());
(void)conn;
LOG_DEBUG((errno == EBADF));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::abort();
}
void on_wait_timeout() {}
Buffer on_alloc(io::tcp::Stream&)
{
return Buffer { buf, sizeof buf };
}
void on_read(io::tcp::Stream& stream, Buffer& buf)
{
/* std::cout << "RESPONSE" << std::endl; */
/* std::cout << std::string(buf.ptr, buf.len) << std::endl; */
requests++;
LOG_DEBUG("on_read");
sendreq(stream.socket);
}
void on_close(io::tcp::Stream&) {}
void sendreq(io::Socket& socket)
{
/* auto query = std::string("CREATE (n:Person {id: #, name: ^}) RETURN n"); */
auto query = std::string("MATCH (n:Person {id: #}) RETURN n");
post.set(replacer(query));
/* std::cout << "REQUEST" << std::endl; */
/* std::cout << static_cast<const std::string&>(post) << std::endl; */
/* std::cout << "SIZE = " << static_cast<const std::string&>(post).size() << std::endl; */
auto n = socket.write(static_cast<const std::string&>(post));
/* std::cout << "Written N = " << n << " bytes." << std::endl; */
LOG_DEBUG("sent.");
}
Result run_benchmark(std::chrono::duration<double> duration)
{
LOG_DEBUG("run_benchmark");
using clock = std::chrono::high_resolution_clock;
clock::time_point end, start = clock::now();
for(auto& stream : streams)
sendreq(stream->socket);
LOG_DEBUG("sent req to all streams");
while(true)
{
LOG_DEBUG("WAIT AND PROCESS");
this->wait_and_process_events();
if((end = clock::now()) - start > duration)
break;
}
return {start, end, requests};
}
private:
uint64_t requests {0};
std::vector<std::unique_ptr<io::tcp::Stream>> streams;
};
class WorkerRunner
{
public:
WorkerRunner() : worker(std::make_unique<Worker>()) {}
Worker* operator->() { return worker.get(); }
const Worker* operator->() const { return worker.get(); }
void operator()(std::chrono::duration<double> duration)
{
std::packaged_task<Result()> task([this, duration]() {
return this->worker->run_benchmark(duration);
});
result = std::move(task.get_future());
std::thread(std::move(task)).detach();
}
std::unique_ptr<Worker> worker;
std::future<Result> result;
};
std::atomic<bool> alive {true};
int main(int argc, const char* argv[])
{
using clock = std::chrono::high_resolution_clock;
using namespace std::chrono;
if(argc < 4)
std::abort();
auto threads = std::stoi(argv[1]);
auto connections = std::stoi(argv[2]);
auto duration = std::stoi(argv[3]);
std::vector<WorkerRunner> workers;
for(int i = 0; i < threads; ++i)
workers.emplace_back();
for(int i = 0; i < connections; ++i)
workers[i % threads]->connect("localhost", "7474");
std::vector<Result> results;
std::cout << "Running queries on " << connections << " connections "
<< "using " << threads << " threads "
<< "for " << duration << " seconds." << std::endl
<< "..." << std::endl;
for(auto& worker : workers)
worker(std::chrono::seconds(duration));
for(auto& worker : workers)
{
worker.result.wait();
results.push_back(worker.result.get());
}
auto start = std::min_element(results.begin(), results.end(),
[](auto a, auto b) { return a.start < b.start; })->start;
auto end = std::max_element(results.begin(), results.end(),
[](auto a, auto b) { return a.end < b.end; })->end;
auto requests = std::accumulate(results.begin() + 1, results.end(),
results[0].requests, [](auto acc, auto r) { return acc + r.requests; });
auto elapsed = (end - start).count() / 1.0e9;
std::cout << "Total of " << requests << " requests in "
<< elapsed << "s." << std::endl
<< "Requests/sec: " << int(requests / elapsed)
<< "." << std::endl;
return 0;
}

View File

@ -1,81 +0,0 @@
#include <iostream>
#include <cstdint>
#include <byteswap.h>
char b[8] = {1, 2, 3, 4, 0, 0, 0, 1};
int64_t safe_int64(const char* b)
{
return int64_t(b[0]) << 56 | int64_t(b[1]) << 48
| int64_t(b[2]) << 40 | int64_t(b[3]) << 32
| int64_t(b[4]) << 24 | int64_t(b[5]) << 16
| int64_t(b[6]) << 8 | int64_t(b[7]);
}
int64_t unsafe_int64(const char* b)
{
auto i = reinterpret_cast<const int64_t*>(b);
return __bswap_64(*i);
}
int32_t safe_int32(const char* b)
{
return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
}
int32_t unsafe_int32(const char* b)
{
auto i = reinterpret_cast<const int32_t*>(b);
return __bswap_32(*i);
}
[[clang::optnone]]
void test(uint64_t n)
{
for(uint64_t i = 0; i < n; ++i)
unsafe_int64(b);
}
uint8_t f[8] = {0x3F, 0xF1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A};
double ff = 1.1;
double get_double(const uint8_t* b)
{
auto v = __bswap_64(*reinterpret_cast<const uint64_t*>(b));
return *reinterpret_cast<const double*>(&v);
}
void print_hex(const char* buf, size_t n)
{
for (size_t i = 0; i < n; ++i)
printf("%02X ", (unsigned char)buf[i]);
}
void print_hex(const uint8_t* buf, size_t n)
{
print_hex((const char*)buf, n);
}
int main(void)
{
auto dd = get_double(f);
print_hex(f, 8);
std::cout << std::endl;
print_hex((const uint8_t*)(&ff), 8);
std::cout << std::endl;
print_hex((const uint8_t*)(&dd), 8);
std::cout << dd << std::endl;
/* std::cout << safe_int64(b) << std::endl; */
/* std::cout << unsafe_int64(b) << std::endl; */
/* test(1000000000ull); */
return 0;
}

View File

@ -1,32 +0,0 @@
#include <iostream>
#include "utils/exceptions/basic_exception.hpp"
void i_will_throw()
{
throw BasicException("this is not {}", "ok!");
}
void bar()
{
i_will_throw();
}
void foo()
{
bar();
}
int main(void)
{
try
{
foo();
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}

View File

@ -1,63 +0,0 @@
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <vector>
#include <cassert>
#include <random>
#include "threading/sync/futex.hpp"
#include "threading/sync/spinlock.hpp"
//#include "debug/log.hpp"
Futex futex;
//std::mutex mutex;
//SpinLock spinlock;
int x = 0;
void test_lock(int id)
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 1000);
for(int i = 0; i < 5000000; ++i)
{
// uncomment sleeps and LOG_DEBUGs to test high contention
//LOG_DEBUG("Acquiring Futex (" << id << ")");
{
//std::unique_lock<SpinLock> guard(spinlock);
std::unique_lock<Futex> guard(futex);
//std::unique_lock<std::mutex> guard(mutex);
x++;
//std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen)));
//LOG_DEBUG("Critical section no. " << i << " (" << id << ")");
assert(x == 1);
x--;
}
//LOG_DEBUG("Non Critical section... (" << id << ")");
//std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen)));
}
}
int main(void)
{
constexpr int N = 4;
std::vector<std::thread> threads;
for(int i = 0; i < N; ++i)
threads.push_back(std::thread(test_lock, i));
for(auto& thread : threads){
thread.join();
}
return 0;
}

View File

@ -1,77 +0,0 @@
#include <iostream>
#include <mutex>
#include <vector>
#include <chrono>
#include "threading/thread.hpp"
#include "threading/hazard_ptr.hpp"
std::mutex mutex;
struct Foo
{
int bar = 0;
};
void scan_foos(const std::vector<Foo>& foos)
{
auto& hp = HazardStore::get();
std::unique_lock<std::mutex> cout_guard(mutex);
std::cout << "Scanning foos..." << std::endl;
for(auto& foo : foos)
{
auto foo_ptr = &foo;
std::unique_lock<std::mutex> cout_guard(mutex);
std::cout << "Foo taken? " << hp.scan(foo_ptr) << std::endl;
}
}
int main(void)
{
using namespace std::chrono_literals;
std::cout << std::boolalpha;
static constexpr size_t NUM_THREADS = 8;
std::vector<Thread> threads;
std::vector<Foo> foos;
foos.resize(NUM_THREADS + 2);
for(size_t i = 0; i < NUM_THREADS; ++i)
threads.emplace_back([&foos]() {
auto id = this_thread::id;
auto foo = &foos.at(id);
auto hazard = hazard_ptr(foo);
foo->bar = id;
std::unique_lock<std::mutex> cout_guard(mutex);
std::cout << "Hello from thread " << this_thread::id << std::endl;
std::this_thread::sleep_for(5s);
});
// 0 to NUM_THREADS foos should be taken
// maybe none, maybe all!
scan_foos(foos);
std::this_thread::sleep_for(3s);
// first NUM_THREADS foos should be taken
scan_foos(foos);
std::this_thread::sleep_for(3s);
// all foos should be available now
scan_foos(foos);
for(auto& thread : threads)
thread.join();
return 0;
}

View File

@ -1,41 +0,0 @@
#include <iostream>
#include "mvcc/id.hpp"
using std::cout;
using std::endl;
int main() {
Id id0(0);
Id id1(1);
Id id2(1);
Id id3(id2);
Id id4 = id3;
Id id5(5);
cout << id5 << " " << id0 << endl;
if (id0 < id5)
cout << "id0 < id5" << endl;
if (id1 == id2)
cout << "are equal" << endl;
if (id3 == id4)
cout << "id3 == id4" << endl;
if (id5 > id0)
cout << "id5 > id0" << endl;
if (id5 != id3)
cout << "id5 != id3" << endl;
if (id1 >= id2)
cout << "id1 >= id2" << endl;
if (id3 <= id4)
cout << "id3 <= id4" << endl;
return 0;
}

View File

@ -1,59 +0,0 @@
#include <iostream>
#include "transactions/engine.hpp"
#include "mvcc/version_list.hpp"
#include "storage/vertex.hpp"
#include "storage/indexes/property_index.hpp"
using std::cout;
using std::endl;
using Record = mvcc::VersionList<Vertex>;
tx::Engine engine;
Index<Vertex>* index = new PropertyIndex<Vertex>();
Record* create(int id, tx::Transaction& t)
{
auto v = new record_t(id);
auto a = v->access(t);
a.insert();
return v;
}
auto insert(int id, tx::Transaction& t)
{
auto r = create(id, t);
return index.insert(&r->id, r, t);
}
int main(void)
{
/* v1->data.props.set<String>("name", "buda"); */
/* v1->data.props.set<Int32>("age", 23); */
auto& t1 = engine.begin();
insert(0, t1);
insert(1, t1);
insert(2, t1);
insert(3, t1);
insert(6, t1);
insert(7, t1);
t1.commit();
auto& t2 = engine.begin();
insert(4, t2);
insert(5, t2);
insert(8, t2);
t2.commit();
auto& t3 = engine.begin();
auto cursor = index.scan(8, t3);
for(; not cursor.end(); cursor++)
cout << cursor->id() << endl;
return 0;
}

View File

@ -1,26 +0,0 @@
#include "logging/logger.hpp"
#include "logging/logs/sync_log.hpp"
#include "logging/logs/async_log.hpp"
#include "logging/streams/stdout.hpp"
int main(void)
{
//Log::uptr log = std::make_unique<SyncLog>();
Log::uptr log = std::make_unique<AsyncLog>();
log->pipe(std::make_unique<Stdout>());
auto logger = log->logger("main");
logger.info("This is very {}!", "awesome");
logger.warn("This is very {}!", "awesome");
logger.error("This is very {}!", "awesome");
logger.trace("This is very {}!", "awesome");
logger.debug("This is very {}!", "awesome");
using namespace std::chrono;
/* std::this_thread::sleep_for(1s); */
return 0;
}

View File

@ -1,55 +0,0 @@
#include <iostream>
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/property.hpp"
#include "storage/model/properties/traversers/jsonwriter.hpp"
using std::endl;
using std::cout;
int main(void)
{
Properties props;
props.set<Bool>("awesome", true);
props.set<Bool>("lame", false);
props.set<Int32>("age", 32);
// integral
Int32 a = 12;
Int32 b = 24;
Int32 c = b;
Property& d = b;
cout << "a = " << a << "; b = " << b << endl;
cout << (a > b) << (a < b) << (a == b) << (a != b) << endl;
cout << "b == d" << " -> " << (b == d) << endl;
Float x = 3.14;
Float y = 6.28;
Float z = x * 3.28 / y + a * b + 3;
cout << x << endl;
cout << z << endl;
props.set<Float>("pi", z);
cout << props.at("awesome") << endl;
cout << props.at("lame") << endl;
cout << props.at("age") << endl;
cout << props.at("pi") << endl;
cout << props.at("lol") << endl;
StringBuffer buffer;
JsonWriter<StringBuffer> writer(buffer);
props.accept(writer);
cout << buffer.str() << endl;
return 0;
}

View File

@ -1,53 +0,0 @@
#include <iostream>
#include "data_structures/skiplist/skiplist.hpp"
using std::cout;
using std::endl;
using skiplist_t = SkipList<int, int>;
void print_skiplist(const skiplist_t::Accessor& skiplist)
{
cout << "---- skiplist now has: ";
for(auto& kv : skiplist)
cout << "(" << kv.first << ", " << kv.second << ") ";
cout << "----" << endl;
}
int main(void)
{
cout << std::boolalpha;
skiplist_t skiplist;
auto accessor = skiplist.access();
cout << "added non-existing (1, 10)? (true) "
<< accessor.insert_unique(1, 10).second << endl;
cout << "added already existing (1, 10)? (false) "
<< accessor.insert_unique(1, 10).second << endl;
accessor.insert_unique(2, 20);
print_skiplist(accessor);
cout << "value at key 3 exists? (false) "
<< (accessor.find(3) == accessor.end()) << endl;
cout << "value at key 2 exists? (true) "
<< (accessor.find(2) != accessor.end()) << endl;
cout << "at key 2 is? (20) " << accessor.find(2)->second << endl;
cout << "removed existing (1)? (true) " << accessor.remove(1) << endl;
cout << "removed non-existing (3)? (false) " << accessor.remove(3) << endl;
accessor.insert_unique(1, 10);
accessor.insert_unique(4, 40);
print_skiplist(accessor);
return 0;
}

View File

@ -1,40 +0,0 @@
#include <iostream>
#include "data_structures/skiplist/skiplist.hpp"
#include "storage/indexes/keys/unique_key.hpp"
using std::cout;
using std::endl;
using skiplist_t = SkipList<UniqueKeyAsc<int>, int>;
void print_skiplist(const skiplist_t::Accessor& skiplist)
{
cout << "---- skiplist now has: ";
for(auto& kv : skiplist)
cout << "(" << kv.first << ", " << kv.second << ") ";
cout << "----" << endl;
}
int main(void)
{
skiplist_t skiplist;
auto accessor = skiplist.access();
// this has to be here since UniqueKey<> class takes references!
int keys[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
accessor.insert_unique(keys[1], 10);
accessor.insert_unique(keys[2], 20);
accessor.insert_unique(keys[7], 70);
accessor.insert_unique(keys[4], 40);
accessor.insert_unique(keys[8], 80);
accessor.insert_unique(keys[3], 30);
print_skiplist(accessor);
return 0;
}

View File

@ -1,54 +0,0 @@
#include <iostream>
#include "data_structures/skiplist/skiplistset.hpp"
using std::cout;
using std::endl;
void print_skiplist(const SkipListSet<int>::Accessor& skiplist)
{
cout << "---- skiplist set now has: ";
for(auto& item : skiplist)
cout << item << ", ";
cout << "----" << endl;
}
int main(void)
{
SkipListSet<int> set;
auto accessor = set.access();
cout << std::boolalpha;
cout << "added non-existing 1? (true) "
<< accessor.insert(1).second << endl;
cout << "added already existing 1? (false) "
<< accessor.insert(1).second << endl;
accessor.insert(2);
print_skiplist(accessor);
cout << "item 3 doesn't exist? (true) "
<< (accessor.find(3) == accessor.end()) << endl;
cout << "item 3 exists? (false) "
<< accessor.contains(3) << endl;
cout << "item 2 exists? (true) "
<< (accessor.find(2) != accessor.end()) << endl;
cout << "at item 2 is? 2 " << *accessor.find(2) << endl;
cout << "removed existing 1? (true) " << accessor.remove(1) << endl;
cout << "removed non-existing 3? (false) " << accessor.remove(3) << endl;
accessor.insert(1);
accessor.insert(4);
print_skiplist(accessor);
return 0;
}

View File

@ -1,27 +0,0 @@
#include <iostream>
#include <fstream>
#include <cstring>
std::string load_file(const std::string& fname)
{
std::ifstream in(fname);
return std::string((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
}
int main(int argc, const char* argv[])
{
if(argc < 3)
return -1;
auto a = load_file(argv[1]);
auto b = load_file(argv[2]);
bool result = true;
for(size_t i = 0; i < a.size(); ++i)
result &= strcmp(a.c_str() + i, b.c_str() + i) == 0;
std::cout << result << std::endl;
return 0;
}

View File

@ -1,23 +0,0 @@
#include <iostream>
#include <chrono>
#include <thread>
#include "utils/datetime/timestamp.hpp"
int main(void)
{
auto timestamp = Timestamp::now();
std::cout << timestamp << std::endl;
std::cout << Timestamp::now() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
std::cout << Timestamp::now().to_iso8601() << std::endl;
std::cout << std::boolalpha;
std::cout << (timestamp == Timestamp::now()) << std::endl;
return 0;
}

View File

@ -1,45 +0,0 @@
#include <iostream>
#include "transactions/engine.hpp"
#include "mvcc/version_list.hpp"
#include "storage/vertex.hpp"
using std::cout;
using std::endl;
int main(void)
{
tx::Engine engine;
VertexRecord vertex;
auto& t1 = engine.begin();
auto a1 = vertex.access(t1);
auto v1 = a1.insert();
v1->data.props.set<String>("name", "buda");
v1->data.props.set<Int32>("age", 23);
cout << vertex;
t1.commit();
auto& t2 = engine.begin();
auto a2 = vertex.access(t2);
auto v2 = a2.update();
v2->data.props.set<Int32>("age", 24);
cout << vertex;
t2.abort();
auto& t3 = engine.begin();
auto a3 = vertex.access(t3);
auto v3 = a3.update();
v3->data.props.set<Int32>("age", 25);
cout << vertex;
return 0;
}

View File

@ -1,67 +0,0 @@
/* Plots the distribution histogram of the xorshift algorithm
* (spoiler alert: it's pleasingly uniform all the way :D)
*/
#include <iostream>
#include <array>
#include <atomic>
#include <thread>
#include <cassert>
#include <sys/ioctl.h>
#include <unistd.h>
#include "utils/random/xorshift128plus.hpp"
static thread_local Xorshift128plus rnd;
static constexpr unsigned B = 1 << 10;
static constexpr uint64_t K = (uint64_t)(-1) / B;
static constexpr unsigned M = 4;
static constexpr size_t N = 1ULL << 34;
static constexpr size_t per_thread_iters = N / M;
std::array<std::atomic<unsigned>, B> buckets;
void generate()
{
for(size_t i = 0; i < per_thread_iters; ++i)
buckets[rnd() / K].fetch_add(1);
}
int main(void)
{
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
auto bar_len = w.ws_col - 20;
std::array<std::thread, M> threads;
for(auto& bucket : buckets)
bucket.store(0);
for(auto& t : threads)
t = std::thread([]() { generate(); });
for(auto& t : threads)
t.join();
auto max = std::accumulate(buckets.begin(), buckets.end(), 0u,
[](auto& acc, auto& x) { return std::max(acc, x.load()); });
assert(max != 0u);
std::cout << std::fixed;
for(auto& bucket : buckets)
{
auto x = bucket.load();
auto rel = bar_len * x / max;
for(size_t i = 0; i < rel; ++i)
std::cout << "=";
std::cout << " " << 100.0 * x / N * B - 100 << "%" << std::endl;
}
return 0;
}

View File

@ -5,7 +5,7 @@
#include <functional>
#include "logging/default.hpp"
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
#include "utils/likely.hpp"
#include "utils/types/byte.hpp"
@ -14,9 +14,9 @@ namespace bolt {
template <class Stream>
class ChunkedDecoder {
public:
class DecoderError : public BasicException {
class DecoderError : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};
ChunkedDecoder(Stream &stream) : stream(stream) {}

View File

@ -1,11 +1,11 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
namespace bolt {
class StreamError : BasicException {
class StreamError : StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};
}

View File

@ -1,53 +0,0 @@
#pragma once
#include <queue>
#include "threading/sync/lockable.hpp"
#include "threading/sync/spinlock.hpp"
template <class T>
class SlQueue : Lockable<SpinLock> {
public:
template <class... Args>
void emplace(Args&&... args) {
auto guard = acquire_unique();
queue.emplace(args...);
}
void push(const T& item) {
auto guard = acquire_unique();
queue.push(item);
}
T front() {
auto guard = acquire_unique();
return queue.front();
}
void pop() {
auto guard = acquire_unique();
queue.pop();
}
bool pop(T& item) {
auto guard = acquire_unique();
if (queue.empty()) return false;
item = std::move(queue.front());
queue.pop();
return true;
}
bool empty() {
auto guard = acquire_unique();
return queue.empty();
}
size_t size() {
auto guard = acquire_unique();
return queue.size();
}
private:
std::queue<T> queue;
};

View File

@ -1,12 +0,0 @@
#pragma once
#include <map>
#include "threading/sync/spinlock.hpp"
template <class K, class T>
class SlRbTree : Lockable<SpinLock> {
public:
private:
std::map<K, T> tree;
};

View File

@ -1,28 +0,0 @@
#pragma once
#include <stack>
#include "threading/sync/lockable.hpp"
#include "threading/sync/spinlock.hpp"
template <class T>
class SpinLockStack : Lockable<SpinLock> {
public:
T pop() {
auto guard = acquire();
T elem = stack.top();
stack.pop();
return elem;
}
void push(const T& elem) {
auto guard = acquire();
stack.push(elem);
}
private:
std::stack<T> stack;
};

View File

@ -1,6 +0,0 @@
#pragma once
template <class T>
class ArrayStack {
private:
};

View File

@ -5,13 +5,13 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
/**
* Thrown when something (Edge or a Vertex) can not
* be created. Typically due to database overload.
*/
class CreationException : public BasicException {
class CreationException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -1 +0,0 @@
test

View File

@ -9,9 +9,9 @@
namespace io {
class EpollError : BasicException {
class EpollError : StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};
class Epoll {

View File

@ -2,12 +2,12 @@
#include <stdexcept>
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
namespace io {
class NetworkError : public BasicException {
class NetworkError : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};
}

View File

@ -1,126 +0,0 @@
#include <signal.h>
#include <iostream>
#include <thread>
#include <vector>
#include "http/request.hpp"
#include "http/response.hpp"
#include "http/worker.hpp"
#include "socket.hpp"
#ifndef NDEBUG
#define LOG_DEBUG(x) std::cout << x << std::endl;
#else
#define LOG_DEBUG(x)
#endif
std::hash<std::thread::id> hash;
constexpr unsigned K = 128;
std::array<http::Parser<http::Request, http::Response>, K> workers;
std::array<std::thread, K> threads;
std::atomic<bool> alive{true};
void exiting() { LOG_DEBUG("Exiting..."); }
void sigint_handler(int) {
exiting();
std::exit(0);
}
#define MAXEVENTS 64
int main(void) {
// std::atexit(exiting);
signal(SIGINT, sigint_handler);
for (size_t i = 0; i < workers.size(); ++i) {
auto &w = workers[i];
threads[i] = std::thread([i, &w]() {
while (alive) {
LOG_DEBUG("waiting for events on thread " << i);
w.wait_and_process_events();
}
});
}
/* size_t WORKERS = std::thread::hardware_concurrency(); */
/* std::vector<io::Worker> workers; */
/* workers.resize(WORKERS); */
/* for(size_t i = 0; i < WORKERS; ++i) */
/* { */
/* workers.push_back(std::move(io::Worker())); */
/* workers.back().start(); */
/* } */
int idx = 0;
auto socket = io::Socket::bind("0.0.0.0", "7474");
socket.set_non_blocking();
socket.listen(1024);
int efd, s;
struct epoll_event event;
struct epoll_event *events;
efd = epoll_create1(0);
if (efd == -1) {
perror("epoll_create");
abort();
}
event.data.fd = socket;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, socket, &event);
if (s == -1) {
perror("epoll_ctl");
abort();
}
/* Buffer where events are returned */
events = static_cast<struct epoll_event *>(calloc(MAXEVENTS, sizeof event));
/* The event loop */
while (1) {
int n, i;
LOG_DEBUG("acceptor waiting for events");
n = epoll_wait(efd, events, MAXEVENTS, -1);
LOG_DEBUG("acceptor recieved " << n << " connection requests");
for (i = 0; i < n; i++) {
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) ||
(!(events[i].events & EPOLLIN))) {
/* An error has occured on this fd, or the socket is not
ready for reading (why were we notified then?) */
fprintf(stderr, "epoll error\n");
close(events[i].data.fd);
continue;
}
else if (socket == events[i].data.fd) {
/* We have a notification on the listening socket, which
means one or more incoming connections. */
while (true) {
LOG_DEBUG("trying to accept connection on thread " << idx);
if (!workers[idx].accept(socket)) break;
LOG_DEBUG("Accepted a new connection on thread " << idx);
idx = (idx + 1) % workers.size();
break;
}
}
}
}
free(events);
return 0;
}

View File

@ -1,11 +1,11 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
namespace io {
class TlsError : public BasicException {
class TlsError : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};
}

View File

@ -79,9 +79,9 @@ class QueryEngine : public Loggable {
logger.error("QueryEngineException: {}", std::string(e.what()));
throw e;
} catch (std::exception &e) {
throw BasicException(e.what());
throw StacktraceException(e.what());
} catch (...) {
throw BasicException("unknown query engine exception");
throw StacktraceException("unknown query engine exception");
}
}

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class CppCodeGeneratorException : public BasicException {
class CppCodeGeneratorException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class DecoderException : public BasicException {
class DecoderException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class PlanCompilationException : public BasicException {
class PlanCompilationException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class PlanExecutionException : public BasicException {
class PlanExecutionException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class QueryEngineException : public BasicException {
class QueryEngineException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -10,25 +10,19 @@ using std::endl;
// Query: {{query}}
class {{class_name}} : public PlanInterface<{{stream}}>
{
class {{class_name}} : public PlanInterface<{{stream}}> {
public:
bool run(Db &db, const PlanArgsT &args,
{{stream}} &stream) override
{
{{code}}
bool run(Db &db, const PlanArgsT &args, {{stream}} &stream) override {
{{code}}
}
~{{class_name}}() {}
};
extern "C" PlanInterface<{{stream}}>* produce()
{
extern "C" PlanInterface<{{stream}}>* produce() {
return new {{class_name}}();
}
extern "C" void destruct(PlanInterface<{{stream}}>* p)
{
extern "C" void destruct(PlanInterface<{{stream}}>* p) {
delete p;
}

View File

@ -7,7 +7,7 @@
#include "fmt/format.h"
#include "logging/default.hpp"
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
using std::cout;
using std::endl;
@ -18,9 +18,9 @@ using std::endl;
// but sometimes that might be a problem
namespace {
class CodeLineFormatException : public BasicException {
class CodeLineFormatException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};
template <typename... Args>

View File

@ -6,7 +6,7 @@
#include <string>
#include <vector>
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
#include "utils/total_ordering.hpp"
#include "utils/underlying_cast.hpp"
@ -82,9 +82,9 @@ class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
* trying to perform operations (such as addition) on TypedValues
* of incompatible Types.
*/
class TypedValueException : public BasicException {
class TypedValueException : public StacktraceException {
public:
using ::BasicException::BasicException;
using ::StacktraceException::StacktraceException;
};
// comparison operators

6
src/test/.gitignore vendored
View File

@ -1,6 +0,0 @@
# ignore object and executable files
*.o
tests
# ignore the library, download your own copy via install.sh
catch.hpp

View File

@ -1,29 +0,0 @@
TARGET = tests
LIBS = -lm
CC = c++
CFLAGS = -g -Wall -std=c++1y
INCLUDE = "../"
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
HEADERS = $(wildcard *.hpp)
%.o: %.cpp $(HEADERS)
$(CC) $(CFLAGS) -I $(INCLUDE) -c $< -o $@
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $@
clean:
-rm -f *.o
-rm -f $(TARGET)
test:
make
./tests

View File

@ -1,3 +0,0 @@
# NOTE
Files with .old extension are old test files. They have to be rewritten because of changes in the appropriate project files.
bitblock.hpp is going to be replaced with the dynamic_bitset

View File

@ -1,186 +0,0 @@
#include <thread>
#include "catch.hpp"
#include "data_structures/bitset/bitblock.hpp"
#include "sync/spinlock.hpp"
TEST_CASE("BitBlock should be empty on construction")
{
BitBlock<> bb;
REQUIRE(bb.block.load(std::memory_order_relaxed) == 0);
}
template <class block_t, size_t N>
void test_sizes()
{
BitBlock<block_t, N> bb;
auto bits = bb.bits;
auto size = bb.size;
REQUIRE(bits == (8 * sizeof(block_t)));
REQUIRE(size == (8 * sizeof(block_t) / N));
}
template <class T, size_t N>
struct test_sizes_loop : test_sizes_loop<T, N - 1>
{
test_sizes_loop()
{
test_sizes<T, N>();
}
};
template <class T>
struct test_sizes_loop<T, 1>
{
test_sizes_loop()
{
test_sizes<T, 1>();
}
};
TEST_CASE("BitBlock bit sizes should be set correctly")
{
test_sizes_loop<uint8_t, 8> size_test8;
test_sizes_loop<uint16_t, 8> size_test16;
test_sizes_loop<uint32_t, 8> size_test32;
test_sizes_loop<uint64_t, 8> size_test64;
}
TEST_CASE("Values load correctly from the BitBlock")
{
constexpr uint32_t k = 0xCA3F;
SECTION("Block size = 1")
{
constexpr size_t N = 1;
BitBlock<uint32_t, N> bb;
bb.block.store(k);
for(size_t i = 0; i < bb.size; ++i)
REQUIRE(bb.at(i) == ((k >> i) & 1));
}
SECTION("Block size = 4")
{
constexpr size_t N = 4;
BitBlock<uint32_t, N> bb;
bb.block.store(k);
for(size_t i = 0; i < bb.size; ++i)
REQUIRE(bb.at(i) == ((k >> (N * i)) & 0xF));
}
}
TEST_CASE("You can set a bit in a BitBlock and get the result")
{
SECTION("Block size = 1")
{
BitBlock<uint8_t, 1> bb;
for(size_t i = 0; i < bb.bits; ++i)
{
bb.set(i, 1);
for(size_t j = 0; j < bb.bits; ++j)
{
if(j <= i)
REQUIRE(bb.at(j) == 1);
else
REQUIRE(bb.at(j) == 0);
}
}
}
SECTION("Block size = 2")
{
constexpr size_t N = 2;
BitBlock<uint16_t, N> bb;
for(size_t i = 0; i < bb.size; ++i)
{
auto k = i % (1 << N);
bb.set(i, k);
for(size_t j = 0; j < bb.size; j++)
{
auto l = j % (1 << N);
if(j <= i)
REQUIRE(bb.at(j) == l);
else
REQUIRE(bb.at(j) == 0);
}
}
}
SECTION("Block size = 5")
{
constexpr size_t N = 5;
BitBlock<uint16_t, N> bb;
for(size_t i = 0; i < bb.size; ++i)
{
auto k = i % (1 << N);
bb.set(i, k);
for(size_t j = 0; j < bb.size; j++)
{
auto l = j % (1 << N);
if(j <= i)
REQUIRE(bb.at(j) == l);
else
REQUIRE(bb.at(j) == 0);
}
}
}
}
template <class T, size_t N>
void bitblock_thead_test(BitBlock<T, N>* bb, size_t idx, size_t n)
{
static SpinLock lock;
uint8_t x;
uint64_t sum = 0, actual = 0;
for(size_t i = 0; i < n; ++i)
{
int y = i % 2;
actual += i * y;
bb->set(idx, y);
x = bb->at(idx);
sum += i * x;
bb->clear(idx);
x = bb->at(idx);
}
auto guard = std::unique_lock<SpinLock>(lock);
REQUIRE(sum == actual);
}
TEST_CASE("(try to) Test multithreaded correctness")
{
BitBlock<uint64_t, 1> bb;
constexpr int N = 2;
constexpr int K = 500000;
std::vector<std::thread> threads;
for(int i = 0; i < N; ++i)
threads.push_back(std::thread(
bitblock_thead_test<uint64_t, 1>, &bb, i, K));
for(auto& thread : threads){
thread.join();
}
}

View File

@ -1,7 +0,0 @@
#!/bin/sh
echo "Installing Catch..."
wget https://raw.githubusercontent.com/philsquared/Catch/develop/single_include/catch.hpp
echo "All done!"

View File

@ -1,48 +0,0 @@
#include <iostream>
#include <array>
#include "catch.hpp"
#include "data_structures/skiplist/new_height.hpp"
TEST_CASE("New height distribution must be approx. 1/2 1/4 1/8 ...")
{
// NEVER forget to do this.
xorshift::init();
constexpr int N = 1e8;
constexpr int max_height = 8;
// 2% is a good margin to start with, no?
// depends on the max_height and N, beware.
constexpr double error_margin = 0.02;
// array to store the number of i-height towers generated
std::array<int, max_height> heights;
heights.fill(0);
// generate a tower and put it in a box with his same-height brothers
for(int i = 0; i < N; ++i)
heights[new_height(max_height) - 1]++;
// evaluate the number of towers in all of the boxes
for(int i = 1; i < max_height; ++i)
{
// compute how much towers should be in this box
int x = N / (2 << i);
// the actual number of towers
int xx = heights[i];
// relative error
double relative_error = (double)std::abs(xx - x) / xx;
// this might fail actually in some cases, especially if N is not big
// enough. it's probabilistic after all :D
REQUIRE(relative_error < error_margin);
}
}
TEST_CASE("You can add an item to the skiplist")
{
}

View File

@ -1,51 +0,0 @@
#include <thread>
#include <chrono>
#include <vector>
#include <mutex>
#include <atomic>
#include "catch.hpp"
#include "sync/spinlock.hpp"
TEST_CASE("a thread can acquire and release the lock", "[spinlock]")
{
{
std::unique_lock<SpinLock> lock;
// I HAS A LOCK!
}
REQUIRE(true);
}
int x = 0;
SpinLock lock;
void test_lock()
{
using namespace std::literals;
{
std::unique_lock<SpinLock> guard(lock);
x++;
std::this_thread::sleep_for(25ms);
REQUIRE(x < 2);
x--;
}
}
TEST_CASE("only one thread at a time can own the lock", "[spinlock]")
{
constexpr int N = 64;
std::vector<std::thread> threads;
for(int i = 0; i < N; ++i)
threads.push_back(std::thread(test_lock));
for(auto& thread : threads){
thread.join();
}
}

View File

@ -1,53 +0,0 @@
#include <thread>
#include <vector>
#include <unistd.h>
#include "catch.hpp"
#include "transaction/transactionengine.hpp"
#include "sync/spinlock.hpp"
TEST_CASE("(try to) test correctness of the transaction life cycle")
{
constexpr int THREADS = 16;
constexpr int TRANSACTIONS = 10;
TransactionEngine<uint64_t, SpinLock> engine(0);
std::vector<uint64_t> sums;
sums.resize(THREADS);
auto f = [&engine, &sums](int idx, int n)
{
uint64_t sum = 0;
for(int i = 0; i < n; ++i)
{
auto t = engine.begin();
sum += t.id;
engine.commit(t);
}
sums[idx] = sum;
};
std::vector<std::thread> threads;
for(int i = 0; i < THREADS; ++i)
threads.push_back(std::thread(f, i, TRANSACTIONS));
for(auto& thread : threads)
thread.join();
uint64_t sum_computed = 0;
for(int i = 0; i < THREADS; ++i)
sum_computed += sums[i];
uint64_t sum_actual = 0;
for(uint64_t i = 0; i <= THREADS * TRANSACTIONS; ++i)
sum_actual += i;
REQUIRE(sum_computed == sum_actual);
}

View File

@ -1 +0,0 @@
test

View File

@ -1,98 +0,0 @@
#pragma once
#include <unistd.h>
#include <atomic>
#include <vector>
#include "hazard_store.hpp"
class hazard_ptr {
static constexpr size_t EMPTY = -1;
static constexpr uintptr_t NULLPTR = 0;
public:
hazard_ptr() = default;
template <class T>
hazard_ptr(const T* ptr) : ptr(reinterpret_cast<uintptr_t>(ptr)) {
if (ptr == nullptr) return;
idx = HazardStore::get().acquire(this->ptr);
}
hazard_ptr(const hazard_ptr&) = delete;
hazard_ptr(hazard_ptr&& other) { *this = std::move(other); }
~hazard_ptr() { reset(); }
void reset() {
if (idx == EMPTY) return;
HazardStore::get().release(idx);
detach();
}
hazard_ptr& operator=(hazard_ptr&& other) {
reset();
ptr = other.ptr;
idx = other.idx;
other.detach();
return *this;
}
uintptr_t get() const { return ptr; }
template <class T>
operator T*() const {
return reinterpret_cast<T*>(ptr);
}
friend bool operator==(const hazard_ptr& lhs, uintptr_t rhs) {
return lhs.ptr == rhs;
}
friend bool operator==(uintptr_t lhs, const hazard_ptr& rhs) {
return operator==(rhs, lhs);
}
template <class T>
friend bool operator==(const hazard_ptr& lhs, const T* const rhs) {
return lhs.ptr == reinterpret_cast<uintptr_t>(rhs);
}
template <class T>
friend bool operator==(const T* const lhs, const hazard_ptr& rhs) {
return operator==(rhs, lhs);
}
friend bool operator!=(const hazard_ptr& lhs, uintptr_t rhs) {
return !operator==(lhs, rhs);
}
friend bool operator!=(uintptr_t lhs, const hazard_ptr& rhs) {
return operator!=(rhs, lhs);
}
template <class T>
friend bool operator!=(const hazard_ptr& lhs, const T* const rhs) {
return !operator==(lhs, rhs);
}
template <class T>
friend bool operator!=(const T* const lhs, const hazard_ptr& rhs) {
return operator!=(rhs, lhs);
}
private:
uintptr_t ptr{NULLPTR};
size_t idx{EMPTY};
void detach() {
ptr = NULLPTR;
idx = EMPTY;
}
};

View File

@ -1,81 +0,0 @@
#pragma once
#include <atomic>
#include <cassert>
#include <cstdlib>
#include <thread>
#include <vector>
#include "id.hpp"
class HazardPointerError : std::runtime_error {
using runtime_error::runtime_error;
};
class HazardStore {
using atomic_hp_t = std::atomic<uintptr_t>;
static constexpr uintptr_t NULLPTR = 0;
friend class hazard_ptr;
HazardStore(size_t N, size_t K) : N(N), K(K), ptrs(new atomic_hp_t[N * K]) {}
public:
HazardStore(const HazardStore&) = delete;
HazardStore(HazardStore&&) = delete;
HazardStore& operator=(const HazardStore&) = delete;
static HazardStore& get() {
static constexpr size_t N = 16; // number of threds
static constexpr size_t K = 128; // pointers per thread
static HazardStore hp(N, K);
return hp;
}
template <class T>
bool scan(T* ptr) {
return scan(reinterpret_cast<uintptr_t>(ptr));
}
bool scan(uintptr_t ptr) {
assert(ptr != NULLPTR);
for (size_t i = 0; i < N * K; ++i) {
auto& hazard = ptrs[i];
if (hazard == ptr) return true;
}
return false;
}
private:
const size_t N, K;
std::unique_ptr<atomic_hp_t[]> ptrs;
size_t acquire(uintptr_t ptr) {
assert(ptr != NULLPTR);
auto idx = this_thread::id;
for (auto i = N * idx; i < N * idx + K; ++i) {
auto& hazard = ptrs[i];
if (hazard.load(std::memory_order_relaxed) == NULLPTR) continue;
// this MUST be seq_cst, otherwise garbage collector might not see
// the hazard pointer even if it is set
hazard.store(ptr, std::memory_order_seq_cst);
return i;
}
throw HazardPointerError("Exhausted all hazard pointers");
}
void release(size_t idx) {
assert(ptrs[idx] != NULLPTR);
ptrs[idx].store(NULLPTR, std::memory_order_release);
}
};

View File

@ -1,5 +0,0 @@
#pragma once
namespace this_thread {
// thread_local unsigned id = 0;
};

View File

@ -1,3 +1,6 @@
//
// Created by buda on 18/02/17.
//
#pragma once
#include <stdexcept>

View File

@ -0,0 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
class LockTimeoutException : public BasicException {
public:
using BasicException::BasicException;
};

View File

@ -1,22 +1,16 @@
#pragma onces
#include <unistd.h>
#include <atomic>
#include <chrono>
#include <stdexcept>
#include <unistd.h>
class LockExpiredError : public std::runtime_error {
using runtime_error::runtime_error;
};
#include "lock_timeout_exception.hpp"
template <size_t microseconds = 250>
class TimedSpinLock {
public:
TimedSpinLock(std::chrono::seconds expiration) : expiration(expiration) {}
TimedSpinLock(std::chrono::milliseconds expiration)
: expiration(expiration) {}
TimedSpinLock(std::chrono::seconds expiration) : expiration_(expiration) {}
void lock() {
using clock = std::chrono::high_resolution_clock;
@ -28,8 +22,8 @@ class TimedSpinLock {
// time, throw an exception and stop being blocked because this
// might be a deadlock!
if (clock::now() - start > expiration)
throw LockExpiredError("This lock has expired");
if (clock::now() - start > expiration_)
throw LockTimeoutException("This lock has expired");
usleep(microseconds);
}
@ -38,7 +32,7 @@ class TimedSpinLock {
void unlock() { lock_flag.clear(std::memory_order_release); }
private:
std::chrono::milliseconds expiration;
std::chrono::milliseconds expiration_;
// guaranteed by standard to be lock free!
std::atomic_flag lock_flag = ATOMIC_FLAG_INIT;

View File

@ -1,21 +0,0 @@
#include <iostream>
#include "pool.hpp"
int main(void) {
auto size = 7;
auto N = 1000000;
Pool pool(size);
for (int i = 0; i < N; ++i)
pool.run(
[](int) {
int sum = 0;
for (int i = 0; i < 2000; ++i) sum += i % 7;
},
i);
return 0;
}

View File

@ -4,7 +4,6 @@
#include <cassert>
#include <thread>
#include "id.hpp"
#include "utils/underlying_cast.hpp"
class Thread {

View File

@ -9,7 +9,7 @@
#include <string>
#include <vector>
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
#include "utils/option.hpp"
#define REGISTER_ARGS(argc, argv) \
@ -29,10 +29,10 @@ namespace {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
class ProgramArgumentException : public BasicException {
class ProgramArgumentException : public StacktraceException {
public:
ProgramArgumentException(const std::string &mess)
: BasicException("ProgramArgumentException: " + mess + ".") {}
: StacktraceException("ProgramArgumentException: " + mess + ".") {}
};
class ProgramArguments {

View File

@ -1,6 +1,6 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class Datetime {
public:

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class DatetimeError : public BasicException {
class DatetimeError : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -1,30 +1,50 @@
//
// Created by buda on 18/02/17.
//
#pragma once
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <stdexcept>
#include "utils/auto_scope.hpp"
#include "utils/stacktrace/stacktrace.hpp"
/**
* @brief BasicException
*
* Just a wrapper around std::exception.
*/
class BasicException : public std::exception {
public:
BasicException(const std::string &message) noexcept : message_(message) {
Stacktrace stacktrace;
message_.append(stacktrace.dump());
}
/** Constructor (C strings).
*
* @param message C-style string error message.
* The string contents are copied upon construction.
* Hence, responsibility for deleting the char* lies
* with the caller.
*/
explicit BasicException(const char* message) : msg_(message) {}
template <class... Args>
BasicException(const std::string &format, Args &&... args) noexcept
: BasicException(fmt::format(format, std::forward<Args>(args)...)) {}
/**
* Constructor (C++ STL strings).
*
* @param message The error message.
*/
explicit BasicException(const std::string& message) : msg_(message) {}
template <class... Args>
BasicException(const char *format, Args &&... args) noexcept
: BasicException(fmt::format(std::string(format),
std::forward<Args>(args)...)) {}
/**
* Destructor. Virtual to allow for subclassing.
*/
virtual ~BasicException() {}
const char *what() const noexcept override { return message_.c_str(); }
/**
* Returns a pointer to the (constant) error description.
*
* @return A pointer to a const char*. The underlying memory
* is in possession of the BasicException object. Callers must
* not attempt to free the memory.
*/
const char* what() const noexcept override { return msg_.c_str(); }
private:
std::string message_;
protected:
/**
* Error message.
*/
std::string msg_;
};

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class NonExhaustiveSwitch : public BasicException {
class NonExhaustiveSwitch : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -1,10 +1,10 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class NotYetImplemented : public BasicException {
class NotYetImplemented : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
NotYetImplemented() : BasicException("") {}
NotYetImplemented() : StacktraceException("") {}
};

View File

@ -1,8 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
class OutOfMemory : public BasicException {
class OutOfMemory : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};

View File

@ -0,0 +1,30 @@
#pragma once
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <stdexcept>
#include "utils/auto_scope.hpp"
#include "utils/stacktrace/stacktrace.hpp"
class StacktraceException : public std::exception {
public:
StacktraceException(const std::string &message) noexcept : message_(message) {
Stacktrace stacktrace;
message_.append(stacktrace.dump());
}
template <class... Args>
StacktraceException(const std::string &format, Args &&... args) noexcept
: StacktraceException(fmt::format(format, std::forward<Args>(args)...)) {}
template <class... Args>
StacktraceException(const char *format, Args &&... args) noexcept
: StacktraceException(fmt::format(std::string(format),
std::forward<Args>(args)...)) {}
const char *what() const noexcept override { return message_.c_str(); }
private:
std::string message_;
};

View File

@ -23,7 +23,7 @@ namespace fs = std::experimental::filesystem;
#include "logging/loggable.hpp"
#include "utils/algorithm.hpp"
#include "utils/assert.hpp"
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
#include "utils/linux.hpp"
#include "utils/underlying_cast.hpp"
@ -131,9 +131,9 @@ struct FSEvent : public FSEventBase {
/**
* Custom FSWatcher Exception
*/
class FSWatcherException : public BasicException {
class FSWatcherException : public StacktraceException {
public:
using BasicException::BasicException;
using StacktraceException::StacktraceException;
};
/**

View File

@ -15,13 +15,13 @@
#include <fcntl.h>
#include <unistd.h>
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/not_yet_implemented.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
#include "utils/likely.hpp"
namespace linux_os {
class LinuxException : public BasicException {
using BasicException::BasicException;
class LinuxException : public StacktraceException {
using StacktraceException::StacktraceException;
};
/**

View File

@ -8,7 +8,7 @@
#include "logging/streams/stdout.hpp"
#include "utils/command_line/arguments.hpp"
#include "utils/hashing/fnv64.hpp"
#include "utils/random/generator.h"
#include "utils/random/random_generator.hpp"
using utils::random::StringGenerator;
using StringHashFunction = std::function<uint64_t(const std::string &)>;

View File

@ -7,7 +7,7 @@
#include "logging/streams/stdout.hpp"
#include "utils/command_line/arguments.hpp"
#include "utils/hashing/fnv64.hpp"
#include "utils/random/generator.h"
#include "utils/random/random_generator.hpp"
#include "benchmark/benchmark_api.h"

View File

@ -5,7 +5,7 @@
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
#include "utils/command_line/arguments.hpp"
#include "utils/random/generator.h"
#include "utils/random/random_generator.hpp"
#include "benchmark/benchmark_api.h"

View File

@ -5,7 +5,7 @@
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
#include "utils/command_line/arguments.hpp"
#include "utils/random/generator.h"
#include "utils/random/random_generator.hpp"
#include "benchmark/benchmark_api.h"

View File

@ -14,7 +14,7 @@
#include "data_structures/concurrent/skiplist.hpp"
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
#include "utils/random/generator.h"
#include "utils/random/random_generator.hpp"
using utils::random::NumberGenerator;
using IntegerGenerator = NumberGenerator<std::uniform_int_distribution<int>,

View File

@ -1,9 +1,9 @@
#define LOG_NO_INFO 1
#include "benchmark/benchmark_api.h"
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
#include "query/preprocessor.hpp"
#include "benchmark/benchmark_api.h"
#include "yaml-cpp/yaml.h"
auto BM_Strip = [](benchmark::State &state, auto &function, std::string query) {

View File

@ -0,0 +1,42 @@
#include <chrono>
#include <mutex>
#include <random>
#include <thread>
#include "threading/sync/futex.hpp"
#include "utils/assert.hpp"
Futex futex;
int x = 0;
void test_lock(int id) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 1000);
for (int i = 0; i < 5000000; ++i) {
{
std::unique_lock<Futex> guard(futex);
x++;
std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen)));
permanent_assert(x == 1,
"Other thread shouldn't be able to "
"change the value of x");
x--;
}
std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen)));
}
}
int main(void) {
constexpr int N = 16;
std::vector<std::thread> threads;
for (int i = 0; i < N; ++i) threads.push_back(std::thread(test_lock, i));
for (auto& thread : threads) {
thread.join();
}
return 0;
}

View File

@ -0,0 +1,41 @@
#include <atomic>
#include <chrono>
#include <mutex>
#include <thread>
#include <vector>
#include "threading/sync/spinlock.hpp"
#include "utils/assert.hpp"
int x = 0;
SpinLock lock;
void test_lock() {
using namespace std::literals;
{
std::unique_lock<SpinLock> guard(lock);
x++;
std::this_thread::sleep_for(25ms);
permanent_assert(
x < 2,
"x always has to be less than 2 (other "
"threads shouldn't be able to change the x simultaneously");
x--;
}
}
int main() {
constexpr int N = 16;
std::vector<std::thread> threads;
for (int i = 0; i < N; ++i) threads.push_back(std::thread(test_lock));
for (auto& thread : threads) {
thread.join();
}
return 0;
}

View File

@ -0,0 +1,46 @@
#include <thread>
#include <vector>
#include "transactions/engine.hpp"
#include "utils/assert.hpp"
int main() {
// (try to) test correctness of the transaction life cycle
constexpr int THREADS = 16;
constexpr int TRANSACTIONS = 10;
tx::Engine engine;
std::vector<uint64_t> sums;
sums.resize(THREADS);
auto f = [&engine, &sums](int idx, int n) {
uint64_t sum = 0;
for (int i = 0; i < n; ++i) {
auto& t = engine.begin();
sum += t.id;
engine.commit(t);
}
sums[idx] = sum;
};
std::vector<std::thread> threads;
for (int i = 0; i < THREADS; ++i)
threads.push_back(std::thread(f, i, TRANSACTIONS));
for (auto& thread : threads) thread.join();
uint64_t sum_computed = 0;
for (int i = 0; i < THREADS; ++i) sum_computed += sums[i];
uint64_t sum_actual = 0;
for (uint64_t i = 2; i <= THREADS * TRANSACTIONS + 1; ++i) sum_actual += i;
// the range is strange because the first transaction gets transaction id 2
std::cout << sum_computed << " " << sum_actual << std::endl;
permanent_assert(sum_computed == sum_actual, "sums have to be the same");
}

60
tests/manual/binomial.cpp Normal file
View File

@ -0,0 +1,60 @@
/* Plots the distribution histogram of the fast_binomial algorithm
* (spoiler alert: it's pleasingly (1/2)^N all the way :D)
*/
#include <array>
#include <atomic>
#include <iomanip>
#include <iostream>
#include <thread>
#include <sys/ioctl.h>
#include <unistd.h>
#include "utils/random/fast_binomial.hpp"
static constexpr unsigned B = 24;
static thread_local FastBinomial<B> rnd;
static constexpr unsigned M = 4;
static constexpr size_t N = 1ULL << 34;
static constexpr size_t per_thread_iters = N / M;
std::array<std::atomic<uint64_t>, B> buckets;
void generate() {
for (size_t i = 0; i < per_thread_iters; ++i) buckets[rnd() - 1].fetch_add(1);
}
int main(void) {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
auto bar_len = w.ws_col - 20;
std::array<std::thread, M> threads;
for (auto& bucket : buckets) bucket.store(0);
for (auto& t : threads) t = std::thread([]() { generate(); });
for (auto& t : threads) t.join();
auto max = std::accumulate(
buckets.begin(), buckets.end(), (uint64_t)0,
[](auto& acc, auto& x) { return std::max(acc, x.load()); });
std::cout << std::fixed;
for (size_t i = 0; i < buckets.size(); ++i) {
auto x = buckets[i].load();
auto rel = bar_len * x / max;
std::cout << std::setw(2) << i + 1 << " ";
for (size_t i = 0; i < rel; ++i) std::cout << "=";
std::cout << " " << 100 * (double)x / N << "%" << std::endl;
}
return 0;
}

65
tests/manual/endinan.cpp Normal file
View File

@ -0,0 +1,65 @@
#include <cstdint>
#include <iostream>
#include <byteswap.h>
char b[8] = {1, 2, 3, 4, 0, 0, 0, 1};
int64_t safe_int64(const char* b) {
return int64_t(b[0]) << 56 | int64_t(b[1]) << 48 | int64_t(b[2]) << 40 |
int64_t(b[3]) << 32 | int64_t(b[4]) << 24 | int64_t(b[5]) << 16 |
int64_t(b[6]) << 8 | int64_t(b[7]);
}
int64_t unsafe_int64(const char* b) {
auto i = reinterpret_cast<const int64_t*>(b);
return __bswap_64(*i);
}
int32_t safe_int32(const char* b) {
return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
}
int32_t unsafe_int32(const char* b) {
auto i = reinterpret_cast<const int32_t*>(b);
return __bswap_32(*i);
}
[[clang::optnone]] void test(uint64_t n) {
for (uint64_t i = 0; i < n; ++i) unsafe_int64(b);
}
uint8_t f[8] = {0x3F, 0xF1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A};
double ff = 1.1;
double get_double(const uint8_t* b) {
auto v = __bswap_64(*reinterpret_cast<const uint64_t*>(b));
return *reinterpret_cast<const double*>(&v);
}
void print_hex(const char* buf, size_t n) {
for (size_t i = 0; i < n; ++i) printf("%02X ", (unsigned char)buf[i]);
}
void print_hex(const uint8_t* buf, size_t n) { print_hex((const char*)buf, n); }
int main(void) {
auto dd = get_double(f);
print_hex(f, 8);
std::cout << std::endl;
print_hex((const uint8_t*)(&ff), 8);
std::cout << std::endl;
print_hex((const uint8_t*)(&dd), 8);
std::cout << "dd: " << dd << std::endl;
std::cout << "Safe: " << safe_int64(b) << std::endl;
std::cout << unsafe_int64(b) << std::endl;
test(1000000ull);
return 0;
}

60
tests/manual/xorshift.cpp Normal file
View File

@ -0,0 +1,60 @@
/* Plots the distribution histogram of the xorshift algorithm
* (spoiler alert: it's pleasingly uniform all the way :D)
*/
#include <array>
#include <atomic>
#include <cassert>
#include <iostream>
#include <thread>
#include <sys/ioctl.h>
#include <unistd.h>
#include "utils/random/xorshift128plus.hpp"
static thread_local Xorshift128plus rnd;
static constexpr unsigned B = 1 << 10;
static constexpr uint64_t K = (uint64_t)(-1) / B;
static constexpr unsigned M = 4;
static constexpr size_t N = 1ULL << 34;
static constexpr size_t per_thread_iters = N / M;
std::array<std::atomic<unsigned>, B> buckets;
void generate() {
for (size_t i = 0; i < per_thread_iters; ++i) buckets[rnd() / K].fetch_add(1);
}
int main(void) {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
auto bar_len = w.ws_col - 20;
std::array<std::thread, M> threads;
for (auto& bucket : buckets) bucket.store(0);
for (auto& t : threads) t = std::thread([]() { generate(); });
for (auto& t : threads) t.join();
auto max = std::accumulate(
buckets.begin(), buckets.end(), 0u,
[](auto& acc, auto& x) { return std::max(acc, x.load()); });
assert(max != 0u);
std::cout << std::fixed;
for (auto& bucket : buckets) {
auto x = bucket.load();
auto rel = bar_len * x / max;
for (size_t i = 0; i < rel; ++i) std::cout << "=";
std::cout << " " << 100.0 * x / N * B - 100 << "%" << std::endl;
}
return 0;
}

View File

@ -1,2 +0,0 @@
All unit test should be gtest because in that case the test infrastructure can
then visualize the results. (JUnit xml output)

View File

@ -1,8 +1,8 @@
#include "catch.hpp"
#include "gtest/gtest.h"
#include "utils/memory/allocator.hpp"
TEST_CASE("A block of integers can be allocated") {
TEST(AllocatorTest, ABlockOfIntegersCanBeAllocated) {
constexpr int N = 100;
fast_allocator<int> a;
@ -12,13 +12,13 @@ TEST_CASE("A block of integers can be allocated") {
for (int i = 0; i < N; ++i) xs[i] = i;
// can we read them back?
for (int i = 0; i < N; ++i) REQUIRE(xs[i] == i);
for (int i = 0; i < N; ++i) ASSERT_EQ(xs[i], i);
// we should be able to free the memory
a.deallocate(xs, N);
}
TEST_CASE("Allocator should work with structures") {
TEST(AllocatorTest, AllocatorShouldWorkWithStructures) {
struct TestObject {
TestObject(int a, int b, int c, int d) : a(a), b(b), c(c), d(d) {}
@ -27,19 +27,21 @@ TEST_CASE("Allocator should work with structures") {
fast_allocator<TestObject> a;
SECTION("Allocate a single object") {
// allocate a single object
{
auto* test = a.allocate(1);
*test = TestObject(1, 2, 3, 4);
REQUIRE(test->a == 1);
REQUIRE(test->b == 2);
REQUIRE(test->c == 3);
REQUIRE(test->d == 4);
ASSERT_EQ(test->a, 1);
ASSERT_EQ(test->b, 2);
ASSERT_EQ(test->c, 3);
ASSERT_EQ(test->d, 4);
a.deallocate(test, 1);
}
SECTION("Allocate a block of structures") {
// Allocate a block of structures
{
constexpr int N = 8;
auto* tests = a.allocate(N);
@ -47,12 +49,17 @@ TEST_CASE("Allocator should work with structures") {
for (int i = 0; i < N; ++i) tests[i] = TestObject(i, i, i, i);
for (int i = 0; i < N; ++i) {
REQUIRE(tests[i].a == i);
REQUIRE(tests[i].b == i);
REQUIRE(tests[i].c == i);
REQUIRE(tests[i].d == i);
ASSERT_EQ(tests[i].a, i);
ASSERT_EQ(tests[i].b, i);
ASSERT_EQ(tests[i].c, i);
ASSERT_EQ(tests[i].d, i);
}
a.deallocate(tests, N);
}
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -9,16 +9,15 @@
#include "logging/streams/stdout.hpp"
#include "utils/assert.hpp"
using skiplist_t = ConcurrentMap<int, int>;
using concurrent_map_t = ConcurrentMap<int, int>;
void print_skiplist(const skiplist_t::Accessor &skiplist) {
logging::info("Skiplist now has: ");
for (auto &kv : skiplist) logging::info(" ({}, {})", kv.first, kv.second);
void print_skiplist(const concurrent_map_t::Accessor &map) {
logging::info("Map now has: ");
for (auto &kv : map) logging::info(" ({}, {})", kv.first, kv.second);
}
TEST(ConcurrentMapSkiplist, Mix) {
skiplist_t skiplist;
concurrent_map_t skiplist;
auto accessor = skiplist.access();
// insert 10

28
tests/unit/exceptions.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "gtest/gtest.h"
#include "utils/exceptions/basic_exception.hpp"
#include "utils/exceptions/stacktrace_exception.hpp"
void i_will_throw() { throw BasicException("this is not ok"); }
void bar() { i_will_throw(); }
void foo() { bar(); }
void i_will_throw_stacktrace_exception() {
throw StacktraceException("this is not {}", "ok!");
}
void bar_stacktrace() { i_will_throw_stacktrace_exception(); }
void foo_stacktrace() { bar_stacktrace(); }
TEST(ExceptionsTest, ThrowBasicAndStackExceptions) {
ASSERT_THROW(foo(), BasicException);
ASSERT_THROW(foo_stacktrace(), StacktraceException);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

33
tests/unit/id.cpp Normal file
View File

@ -0,0 +1,33 @@
#include <iostream>
#include "mvcc/id.hpp"
using std::cout;
using std::endl;
int main() {
Id id0(0);
Id id1(1);
Id id2(1);
Id id3(id2);
Id id4 = id3;
Id id5(5);
cout << id5 << " " << id0 << endl;
if (id0 < id5) cout << "id0 < id5" << endl;
if (id1 == id2) cout << "are equal" << endl;
if (id3 == id4) cout << "id3 == id4" << endl;
if (id5 > id0) cout << "id5 > id0" << endl;
if (id5 != id3) cout << "id5 != id3" << endl;
if (id1 >= id2) cout << "id1 >= id2" << endl;
if (id3 <= id4) cout << "id3 <= id4" << endl;
return 0;
}

25
tests/unit/log.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "logging/logger.hpp"
#include "logging/logs/async_log.hpp"
#include "logging/logs/sync_log.hpp"
#include "logging/streams/stdout.hpp"
int main(void) {
// Log::uptr log = std::make_unique<SyncLog>();
Log::uptr log = std::make_unique<AsyncLog>();
log->pipe(std::make_unique<Stdout>());
auto logger = log->logger("main");
logger.info("This is very {}!", "awesome");
logger.warn("This is very {}!", "awesome");
logger.error("This is very {}!", "awesome");
logger.trace("This is very {}!", "awesome");
logger.debug("This is very {}!", "awesome");
using namespace std::chrono;
/* std::this_thread::sleep_for(1s); */
return 0;
}

View File

@ -17,7 +17,7 @@
#include "data_structures/concurrent/skiplist.hpp"
#include "logging/default.cpp"
#include "utils/random/generator.h"
#include "utils/random/random_generator.hpp"
using utils::random::NumberGenerator;
using IntegerGenerator = NumberGenerator<std::uniform_int_distribution<int>,

View File

@ -1,54 +0,0 @@
#include <iostream>
#include "data_structures/concurrent/concurrent_set.hpp"
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
using std::cout;
using std::endl;
void print_skiplist(const ConcurrentSet<int>::Accessor &skiplist) {
cout << "---- skiplist set now has: ";
for (auto &item : skiplist) cout << item << ", ";
cout << "----" << endl;
}
int main(void) {
logging::init_async();
logging::log->pipe(std::make_unique<Stdout>());
ConcurrentSet<int> set;
auto accessor = set.access();
cout << std::boolalpha;
cout << "added non-existing 1? (true) " << accessor.insert(1).second << endl;
cout << "added already existing 1? (false) " << accessor.insert(1).second
<< endl;
accessor.insert(2);
print_skiplist(accessor);
cout << "item 3 doesn't exist? (true) "
<< (accessor.find(3) == accessor.end()) << endl;
cout << "item 3 exists? (false) " << accessor.contains(3) << endl;
cout << "item 2 exists? (true) " << (accessor.find(2) != accessor.end())
<< endl;
cout << "at item 2 is? 2 " << *accessor.find(2) << endl;
cout << "removed existing 1? (true) " << accessor.remove(1) << endl;
cout << "removed non-existing 3? (false) " << accessor.remove(3) << endl;
accessor.insert(1);
accessor.insert(4);
print_skiplist(accessor);
return 0;
}

22
tests/unit/timestamp.cpp Normal file
View File

@ -0,0 +1,22 @@
#include <chrono>
#include <iostream>
#include <thread>
#include "utils/datetime/timestamp.hpp"
int main(void) {
auto timestamp = Timestamp::now();
std::cout << timestamp << std::endl;
std::cout << Timestamp::now() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
std::cout << Timestamp::now().to_iso8601() << std::endl;
std::cout << std::boolalpha;
std::cout << (timestamp == Timestamp::now()) << std::endl;
return 0;
}