revisionstore: remove c_api

Summary: It was once used by EdenFS, but is now dead code, no need to keep it around.

Reviewed By: singhsrb

Differential Revision: D22784582

fbshipit-source-id: d01cf5a99a010530166cabb0de55a5ea3c51c9c7
This commit is contained in:
Xavier Deguillard 2020-07-27 23:22:53 -07:00 committed by Facebook GitHub Bot
parent 537f4445f8
commit 5af4e00fb4
6 changed files with 0 additions and 522 deletions

View File

@ -7,4 +7,3 @@ add_subdirectory(backingstore)
add_subdirectory(cdatapack)
add_subdirectory(clib)
add_subdirectory(configparser)
add_subdirectory(revisionstore)

View File

@ -1,44 +0,0 @@
rust_static_library(rust_revisionstore CRATE revisionstore)
install_rust_static_library(
rust_revisionstore
EXPORT mercurial
INSTALL_DIR lib
)
add_library(revisionstore RevisionStore.cpp)
set_target_properties(
revisionstore
PROPERTIES
PUBLIC_HEADER
RevisionStore.h
)
target_include_directories(revisionstore PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(
revisionstore
PRIVATE
rust_revisionstore
Folly::folly
)
# curl used in the Rust crate has its own copy of curl compiled and it uses
# Crypt32 and Secur32 on Windows. We need to declare the link dependencies here
# to avoid linker errors.
if (WIN32)
target_link_libraries(
revisionstore
PRIVATE
Crypt32
Secur32
Ncrypt
)
endif()
install(
TARGETS revisionstore
EXPORT mercurial
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION "include/eden/scm/lib/revisionstore/"
)

View File

@ -1,103 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#include "RevisionStore.h"
using namespace facebook::eden;
// The following functions are exported from this rust library:
// @dep=//eden/scm/lib/revisionstore:revisionstore
namespace {
struct ByteData {
const uint8_t* ptr;
size_t len;
};
struct GetData {
RevisionStoreByteVecStruct* value;
RevisionStoreStringStruct* error;
bool is_key_error;
};
} // namespace
extern "C" DataPackUnionStruct* revisionstore_datapackunion_new(
const char* const paths[],
size_t num_paths) noexcept;
extern "C" void revisionstore_datapackunion_free(
DataPackUnionStruct* store) noexcept;
extern "C" GetData revisionstore_datapackunion_get(
DataPackUnionStruct* store,
const uint8_t* name,
size_t name_len,
const uint8_t* hgid,
size_t hgid_len) noexcept;
extern "C" void revisionstore_string_free(
RevisionStoreStringStruct* str) noexcept;
extern "C" ByteData revisionstore_string_data(
RevisionStoreStringStruct* str) noexcept;
extern "C" void revisionstore_bytevec_free(
RevisionStoreByteVecStruct* bytes) noexcept;
extern "C" ByteData revisionstore_bytevec_data(
RevisionStoreByteVecStruct* bytes) noexcept;
namespace facebook {
namespace eden {
void DataPackUnion::Deleter::operator()(DataPackUnionStruct* ptr) const
noexcept {
revisionstore_datapackunion_free(ptr);
}
DataPackUnion::DataPackUnion(const char* const paths[], size_t num_paths)
: store_(revisionstore_datapackunion_new(paths, num_paths)) {}
folly::Optional<RevisionStoreByteVec> DataPackUnion::get(
folly::ByteRange name,
folly::ByteRange hgid) {
// This implementation is strongly coupled to that of
// revisionstore_datapackunion_get in eden/scm/lib/revisionstore/src/c_api.rs
auto got = revisionstore_datapackunion_get(
store_.get(), name.data(), name.size(), hgid.data(), hgid.size());
if (got.value) {
return RevisionStoreByteVec(got.value);
}
if (got.is_key_error) {
return folly::none;
}
RevisionStoreString error(got.error);
throw DataPackUnionGetError(error.stringPiece().str());
}
RevisionStoreString::RevisionStoreString(RevisionStoreStringStruct* ptr)
: ptr_(ptr) {}
void RevisionStoreString::Deleter::operator()(
RevisionStoreStringStruct* ptr) const noexcept {
revisionstore_string_free(ptr);
}
folly::StringPiece RevisionStoreString::stringPiece() const noexcept {
auto data = revisionstore_string_data(ptr_.get());
return folly::StringPiece(reinterpret_cast<const char*>(data.ptr), data.len);
}
RevisionStoreByteVec::RevisionStoreByteVec(RevisionStoreByteVecStruct* ptr)
: ptr_(ptr) {}
void RevisionStoreByteVec::Deleter::operator()(
RevisionStoreByteVecStruct* ptr) const noexcept {
revisionstore_bytevec_free(ptr);
}
folly::ByteRange RevisionStoreByteVec::bytes() const noexcept {
auto data = revisionstore_bytevec_data(ptr_.get());
return folly::ByteRange(data.ptr, data.len);
}
} // namespace eden
} // namespace facebook

View File

@ -1,92 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved
#pragma once
/** This module makes available to C++ some of the Rust revisionstore
* functionality.
*/
#include <folly/Optional.h>
#include <folly/Range.h>
#include <cstddef>
#include <cstdint>
namespace facebook {
namespace eden {
struct DataPackUnionStruct;
struct RevisionStoreStringStruct;
struct RevisionStoreByteVecStruct;
/** Represents a Rust String value returned from the revisionstore crate.
* The string bytes are guaranteed to be value UTF-8.
* The string value is used to represent a human readable error string.
*/
class RevisionStoreString {
public:
explicit RevisionStoreString(RevisionStoreStringStruct* ptr);
// Explicitly reference the string bytes as a StringPiece
folly::StringPiece stringPiece() const noexcept;
operator folly::StringPiece() const noexcept {
return stringPiece();
}
private:
struct Deleter {
void operator()(RevisionStoreStringStruct*) const noexcept;
};
std::unique_ptr<RevisionStoreStringStruct, Deleter> ptr_;
};
/** Represents a Rust Vec<u8> value returned from the revisionstore crate.
*/
class RevisionStoreByteVec {
public:
explicit RevisionStoreByteVec(RevisionStoreByteVecStruct* ptr);
// Explicitly reference the bytes as a ByteRange
folly::ByteRange bytes() const noexcept;
// Implicit conversion to ByteRange
operator folly::ByteRange() const noexcept {
return bytes();
}
private:
struct Deleter {
void operator()(RevisionStoreByteVecStruct*) const noexcept;
};
std::unique_ptr<RevisionStoreByteVecStruct, Deleter> ptr_;
};
class DataPackUnionGetError : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
/** DataPackUnion is configured with a list of directory paths that
* contain some number of datapack files.
* DataPackUnion can be queried to see if it contains a given key,
* and fetch the corresponding de-delta'd value
*/
class DataPackUnion {
public:
DataPackUnion(const char* const paths[], size_t num_paths);
// Look up the name/hgid pair. If found, de-delta and return the data as a
// RevisionStoreByteVec. If not found, return folly::none. If an error
// occurs, throw a DataPackUnionGetError exception. This method is not thread
// safe.
folly::Optional<RevisionStoreByteVec> get(
folly::ByteRange name,
folly::ByteRange hgid);
private:
struct Deleter {
void operator()(DataPackUnionStruct*) const noexcept;
};
std::unique_ptr<DataPackUnionStruct, Deleter> store_;
};
} // namespace eden
} // namespace facebook

View File

@ -1,281 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
//! This module exports some concrete implementations of the revisionstore
//! API for use from C++ code. The exports in this file match up to the C++
//! header file RevisionStore.h in the top level of this crate.
use std::{
collections::HashMap,
ffi::CStr,
fs,
os::raw::c_char,
path::{Path, PathBuf},
ptr, slice,
sync::Arc,
};
use anyhow::Result;
use types::{HgId, Key, RepoPath};
use crate::datapack::DataPack;
use crate::datastore::{HgIdDataStore, StoreResult};
use crate::types::StoreKey;
use crate::uniondatastore::UnionHgIdDataStore;
pub struct DataPackUnion {
paths: Vec<PathBuf>,
packs: HashMap<PathBuf, Arc<DataPack>>,
store: UnionHgIdDataStore<Arc<DataPack>>,
}
/// Returns true if the supplied path has a .datapack extension
fn is_datapack(path: &Path) -> bool {
if let Some(extension) = path.extension() {
extension == "datapack"
} else {
false
}
}
enum ScanResult {
NoChanges,
ChangesDetected,
}
impl DataPackUnion {
fn new(paths: Vec<PathBuf>) -> Self {
Self {
paths,
packs: HashMap::new(),
store: UnionHgIdDataStore::new(),
}
}
fn rescan_paths(&mut self) -> ScanResult {
// first step is to release any unlinked pack files
let num_before = self.packs.len();
self.packs.retain(|path, _| path.exists());
let mut num_changed = num_before - self.packs.len();
// next step is to discover any new files
for path in &self.paths {
match Self::scan_dir(&mut self.packs, path) {
Err(e) => {
eprintln!(
"Error while scanning {} for datapack files: {}",
path.display(),
e
);
}
Ok(num) => num_changed += num,
}
}
if num_changed == 0 {
return ScanResult::NoChanges;
}
// Re-create the union portion; while we can add elements, there isn't
// a way to remove them, so we build a new one and populate it.
// The UnionHgIdDataStore is just a Vec of Arc's to our packs, so this is
// relatively cheap.
self.store = UnionHgIdDataStore::new();
for pack in self.packs.values() {
self.store.add(pack.clone());
}
ScanResult::ChangesDetected
}
fn scan_dir(packs: &mut HashMap<PathBuf, Arc<DataPack>>, path: &Path) -> Result<usize> {
let mut num_changed = 0;
for entry in fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();
if is_datapack(&path) {
if !packs.contains_key(&path) {
let pack = Arc::new(DataPack::new(&path)?);
packs.insert(path, pack);
num_changed += 1;
}
}
}
Ok(num_changed)
}
/// Lookup Key. If the key is missing, scan for changes in the pack files and try once more.
fn get(&mut self, key: &Key) -> Result<Option<Vec<u8>>> {
match self.store.get(StoreKey::hgid(key.clone()))? {
StoreResult::Found(data) => Ok(Some(data)),
StoreResult::NotFound(key) => match self.rescan_paths() {
ScanResult::ChangesDetected => match self.store.get(key)? {
StoreResult::Found(data) => Ok(Some(data)),
StoreResult::NotFound(_) => Ok(None),
},
ScanResult::NoChanges => Ok(None),
},
}
}
}
/// Construct a new datapack store.
/// Will panic the program if the paths array or elements
/// of the paths array are null.
/// Returns an instance of DataPackUnion which must be
/// freed using revisionstore_datapackunion_free when it is
/// no longer required.
#[no_mangle]
pub extern "C" fn revisionstore_datapackunion_new(
paths: *const *const c_char,
num_paths: usize,
) -> *mut DataPackUnion {
debug_assert!(!paths.is_null());
let paths = unsafe { slice::from_raw_parts(paths, num_paths) };
let paths = paths
.iter()
.map(|&path_ptr| {
debug_assert!(
!path_ptr.is_null(),
"paths passed to revisionstore_unionstore_new must not be null"
);
let path_cstr = unsafe { CStr::from_ptr(path_ptr) };
let path_str = path_cstr.to_str().expect("Not a valid UTF-8 path");
Path::new(path_str).to_path_buf()
})
.collect();
let mut store = DataPackUnion::new(paths);
store.rescan_paths();
Box::into_raw(Box::new(store))
}
/// Free a DataPackUnion instance created via revisionstore_unionstore_new().
/// Releases all associated resources.
#[no_mangle]
pub extern "C" fn revisionstore_datapackunion_free(store: *mut DataPackUnion) {
debug_assert!(!store.is_null());
let store = unsafe { Box::from_raw(store) };
drop(store);
}
/// Construct an instance of Key from the provided ffi parameters
fn make_key(name: *const u8, name_len: usize, hgid: *const u8, hgid_len: usize) -> Result<Key> {
debug_assert!(!name.is_null());
debug_assert!(!hgid.is_null());
let path_slice = unsafe { slice::from_raw_parts(name, name_len) };
let path = RepoPath::from_utf8(path_slice)?.to_owned();
let hgid_slice = unsafe { slice::from_raw_parts(hgid, hgid_len) };
let hgid = HgId::from_slice(hgid_slice)?;
Ok(Key::new(path, hgid))
}
/// Helper function that performs the get operation, wrapped in a Result
fn datapackunion_get_impl(
store: *mut DataPackUnion,
name: *const u8,
name_len: usize,
hgid: *const u8,
hgid_len: usize,
) -> Result<Option<Vec<u8>>> {
debug_assert!(!store.is_null());
let store = unsafe { &mut *store };
let key = make_key(name, name_len, hgid, hgid_len)?;
store.get(&key)
}
#[repr(C)]
pub struct GetData {
value: *mut Vec<u8>,
error: *mut String,
is_key_error: bool,
}
/// Lookup the value corresponding to name/hgid.
/// If the key is present, de-delta and populate `GetData::value`.
/// If the requested key could not be found sets `GetData::is_key_error` to true.
/// If some other error occurred, populates `GetData::error`.
/// The caller is responsible for calling revisionstore_string_free() on
/// the `error` value if it is non-null when this function returns.
/// The caller is responsible for calling revisionstore_bytevec_free() on
/// the `value` if it is non-null when this function returns.
#[no_mangle]
pub extern "C" fn revisionstore_datapackunion_get(
store: *mut DataPackUnion,
name: *const u8,
name_len: usize,
hgid: *const u8,
hgid_len: usize,
) -> GetData {
match datapackunion_get_impl(store, name, name_len, hgid, hgid_len) {
Ok(Some(data)) => GetData {
value: Box::into_raw(Box::new(data)),
error: ptr::null_mut(),
is_key_error: false,
},
Ok(None) => GetData {
value: ptr::null_mut(),
error: ptr::null_mut(),
is_key_error: true,
},
Err(err) => GetData {
value: ptr::null_mut(),
error: Box::into_raw(Box::new(format!("{}", err))),
is_key_error: false,
},
}
}
/// Dispose of a String object, such as that returned in the `error` parameter
/// of revisionstore_datapackunion_get().
#[no_mangle]
pub extern "C" fn revisionstore_string_free(string: *mut String) {
debug_assert!(!string.is_null());
let string = unsafe { Box::from_raw(string) };
drop(string);
}
/// Returns the pointer to the start of the string data
#[no_mangle]
pub extern "C" fn revisionstore_string_data(string: *mut String) -> ByteData {
debug_assert!(!string.is_null());
let string = unsafe { &*string };
ByteData {
ptr: string.as_bytes().as_ptr(),
len: string.len(),
}
}
/// Dispose of a Vec<u8> object, such as that returned in the `value` parameter
/// of revisionstore_datapackunion_get().
#[no_mangle]
pub extern "C" fn revisionstore_bytevec_free(vec: *mut Vec<u8>) {
debug_assert!(!vec.is_null());
let vec = unsafe { Box::from_raw(vec) };
drop(vec);
}
#[repr(C)]
pub struct ByteData {
ptr: *const u8,
len: usize,
}
/// Returns the pointer to the start of the byte data and its size in bytes
#[no_mangle]
pub extern "C" fn revisionstore_bytevec_data(bytes: *mut Vec<u8>) -> ByteData {
debug_assert!(!bytes.is_null());
let bytes = unsafe { &*bytes };
ByteData {
ptr: bytes.as_ptr(),
len: bytes.len(),
}
}

View File

@ -140,7 +140,6 @@ mod types;
mod unionstore;
mod util;
pub mod c_api;
pub mod datapack;
pub mod datastore;
pub mod edenapi;