revisionstore: use new EdenAPI crate

Summary: Update the `revisionstore` and `backingstore` crates to use the new EdenAPI crate.

Reviewed By: quark-zju

Differential Revision: D22378330

fbshipit-source-id: 989f34827b744ff4b4ac0aa10d004f03dbe9058f
This commit is contained in:
Arun Kulshreshtha 2020-07-09 13:06:18 -07:00 committed by Facebook GitHub Bot
parent 41e68f46d3
commit d1d3224ba1
10 changed files with 91 additions and 68 deletions

View File

@ -6,7 +6,7 @@ edition = "2018"
[dependencies]
configparser = { path = "../configparser" }
edenapi-old = { path = "../edenapi/old" }
edenapi = { path = "../edenapi" }
log = "0.4"
manifest = { path = "../manifest" }
manifest-tree = { path = "../manifest-tree" }

View File

@ -8,10 +8,10 @@
use crate::remotestore::FakeRemoteStore;
use crate::treecontentstore::TreeContentStore;
use crate::utils::key_from_path_node_slice;
use anyhow::Result;
use anyhow::{Context, Result};
use configparser::config::ConfigSet;
use configparser::hg::ConfigSetHgExt;
use edenapi_old::{EdenApi, EdenApiCurlClient};
use edenapi::{Builder as EdenApiBuilder, EdenApi, RepoName};
use log::warn;
use manifest::{List, Manifest};
use manifest_tree::TreeManifest;
@ -36,6 +36,11 @@ impl BackingStore {
config.load_user();
config.load_hgrc(hg.join("hgrc"), "repository");
let repo_name: RepoName = config
.get_opt("remotefilelog", "reponame")
.context("Invalid repo name")?
.context("No repo name specified in remotefilelog.reponame")?;
let store_path = hg.join("store");
let mut blobstore = ContentStoreBuilder::new(&config).local_path(&store_path);
let treestore = ContentStoreBuilder::new(&config)
@ -51,11 +56,13 @@ impl BackingStore {
}
let (blobstore, treestore) = if use_edenapi {
let edenapi_config = edenapi_old::Config::from_hg_config(&config)?;
let edenapi = EdenApiCurlClient::new(edenapi_config)?;
let edenapi = EdenApiBuilder::from_config(&config)?.build()?;
let edenapi: Arc<dyn EdenApi> = Arc::new(edenapi);
let fileremotestore = Arc::new(EdenApiHgIdRemoteStore::filestore(edenapi.clone()));
let treeremotestore = Arc::new(EdenApiHgIdRemoteStore::treestore(edenapi));
let fileremotestore = Arc::new(EdenApiHgIdRemoteStore::filestore(
repo_name.clone(),
edenapi.clone(),
));
let treeremotestore = Arc::new(EdenApiHgIdRemoteStore::treestore(repo_name, edenapi));
(
blobstore.remotestore(fileremotestore).build()?,

View File

@ -18,7 +18,7 @@ use crate::response::{Fetch, ResponseMeta};
pub type ProgressCallback = Box<dyn FnMut(Progress) + Send + 'static>;
#[async_trait]
pub trait EdenApi: Send + 'static {
pub trait EdenApi: Send + Sync + 'static {
async fn health(&self) -> Result<ResponseMeta, EdenApiError>;
async fn files(

View File

@ -24,4 +24,4 @@ pub use crate::name::RepoName;
pub use crate::response::{BlockingFetch, Entries, Fetch, ResponseMeta};
// Re-export for convenience.
pub use http_client::Progress;
pub use http_client::{Progress, Stats};

View File

@ -8,8 +8,11 @@
use std::fmt;
use std::str::FromStr;
use anyhow::Error;
use ascii::{AsAsciiStr, AsciiString};
use configparser::hg::FromConfigValue;
use crate::errors::EdenApiError;
/// A valididated repo name.
@ -49,6 +52,12 @@ impl fmt::Display for RepoName {
}
}
impl FromConfigValue for RepoName {
fn try_from_str(s: &str) -> Result<Self, Error> {
Ok(s.parse()?)
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -76,7 +76,7 @@ impl<T> BlockingFetch<T> {
}
/// Metadata extracted from the headers of an individual HTTP response.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct ResponseMeta {
pub version: Version,
pub status: StatusCode,

View File

@ -7,7 +7,7 @@
use std::{fmt, time::Duration};
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct Stats {
pub downloaded: usize,
pub uploaded: usize,

View File

@ -11,10 +11,11 @@ for-tests = []
[dependencies]
anyhow = "1.0.20"
async-trait = "0.1"
bytes = { version = "0.5", features = ["serde"] }
byteorder = "1.2.7"
configparser = { path = "../configparser" }
edenapi-old = { path = "../edenapi/old" }
edenapi = { path = "../edenapi" }
edenapi_types = { path = "../edenapi/types" }
futures = "0.3"
hex = "0.4"

View File

@ -9,7 +9,7 @@ use std::sync::Arc;
use anyhow::Result;
use edenapi_old::EdenApi;
use edenapi::{EdenApi, EdenApiBlocking, RepoName};
use types::Key;
use crate::{
@ -30,20 +30,23 @@ enum EdenApiHgIdRemoteStoreKind {
/// the `HgIdDataStore` methods will always fetch data from the network.
pub struct EdenApiHgIdRemoteStore {
edenapi: Arc<dyn EdenApi>,
repo: RepoName,
kind: EdenApiHgIdRemoteStoreKind,
}
impl EdenApiHgIdRemoteStore {
pub fn filestore(edenapi: Arc<dyn EdenApi>) -> Self {
pub fn filestore(repo: RepoName, edenapi: Arc<dyn EdenApi>) -> Self {
Self {
edenapi,
repo,
kind: EdenApiHgIdRemoteStoreKind::File,
}
}
pub fn treestore(edenapi: Arc<dyn EdenApi>) -> Self {
pub fn treestore(repo: RepoName, edenapi: Arc<dyn EdenApi>) -> Self {
Self {
edenapi,
repo,
kind: EdenApiHgIdRemoteStoreKind::Tree,
}
}
@ -76,6 +79,7 @@ struct EdenApiRemoteDataStore {
impl RemoteDataStore for EdenApiRemoteDataStore {
fn prefetch(&self, keys: &[StoreKey]) -> Result<()> {
let edenapi = &self.edenapi;
let repo = edenapi.repo.clone();
let keys = keys
.iter()
@ -84,13 +88,13 @@ impl RemoteDataStore for EdenApiRemoteDataStore {
StoreKey::Content(_, _) => None,
})
.collect::<Vec<_>>();
let (entries, _) = match edenapi.kind {
EdenApiHgIdRemoteStoreKind::File => edenapi.edenapi.get_files(keys, None)?,
EdenApiHgIdRemoteStoreKind::Tree => edenapi.edenapi.get_trees(keys, None)?,
let response = match edenapi.kind {
EdenApiHgIdRemoteStoreKind::File => edenapi.edenapi.files_blocking(repo, keys, None)?,
EdenApiHgIdRemoteStoreKind::Tree => edenapi.edenapi.trees_blocking(repo, keys, None)?,
};
for entry in entries {
let key = entry.0.clone();
let data = entry.1;
for entry in response.entries {
let key = entry.key().clone();
let data = entry.data()?;
let metadata = Metadata {
size: Some(data.len() as u64),
flags: None,
@ -157,7 +161,10 @@ mod tests {
let mut map = HashMap::new();
map.insert(k.clone(), d.data.clone());
let edenapi = Arc::new(EdenApiHgIdRemoteStore::filestore(fake_edenapi(map)));
let edenapi = Arc::new(EdenApiHgIdRemoteStore::filestore(
"repo".parse()?,
fake_edenapi(map),
));
let remotestore = edenapi.datastore(store.clone());
@ -176,7 +183,10 @@ mod tests {
let store = Arc::new(IndexedLogHgIdDataStore::new(&tmp)?);
let map = HashMap::new();
let edenapi = Arc::new(EdenApiHgIdRemoteStore::filestore(fake_edenapi(map)));
let edenapi = Arc::new(EdenApiHgIdRemoteStore::filestore(
"repo".parse()?,
fake_edenapi(map),
));
let remotestore = edenapi.datastore(store);

View File

@ -5,15 +5,17 @@
* GNU General Public License version 2.
*/
use std::{collections::HashMap, path::Path, sync::Arc, time::Duration};
use std::{collections::HashMap, path::Path, sync::Arc};
use anyhow::{Error, Result};
use anyhow::{Context, Error, Result};
use async_trait::async_trait;
use bytes::Bytes;
use futures::prelude::*;
use configparser::config::ConfigSet;
use edenapi_old::{ApiResult, DownloadStats, EdenApi, ProgressFn};
use edenapi_types::HistoryEntry;
use types::{HgId, Key, NodeInfo, RepoPathBuf};
use edenapi::{EdenApi, EdenApiError, Fetch, ProgressCallback, RepoName, ResponseMeta, Stats};
use edenapi_types::{DataEntry, HistoryEntry};
use types::{HgId, Key, NodeInfo, Parents, RepoPathBuf};
use crate::{
datastore::{Delta, HgIdDataStore, HgIdMutableDeltaStore, Metadata, RemoteDataStore},
@ -182,71 +184,65 @@ impl FakeEdenApi {
pub fn new(map: HashMap<Key, Bytes>) -> FakeEdenApi {
Self { map }
}
fn fake_downloadstats(&self) -> DownloadStats {
DownloadStats {
downloaded: 0,
uploaded: 0,
requests: 0,
time: Duration::from_secs(0),
latency: Duration::from_secs(0),
}
}
}
#[async_trait]
impl EdenApi for FakeEdenApi {
fn health_check(&self) -> ApiResult<()> {
Ok(())
async fn health(&self) -> Result<ResponseMeta, EdenApiError> {
Ok(ResponseMeta::default())
}
fn hostname(&self) -> ApiResult<String> {
Ok("test".to_string())
}
fn get_files(
async fn files(
&self,
_repo: RepoName,
keys: Vec<Key>,
_progress: Option<ProgressFn>,
) -> ApiResult<(Box<dyn Iterator<Item = (Key, Bytes)>>, DownloadStats)> {
let stats = self.fake_downloadstats();
let iter = keys
_progress: Option<ProgressCallback>,
) -> Result<Fetch<DataEntry>, EdenApiError> {
let entries = keys
.into_iter()
.map(|key| {
self.map
.get(&key)
.ok_or_else(|| "Not found".into())
.map(|data| (key, data.clone()))
let data = self.map.get(&key).context("Not found")?.clone();
let parents = Parents::default();
Ok(DataEntry::new(key, data, parents))
})
.collect::<ApiResult<Vec<(Key, Bytes)>>>()?;
Ok((Box::new(iter.into_iter()), stats))
.collect::<Vec<_>>();
Ok(Fetch {
meta: vec![ResponseMeta::default()],
entries: Box::pin(stream::iter(entries)),
stats: Box::pin(future::ok(Stats::default())),
})
}
fn get_history(
async fn history(
&self,
_repo: RepoName,
_keys: Vec<Key>,
_max_depth: Option<u32>,
_progress: Option<ProgressFn>,
) -> ApiResult<(Box<dyn Iterator<Item = HistoryEntry>>, DownloadStats)> {
unreachable!();
_length: Option<u32>,
_progress: Option<ProgressCallback>,
) -> Result<Fetch<HistoryEntry>, EdenApiError> {
unimplemented!()
}
fn get_trees(
async fn trees(
&self,
_repo: RepoName,
_keys: Vec<Key>,
_progress: Option<ProgressFn>,
) -> ApiResult<(Box<dyn Iterator<Item = (Key, Bytes)>>, DownloadStats)> {
unreachable!();
_progress: Option<ProgressCallback>,
) -> Result<Fetch<DataEntry>, EdenApiError> {
unimplemented!()
}
fn prefetch_trees(
async fn complete_trees(
&self,
_repo: RepoName,
_rootdir: RepoPathBuf,
_mfnodes: Vec<HgId>,
_basemfnodes: Vec<HgId>,
_depth: Option<usize>,
_progress: Option<ProgressFn>,
) -> ApiResult<(Box<dyn Iterator<Item = (Key, Bytes)>>, DownloadStats)> {
unreachable!();
_progress: Option<ProgressCallback>,
) -> Result<Fetch<DataEntry>, EdenApiError> {
unimplemented!()
}
}