sapling/eden/mononoke/microwave/builder/filenodes.rs
Thomas Orozco f4f96c1100 mononoke/microwave: create repository snapshots for faster cache warmup
Summary:
This introduces a new binary and library that (microwave: it makes warmup
faster..!) that can be used to accelerate cache warmup. The idea is the
microwave binary will run cache warmup and capture things that are loaded
during cache warmup, and commit those to a file.

We can then use that file when starting up a host to get a head start on cache
warmup by injecting all those entries into our local cache before actually
starting cache warmup.

Currently, this only supports filenodes, but that's already a pretty good
improvement. Changesets should be easy to add as well. Blobs might require a
bit more work.

Reviewed By: StanislavGlebik

Differential Revision: D20219905

fbshipit-source-id: 82bb13ca487f82ca53b4a68a90ac5893895a96e9
2020-03-04 04:02:18 -08:00

117 lines
2.9 KiB
Rust

/*
* 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.
*/
use anyhow::Error;
use cloned::cloned;
use context::CoreContext;
use filenodes::{FilenodeInfo, Filenodes, PreparedFilenode};
use futures::{
channel::mpsc::Sender,
compat::Future01CompatExt,
future::{FutureExt as _, TryFutureExt},
sink::SinkExt,
};
use futures_ext::{BoxFuture, FutureExt};
use mercurial_types::HgFileNodeId;
use mononoke_types::{RepoPath, RepositoryId};
use std::sync::Arc;
#[derive(Clone)]
pub struct MicrowaveFilenodes {
repo_id: RepositoryId,
recorder: Sender<PreparedFilenode>,
inner: Arc<dyn Filenodes>,
}
impl MicrowaveFilenodes {
pub fn new(
repo_id: RepositoryId,
recorder: Sender<PreparedFilenode>,
inner: Arc<dyn Filenodes>,
) -> Self {
Self {
repo_id,
recorder,
inner,
}
}
}
impl Filenodes for MicrowaveFilenodes {
fn add_filenodes(
&self,
ctx: CoreContext,
info: Vec<PreparedFilenode>,
repo_id: RepositoryId,
) -> BoxFuture<(), Error> {
self.inner.add_filenodes(ctx, info, repo_id)
}
fn add_or_replace_filenodes(
&self,
ctx: CoreContext,
info: Vec<PreparedFilenode>,
repo_id: RepositoryId,
) -> BoxFuture<(), Error> {
self.inner.add_or_replace_filenodes(ctx, info, repo_id)
}
fn get_filenode(
&self,
ctx: CoreContext,
path: &RepoPath,
filenode_id: HgFileNodeId,
repo_id: RepositoryId,
) -> BoxFuture<Option<FilenodeInfo>, Error> {
cloned!(self.inner, mut self.recorder, path);
// NOTE: Receiving any other repo_id here would be a programming error, so we block it.
// This wouldn't be on the path of any live traffic, so panicking if this assertion is
// violated is reasonable.
assert_eq!(repo_id, self.repo_id);
async move {
let info = inner
.get_filenode(ctx, &path, filenode_id, repo_id)
.compat()
.await?;
if let Some(ref info) = info {
recorder
.send(PreparedFilenode {
path,
info: info.clone(),
})
.await?;
}
Ok(info)
}
.boxed()
.compat()
.boxify()
}
fn get_all_filenodes_maybe_stale(
&self,
ctx: CoreContext,
path: &RepoPath,
repo_id: RepositoryId,
) -> BoxFuture<Vec<FilenodeInfo>, Error> {
self.inner.get_all_filenodes_maybe_stale(ctx, path, repo_id)
}
fn prime_cache(
&self,
ctx: &CoreContext,
repo_id: RepositoryId,
filenodes: &[PreparedFilenode],
) {
self.inner.prime_cache(ctx, repo_id, filenodes)
}
}