#ifndef NEURALTABLE_H
|
|
#define NEURALTABLE_H
|
|
|
|
#include "erl_nif.h"
|
|
#include "neural_utils.h"
|
|
#include <string>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unordered_map>
|
|
#include <queue>
|
|
#include <atomic>
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
#include <process.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#define BUCKET_COUNT 64
|
|
#define BUCKET_MASK (BUCKET_COUNT - 1)
|
|
#define GET_BUCKET(key) key & BUCKET_MASK
|
|
#define GET_LOCK(key) key & BUCKET_MASK
|
|
#define RECLAIM_THRESHOLD 1048576
|
|
|
|
using namespace std;
|
|
|
|
class NeuralTable;
|
|
|
|
typedef unordered_map<string, NeuralTable*> table_set;
|
|
typedef unordered_map<unsigned long int, ERL_NIF_TERM> hash_table;
|
|
typedef void (NeuralTable::*BatchFunction)(ErlNifPid pid);
|
|
|
|
class NeuralTable {
|
|
public:
|
|
static ERL_NIF_TERM MakeTable(ErlNifEnv *env, ERL_NIF_TERM name, ERL_NIF_TERM keypos);
|
|
static ERL_NIF_TERM Insert(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM object);
|
|
static ERL_NIF_TERM InsertNew(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM object);
|
|
static ERL_NIF_TERM Delete(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key);
|
|
static ERL_NIF_TERM Empty(ErlNifEnv *env, ERL_NIF_TERM table);
|
|
static ERL_NIF_TERM Get(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key);
|
|
static ERL_NIF_TERM Increment(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
|
|
static ERL_NIF_TERM Shift(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
|
|
static ERL_NIF_TERM Unshift(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
|
|
static ERL_NIF_TERM Swap(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
|
|
static ERL_NIF_TERM Dump(ErlNifEnv *env, ERL_NIF_TERM table);
|
|
static ERL_NIF_TERM Drain(ErlNifEnv *env, ERL_NIF_TERM table);
|
|
static ERL_NIF_TERM GetKeyPosition(ErlNifEnv *env, ERL_NIF_TERM table);
|
|
static ERL_NIF_TERM GarbageCollect(ErlNifEnv *env, ERL_NIF_TERM table);
|
|
static ERL_NIF_TERM GarbageSize(ErlNifEnv *env, ERL_NIF_TERM table);
|
|
static NeuralTable* GetTable(ErlNifEnv *env, ERL_NIF_TERM name);
|
|
static void* DoGarbageCollection(void *table);
|
|
static void* DoBatchOperations(void *table);
|
|
static void* DoReclamation(void *table);
|
|
static void Initialize() {
|
|
table_mutex = enif_mutex_create("neural_table_maker");
|
|
}
|
|
static void Shutdown() {
|
|
running = false;
|
|
table_set::iterator it(tables.begin());
|
|
|
|
while (it != tables.end()) {
|
|
delete it->second;
|
|
tables.erase(it);
|
|
it = tables.begin();
|
|
}
|
|
|
|
enif_mutex_destroy(table_mutex);
|
|
}
|
|
|
|
void rlock(unsigned long int key) { enif_rwlock_rlock(locks[GET_LOCK(key)]); }
|
|
void runlock(unsigned long int key) { enif_rwlock_runlock(locks[GET_LOCK(key)]); }
|
|
void rwlock(unsigned long int key) { enif_rwlock_rwlock(locks[GET_LOCK(key)]); }
|
|
void rwunlock(unsigned long int key) { enif_rwlock_rwunlock(locks[GET_LOCK(key)]); }
|
|
|
|
ErlNifEnv *get_env(unsigned long int key);
|
|
bool erase(unsigned long int key, ERL_NIF_TERM &ret);
|
|
bool find(unsigned long int key, ERL_NIF_TERM &ret);
|
|
void put(unsigned long int key, ERL_NIF_TERM tuple);
|
|
void batch_dump(ErlNifPid pid);
|
|
void batch_drain(ErlNifPid pid);
|
|
void start_gc();
|
|
void stop_gc();
|
|
void start_batch();
|
|
void stop_batch();
|
|
void gc();
|
|
void reclaim(unsigned long int key, ERL_NIF_TERM reclaim);
|
|
unsigned long int garbage_size();
|
|
void add_batch_job(ErlNifPid pid, BatchFunction fun);
|
|
|
|
protected:
|
|
static table_set tables;
|
|
static atomic<bool> running;
|
|
static ErlNifMutex *table_mutex;
|
|
|
|
struct BatchJob {
|
|
ErlNifPid pid;
|
|
BatchFunction fun;
|
|
};
|
|
|
|
NeuralTable(unsigned int kp);
|
|
~NeuralTable();
|
|
|
|
unsigned int garbage_cans[BUCKET_COUNT];
|
|
hash_table hash_buckets[BUCKET_COUNT];
|
|
ErlNifEnv *env_buckets[BUCKET_COUNT];
|
|
ERL_NIF_TERM reclaimable[BUCKET_COUNT];
|
|
ErlNifRWLock *locks[BUCKET_COUNT];
|
|
ErlNifCond *gc_cond;
|
|
ErlNifMutex *gc_mutex;
|
|
ErlNifTid gc_tid;
|
|
ErlNifTid rc_tid;
|
|
ErlNifCond *batch_cond;
|
|
ErlNifMutex *batch_mutex;
|
|
queue<BatchJob> batch_jobs;
|
|
ErlNifTid batch_tid;
|
|
|
|
unsigned int key_pos;
|
|
};
|
|
|
|
#endif
|