mirror of
https://github.com/facebook/sapling.git
synced 2024-12-28 15:44:27 +03:00
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:
parent
537f4445f8
commit
5af4e00fb4
@ -7,4 +7,3 @@ add_subdirectory(backingstore)
|
||||
add_subdirectory(cdatapack)
|
||||
add_subdirectory(clib)
|
||||
add_subdirectory(configparser)
|
||||
add_subdirectory(revisionstore)
|
||||
|
@ -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/"
|
||||
)
|
@ -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
|
@ -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
|
@ -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(),
|
||||
}
|
||||
}
|
@ -140,7 +140,6 @@ mod types;
|
||||
mod unionstore;
|
||||
mod util;
|
||||
|
||||
pub mod c_api;
|
||||
pub mod datapack;
|
||||
pub mod datastore;
|
||||
pub mod edenapi;
|
||||
|
Loading…
Reference in New Issue
Block a user