glean/rocksdb/ffi.cpp (229 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "common/hs/util/cpp/memory.h"
#include "common/hs/util/cpp/wrap.h"
#include "glean/rocksdb/rocksdb.h"
#include "glean/rocksdb/ffi.h"
using namespace facebook::hs;
namespace facebook {
namespace glean {
namespace rocks {
namespace c {
extern "C" {
struct SharedCache {
std::shared_ptr<facebook::glean::rocks::Cache> value;
};
const char *glean_rocksdb_new_cache(
size_t capacity,
SharedCache **cache) {
return ffi::wrap([=]{
*cache = new SharedCache{rocks::newCache(capacity)};
});
}
void glean_rocksdb_free_cache(SharedCache *cache) {
ffi::free_(cache);
}
void glean_rocksdb_container_close(Container *container) {
container->close();
}
const char *glean_rocksdb_container_write_data(
Container *container,
const void *key,
size_t key_size,
const void *value,
size_t value_size) {
return ffi::wrap([=] {
container->writeData(
{static_cast<const unsigned char *>(key), key_size},
{static_cast<const unsigned char *>(value), value_size});
});
}
const char *glean_rocksdb_container_read_data(
Container *container,
const void *key,
size_t key_size,
void **value,
size_t *value_size,
unsigned char *found) {
return ffi::wrap([=] {
*found = container->readData(
{static_cast<const unsigned char *>(key), key_size},
[=](folly::ByteRange val) {
auto bytes = ffi::clone_bytes(val);
*value_size = bytes.size();
*value = bytes.release();
}) ? 1 : 0;
});
}
const char *glean_rocksdb_container_optimize(
Container *container) {
return ffi::wrap([=] {
container->optimize();
});
}
const char *glean_rocksdb_container_backup(
Container *container,
const char *path) {
return ffi::wrap([=] {
container->backup(path);
});
}
const char *glean_rocksdb_container_open(
const char *path,
int mode,
SharedCache *cache,
Container **container) {
return ffi::wrap([=] {
folly::Optional<std::shared_ptr<rocks::Cache>> cache_ptr;
if (cache) {
cache_ptr = cache->value;
}
*container =
rocks::open(path, static_cast<rocks::Mode>(mode), std::move(cache_ptr))
.release();
});
}
void glean_rocksdb_container_free(Container *container) {
ffi::free_(container);
}
const char *glean_rocksdb_container_open_database(
Container *container,
glean_fact_id_t start,
int64_t version,
Database **database) {
return ffi::wrap([=] {
*database = std::move(*container)
.openDatabase(Id::fromThrift(start), version)
.release();
});
}
void glean_rocksdb_database_free(Database *db) {
ffi::free_(db);
}
Container *glean_rocksdb_database_container(
Database *db) {
return &(db->container());
}
Lookup *glean_rocksdb_database_lookup(Database *db) {
return db;
}
const char *glean_rocksdb_commit(
Database *db,
FactSet *facts) {
return ffi::wrap([=] {
db->commit(*facts);
});
}
const char *glean_rocksdb_add_ownership(
Database *db,
size_t count,
const void **units,
const size_t *unit_sizes,
const int64_t **ids,
const size_t *id_sizes) {
return ffi::wrap([=] {
std::vector<Database::OwnershipSet> v;
v.reserve(count);
for (size_t i = 0; i < count; ++i) {
v.push_back({
{static_cast<const unsigned char *>(units[i]), unit_sizes[i]},
{ids[i], id_sizes[i]}});
}
db->addOwnership(v);
});
}
const char *glean_rocksdb_get_ownership_unit_iterator(
Database *db,
OwnershipUnitIterator **iter) {
return ffi::wrap([=] {
*iter = db->getOwnershipUnitIterator().release();
});
}
const char *glean_rocksdb_get_unit_id(Database *db, void *unit,
size_t unit_size, uint64_t *unit_id) {
return ffi::wrap([=] {
auto res = db->getUnitId(folly::ByteRange(
reinterpret_cast<const unsigned char *>(unit), unit_size));
if (res.hasValue()) {
*unit_id = *res;
} else {
*unit_id = UINT64_MAX;
}
});
}
const char *glean_rocksdb_get_unit(Database *db, uint32_t unit_id, void **unit,
size_t *unit_size) {
return ffi::wrap([=] {
auto res = db->getUnit(unit_id);
if (res.hasValue()) {
ffi::clone_bytes(*res).release_to(unit, unit_size);
} else {
*unit = nullptr;
*unit_size = 0;
}
});
}
const char *glean_rocksdb_database_stats(
Database *db,
size_t *count,
int64_t **ids,
uint64_t **counts,
uint64_t **sizes) {
return ffi::wrap([=] {
const auto stats = db->stats();
const auto n = stats.size();
auto ids_arr = ffi::malloc_array<int64_t>(n);
auto counts_arr = ffi::malloc_array<uint64_t>(n);
auto sizes_arr = ffi::malloc_array<uint64_t>(n);
size_t i = 0;
for (const auto x : stats) {
if (x.second.count) {
ids_arr[i] = x.first.toThrift();
counts_arr[i] = x.second.count;
sizes_arr[i] = x.second.memory;
++i;
}
}
*count = i;
*ids = ids_arr.release();
*counts = counts_arr.release();
*sizes = sizes_arr.release();
});
}
const char *glean_rocksdb_restore(const char *target, const char *source) {
return ffi::wrap([=] {
facebook::glean::rocks::restore(target, source);
});
}
const char *glean_rocksdb_store_ownership(
Database *db,
ComputedOwnership *ownership) {
return ffi::wrap([=] {
db->storeOwnership(*ownership);
});
}
const char *glean_rocksdb_get_ownership(
Database *db,
Ownership **ownership) {
return ffi::wrap([=] {
*ownership = db->getOwnership().release();
});
}
const char *glean_rocksdb_add_define_ownership(
Database *db,
DefineOwnership *define) {
return ffi::wrap([=] {
db->addDefineOwnership(*define);
});
}
const char *glean_rocksdb_get_derived_fact_ownership_iterator(
Database *db,
uint64_t pid,
DerivedFactOwnershipIterator **iter) {
return ffi::wrap([=] {
*iter = db->getDerivedFactOwnershipIterator(Pid::fromWord(pid)).release();
});
}
}
}
}
}
}