2019-10-11 23:51:17 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
*
|
|
|
|
* This software may be used and distributed according to the terms of the
|
2020-02-11 13:42:43 +03:00
|
|
|
* GNU General Public License version 2.
|
2019-10-11 23:51:17 +03:00
|
|
|
*/
|
2018-07-19 13:58:24 +03:00
|
|
|
|
|
|
|
#![deny(warnings)]
|
|
|
|
|
2019-12-07 03:26:57 +03:00
|
|
|
use anyhow::{bail, format_err, Context, Error, Result};
|
2019-09-11 13:18:25 +03:00
|
|
|
use ascii::AsciiString;
|
|
|
|
use blobimport_lib;
|
2020-08-12 18:48:16 +03:00
|
|
|
use blobrepo::BlobRepo;
|
2019-10-30 20:42:39 +03:00
|
|
|
use bonsai_globalrev_mapping::SqlBonsaiGlobalrevMapping;
|
2021-03-25 16:44:16 +03:00
|
|
|
use clap::{Arg, ArgGroup};
|
2020-01-22 03:10:07 +03:00
|
|
|
use cmdlib::{
|
2021-04-16 20:26:03 +03:00
|
|
|
args::{self, MononokeClapApp, MononokeMatches, RepoRequirement},
|
2021-02-22 20:20:44 +03:00
|
|
|
helpers::block_execute,
|
2020-01-22 03:10:07 +03:00
|
|
|
};
|
2021-02-16 03:29:16 +03:00
|
|
|
use context::{CoreContext, SessionContainer};
|
2020-12-14 20:22:57 +03:00
|
|
|
use derived_data::BonsaiDerivable;
|
2020-01-27 12:09:21 +03:00
|
|
|
use derived_data_filenodes::FilenodesOnlyPublic;
|
2020-01-22 20:55:26 +03:00
|
|
|
use derived_data_utils::POSSIBLE_DERIVED_TYPES;
|
2019-12-07 03:26:57 +03:00
|
|
|
use failure_ext::SlogKVError;
|
2019-09-14 06:16:08 +03:00
|
|
|
use fbinit::FacebookInit;
|
rust: Rename futures_preview:: to futures::
Summary:
Context: https://fb.workplace.com/groups/rust.language/permalink/3338940432821215/
This codemod replaces *all* dependencies on `//common/rust/renamed:futures-preview` with `fbsource//third-party/rust:futures-preview` and their uses in Rust code from `futures_preview::` to `futures::`.
This does not introduce any collisions with `futures::` meaning 0.1 futures because D20168958 previously renamed all of those to `futures_old::` in crates that depend on *both* 0.1 and 0.3 futures.
Codemod performed by:
```
rg \
--files-with-matches \
--type-add buck:TARGETS \
--type buck \
--glob '!/experimental' \
--regexp '(_|\b)rust(_|\b)' \
| sed 's,TARGETS$,:,' \
| xargs \
-x \
buck query "labels(srcs, rdeps(%Ss, //common/rust/renamed:futures-preview, 1))" \
| xargs sed -i 's,\bfutures_preview::,futures::,'
rg \
--files-with-matches \
--type-add buck:TARGETS \
--type buck \
--glob '!/experimental' \
--regexp '(_|\b)rust(_|\b)' \
| xargs sed -i 's,//common/rust/renamed:futures-preview,fbsource//third-party/rust:futures-preview,'
```
Reviewed By: k21
Differential Revision: D20213432
fbshipit-source-id: 07ee643d350c5817cda1f43684d55084f8ac68a6
2020-03-03 21:58:44 +03:00
|
|
|
use futures::{
|
2020-02-04 17:54:31 +03:00
|
|
|
compat::Future01CompatExt,
|
2021-04-28 21:13:50 +03:00
|
|
|
future::{try_join, TryFutureExt},
|
2020-02-04 17:54:31 +03:00
|
|
|
};
|
2020-07-13 12:58:20 +03:00
|
|
|
#[cfg(fbcode_build)]
|
2020-01-07 22:14:15 +03:00
|
|
|
use mercurial_revlog::revlog::RevIdx;
|
2019-10-02 01:17:14 +03:00
|
|
|
use mercurial_types::{HgChangesetId, HgNodeHash};
|
2020-08-12 18:48:16 +03:00
|
|
|
use mononoke_types::ChangesetId;
|
|
|
|
use mutable_counters::MutableCounters;
|
|
|
|
use mutable_counters::SqlMutableCounters;
|
2020-01-07 22:14:15 +03:00
|
|
|
use slog::{error, info, warn, Logger};
|
2019-10-02 01:17:14 +03:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::fs::read;
|
|
|
|
use std::path::Path;
|
2019-08-07 18:26:52 +03:00
|
|
|
use std::str::FromStr;
|
|
|
|
use std::sync::Arc;
|
2019-11-25 16:09:58 +03:00
|
|
|
use synced_commit_mapping::SqlSyncedCommitMapping;
|
2018-07-19 13:58:24 +03:00
|
|
|
|
2020-04-22 12:47:24 +03:00
|
|
|
const ARG_DERIVED_DATA_TYPE: &str = "derived-data-type";
|
2020-11-18 17:06:39 +03:00
|
|
|
const ARG_EXCLUDE_DERIVED_DATA_TYPE: &str = "exclude-derived-data-type";
|
2020-08-06 23:07:14 +03:00
|
|
|
const ARG_FIND_ALREADY_IMPORTED_REV_ONLY: &str = "find-already-imported-rev-only";
|
2021-03-25 16:44:16 +03:00
|
|
|
const BACKUP_REPO_GROUP: &str = "backup-from-repo";
|
2020-11-10 19:44:53 +03:00
|
|
|
const BACKUP_FROM_REPO_ID: &str = "backup-from-repo-id";
|
2021-03-25 16:44:16 +03:00
|
|
|
const BACKUP_FROM_REPO_NAME: &str = "backup-from-repo-name";
|
2020-01-22 20:55:26 +03:00
|
|
|
|
2020-12-02 18:25:35 +03:00
|
|
|
fn setup_app<'a, 'b>() -> MononokeClapApp<'a, 'b> {
|
2020-12-01 22:43:16 +03:00
|
|
|
args::MononokeAppBuilder::new("revlog to blob importer")
|
2020-12-11 15:28:35 +03:00
|
|
|
.with_repo_required(RepoRequirement::ExactlyOne)
|
2019-11-25 16:09:58 +03:00
|
|
|
.with_source_repos()
|
2021-02-16 03:29:16 +03:00
|
|
|
.with_scuba_logging_args()
|
|
|
|
.with_fb303_args()
|
2019-10-28 17:57:34 +03:00
|
|
|
.build()
|
2018-07-19 13:58:24 +03:00
|
|
|
.about("Import a revlog-backed Mercurial repo into Mononoke blobstore.")
|
|
|
|
.args_from_usage(
|
|
|
|
r#"
|
2019-08-07 18:26:52 +03:00
|
|
|
<INPUT> 'input revlog repo'
|
|
|
|
--changeset [HASH] 'if provided, the only changeset to be imported'
|
|
|
|
--no-bookmark 'if provided won't update bookmarks'
|
2019-09-11 13:18:25 +03:00
|
|
|
--prefix-bookmark [PREFIX] 'if provided will update bookmarks, but prefix them with PREFIX'
|
2019-08-07 18:26:52 +03:00
|
|
|
--no-create 'if provided won't create a new repo (only meaningful for local)'
|
|
|
|
--lfs-helper [LFS_HELPER] 'if provided, path to an executable that accepts OID SIZE and returns a LFS blob to stdout'
|
|
|
|
--concurrent-changesets [LIMIT] 'if provided, max number of changesets to upload concurrently'
|
|
|
|
--concurrent-blobs [LIMIT] 'if provided, max number of blobs to process concurrently'
|
|
|
|
--concurrent-lfs-imports [LIMIT] 'if provided, max number of LFS files to import concurrently'
|
2019-10-30 20:42:39 +03:00
|
|
|
--has-globalrev 'if provided will update globalrev'
|
2020-01-07 22:14:15 +03:00
|
|
|
--manifold-next-rev-to-import [KEY] 'if provided then this manifold key will be updated with the next revision to import'
|
|
|
|
--manifold-bucket [BUCKET] 'can only be used if --manifold-next-rev-to-import is set'
|
2018-07-19 13:58:24 +03:00
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::from_usage("--skip [SKIP] 'skips commits from the beginning'")
|
|
|
|
.conflicts_with("changeset"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::from_usage(
|
|
|
|
"--commits-limit [LIMIT] 'import only LIMIT first commits from revlog repo'",
|
2019-01-14 20:29:33 +03:00
|
|
|
)
|
|
|
|
.conflicts_with("changeset"),
|
2018-07-19 13:58:24 +03:00
|
|
|
)
|
2019-10-02 01:17:14 +03:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("fix-parent-order")
|
|
|
|
.long("fix-parent-order")
|
|
|
|
.value_name("FILE")
|
|
|
|
.takes_value(true)
|
|
|
|
.required(false)
|
|
|
|
.help(
|
|
|
|
"file which fixes order or parents for commits in format 'HG_CS_ID P1_CS_ID [P2_CS_ID]'\
|
|
|
|
This is useful in case of merge commits - mercurial ignores order of parents of the merge commit \
|
|
|
|
while Mononoke doesn't ignore it. That might result in different bonsai hashes for the same \
|
|
|
|
Mercurial commit. Using --fix-parent-order allows to fix order of the parents."
|
|
|
|
)
|
|
|
|
)
|
2020-01-22 20:55:26 +03:00
|
|
|
.arg(
|
|
|
|
Arg::with_name(ARG_DERIVED_DATA_TYPE)
|
|
|
|
.long(ARG_DERIVED_DATA_TYPE)
|
|
|
|
.takes_value(true)
|
|
|
|
.multiple(true)
|
|
|
|
.required(false)
|
|
|
|
.possible_values(POSSIBLE_DERIVED_TYPES)
|
2020-11-18 17:06:39 +03:00
|
|
|
.help("Derived data type to be backfilled. Note - 'filenodes' will always be derived unless excluded")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name(ARG_EXCLUDE_DERIVED_DATA_TYPE)
|
|
|
|
.long(ARG_EXCLUDE_DERIVED_DATA_TYPE)
|
|
|
|
.takes_value(true)
|
|
|
|
.multiple(true)
|
|
|
|
.required(false)
|
|
|
|
.possible_values(POSSIBLE_DERIVED_TYPES)
|
|
|
|
.help("Exclude derived data types explicitly")
|
2020-01-22 20:55:26 +03:00
|
|
|
)
|
2020-08-06 23:07:14 +03:00
|
|
|
.arg(
|
|
|
|
Arg::with_name(ARG_FIND_ALREADY_IMPORTED_REV_ONLY)
|
|
|
|
.long(ARG_FIND_ALREADY_IMPORTED_REV_ONLY)
|
|
|
|
.takes_value(false)
|
|
|
|
.multiple(false)
|
|
|
|
.required(false)
|
|
|
|
.help("Does not do any import. Just finds the rev that was already imported rev and \
|
|
|
|
updates manifold-next-rev-to-import if it's set. Note that we might have \
|
|
|
|
a situation where revision i is imported, i+1 is not and i+2 is imported. \
|
|
|
|
In that case this function would return i.")
|
|
|
|
)
|
2020-11-10 19:44:53 +03:00
|
|
|
.arg(
|
|
|
|
Arg::with_name(BACKUP_FROM_REPO_ID)
|
|
|
|
.long(BACKUP_FROM_REPO_ID)
|
|
|
|
.value_name("ID")
|
|
|
|
.help("numeric ID of backup source of truth mononoke repository (used only for backup jobs to sync bonsai changesets)"),
|
|
|
|
)
|
2021-03-25 16:44:16 +03:00
|
|
|
.arg(
|
|
|
|
Arg::with_name(BACKUP_FROM_REPO_NAME)
|
|
|
|
.long(BACKUP_FROM_REPO_NAME)
|
|
|
|
.value_name("NAME")
|
|
|
|
.help("Name of backup source of truth mononoke repository (used only for backup jobs to sync bonsai changesets)"),
|
|
|
|
)
|
|
|
|
.group(
|
|
|
|
ArgGroup::with_name(BACKUP_REPO_GROUP)
|
|
|
|
.args(&[BACKUP_FROM_REPO_ID, BACKUP_FROM_REPO_NAME])
|
|
|
|
)
|
2019-10-02 01:17:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_fixed_parent_order<P: AsRef<Path>>(
|
|
|
|
logger: &Logger,
|
|
|
|
p: P,
|
|
|
|
) -> Result<HashMap<HgChangesetId, Vec<HgChangesetId>>> {
|
|
|
|
let content = read(p)?;
|
|
|
|
let mut res = HashMap::new();
|
|
|
|
|
|
|
|
for line in String::from_utf8(content).map_err(Error::from)?.split("\n") {
|
|
|
|
if line.is_empty() {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let mut iter = line.split(" ").map(HgChangesetId::from_str).fuse();
|
|
|
|
let maybe_hg_cs_id = iter.next();
|
|
|
|
let hg_cs_id = match maybe_hg_cs_id {
|
|
|
|
Some(hg_cs_id) => hg_cs_id?,
|
|
|
|
None => {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let parents = match (iter.next(), iter.next()) {
|
|
|
|
(Some(p1), Some(p2)) => vec![p1?, p2?],
|
|
|
|
(Some(p), None) => {
|
|
|
|
warn!(
|
|
|
|
logger,
|
|
|
|
"{}: parent order is fixed for a single parent, most likely won't have any effect",
|
|
|
|
hg_cs_id,
|
|
|
|
);
|
|
|
|
vec![p?]
|
|
|
|
}
|
|
|
|
(None, None) => {
|
|
|
|
warn!(
|
2020-09-08 17:31:35 +03:00
|
|
|
logger,
|
|
|
|
"{}: parent order is fixed for a commit with no parents, most likely won't have any effect",
|
2019-10-02 01:17:14 +03:00
|
|
|
hg_cs_id,
|
|
|
|
);
|
|
|
|
vec![]
|
|
|
|
}
|
|
|
|
(None, Some(_)) => unreachable!(),
|
|
|
|
};
|
|
|
|
if let Some(_) = iter.next() {
|
2019-12-06 23:51:47 +03:00
|
|
|
bail!("got 3 parents, but mercurial supports at most 2!");
|
2019-10-02 01:17:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if res.insert(hg_cs_id, parents).is_some() {
|
|
|
|
warn!(logger, "order is fixed twice for {}!", hg_cs_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(res)
|
2018-07-19 13:58:24 +03:00
|
|
|
}
|
|
|
|
|
2020-07-13 12:58:20 +03:00
|
|
|
#[cfg(fbcode_build)]
|
2021-04-28 11:02:26 +03:00
|
|
|
mod facebook {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
use manifold_client::{
|
|
|
|
cpp_client::{ClientOptionsBuilder, ManifoldCppClient},
|
|
|
|
write::WriteRequestOptionsBuilder,
|
|
|
|
ManifoldClient,
|
2020-01-07 22:14:15 +03:00
|
|
|
};
|
2021-04-28 11:02:26 +03:00
|
|
|
|
|
|
|
pub async fn update_manifold_key(
|
|
|
|
fb: FacebookInit,
|
|
|
|
latest_imported_rev: RevIdx,
|
|
|
|
manifold_key: &str,
|
|
|
|
manifold_bucket: &str,
|
|
|
|
) -> Result<()> {
|
|
|
|
let opts = ClientOptionsBuilder::default()
|
|
|
|
.build()
|
|
|
|
.map_err(|e| format_err!("Cannot build Manifold options: {}", e))?;
|
|
|
|
|
|
|
|
let client = ManifoldCppClient::from_options(fb, manifold_bucket, &opts)
|
|
|
|
.context("Cannot build ManifoldCppClient")?;
|
|
|
|
|
|
|
|
let opts = WriteRequestOptionsBuilder::default()
|
|
|
|
.with_allow_overwrite_predicate(true)
|
|
|
|
.build()
|
|
|
|
.map_err(|e| format_err!("Cannot build Write options: {}", e))?;
|
|
|
|
|
|
|
|
let mut req = client
|
|
|
|
.create_write_request(&opts)
|
|
|
|
.context("Cannot build write request")?;
|
|
|
|
|
|
|
|
let next_revision_to_import = latest_imported_rev.as_u32() + 1;
|
2021-05-19 19:56:20 +03:00
|
|
|
let payload = format!("{}", next_revision_to_import);
|
|
|
|
req.write(manifold_key, payload.into()).await?;
|
2021-04-28 11:02:26 +03:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[fbinit::test]
|
|
|
|
async fn test_manifold_write(fb: FacebookInit) -> Result<(), Error> {
|
|
|
|
update_manifold_key(
|
|
|
|
fb,
|
|
|
|
RevIdx::from(0u32),
|
|
|
|
"flat/test_manifold_write",
|
|
|
|
"mononoke_test",
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
update_manifold_key(
|
|
|
|
fb,
|
|
|
|
RevIdx::from(1u32),
|
|
|
|
"flat/test_manifold_write",
|
|
|
|
"mononoke_test",
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2020-01-07 22:14:15 +03:00
|
|
|
}
|
|
|
|
|
2020-03-26 18:07:55 +03:00
|
|
|
async fn run_blobimport<'a>(
|
|
|
|
fb: FacebookInit,
|
2020-03-26 18:07:55 +03:00
|
|
|
ctx: &CoreContext,
|
2020-03-26 18:07:55 +03:00
|
|
|
logger: &Logger,
|
2020-12-02 18:25:35 +03:00
|
|
|
matches: &'a MononokeMatches<'a>,
|
2020-07-13 12:58:20 +03:00
|
|
|
) -> Result<()> {
|
2021-04-16 20:26:03 +03:00
|
|
|
let config_store = matches.config_store();
|
2020-10-24 16:21:31 +03:00
|
|
|
|
2018-07-19 13:58:24 +03:00
|
|
|
let revlogrepo_path = matches
|
|
|
|
.value_of("INPUT")
|
|
|
|
.expect("input is not specified")
|
|
|
|
.into();
|
|
|
|
|
|
|
|
let changeset = match matches.value_of("changeset") {
|
|
|
|
None => None,
|
|
|
|
Some(hash) => Some(HgNodeHash::from_str(hash)?),
|
|
|
|
};
|
|
|
|
|
|
|
|
let skip = if !matches.is_present("skip") {
|
|
|
|
None
|
|
|
|
} else {
|
2020-12-02 18:25:35 +03:00
|
|
|
Some(args::get_usize(matches, "skip", 0))
|
2018-07-19 13:58:24 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
let commits_limit = if !matches.is_present("commits-limit") {
|
|
|
|
None
|
|
|
|
} else {
|
2020-12-02 18:25:35 +03:00
|
|
|
Some(args::get_usize(matches, "commits-limit", 0))
|
2018-07-19 13:58:24 +03:00
|
|
|
};
|
|
|
|
|
2020-01-07 22:14:15 +03:00
|
|
|
let manifold_key = matches
|
|
|
|
.value_of("manifold-next-rev-to-import")
|
|
|
|
.map(|s| s.to_string());
|
|
|
|
|
|
|
|
let manifold_bucket = matches.value_of("manifold-bucket").map(|s| s.to_string());
|
|
|
|
|
|
|
|
let manifold_key_bucket = match (manifold_key, manifold_bucket) {
|
|
|
|
(Some(key), Some(bucket)) => Some((key, bucket)),
|
|
|
|
(None, None) => None,
|
|
|
|
_ => {
|
|
|
|
return Err(format_err!(
|
|
|
|
"invalid manifold parameters: bucket and key should either both be specified or none"
|
|
|
|
));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-07-19 13:58:24 +03:00
|
|
|
let no_bookmark = matches.is_present("no-bookmark");
|
2019-09-11 13:18:25 +03:00
|
|
|
let prefix_bookmark = matches.value_of("prefix-bookmark");
|
|
|
|
if no_bookmark && prefix_bookmark.is_some() {
|
|
|
|
return Err(format_err!(
|
|
|
|
"--no-bookmark is incompatible with --prefix-bookmark"
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let bookmark_import_policy = if no_bookmark {
|
|
|
|
blobimport_lib::BookmarkImportPolicy::Ignore
|
|
|
|
} else {
|
|
|
|
let prefix = match prefix_bookmark {
|
|
|
|
Some(prefix) => AsciiString::from_ascii(prefix).unwrap(),
|
|
|
|
None => AsciiString::new(),
|
|
|
|
};
|
|
|
|
blobimport_lib::BookmarkImportPolicy::Prefix(prefix)
|
|
|
|
};
|
2018-07-19 13:58:24 +03:00
|
|
|
|
2019-07-31 15:13:08 +03:00
|
|
|
let lfs_helper = matches.value_of("lfs-helper").map(|l| l.to_string());
|
|
|
|
|
2020-12-02 18:25:35 +03:00
|
|
|
let concurrent_changesets = args::get_usize(matches, "concurrent-changesets", 100);
|
|
|
|
let concurrent_blobs = args::get_usize(matches, "concurrent-blobs", 100);
|
|
|
|
let concurrent_lfs_imports = args::get_usize(matches, "concurrent-lfs-imports", 10);
|
2019-08-07 18:26:52 +03:00
|
|
|
|
2019-10-02 01:17:14 +03:00
|
|
|
let fixed_parent_order = if let Some(path) = matches.value_of("fix-parent-order") {
|
|
|
|
parse_fixed_parent_order(&logger, path)
|
|
|
|
.context("while parsing file with fixed parent order")?
|
|
|
|
} else {
|
|
|
|
HashMap::new()
|
|
|
|
};
|
|
|
|
|
2020-01-27 12:09:21 +03:00
|
|
|
let mut derived_data_types = matches
|
2020-01-22 20:55:26 +03:00
|
|
|
.values_of(ARG_DERIVED_DATA_TYPE)
|
|
|
|
.map(|v| v.map(|d| d.to_string()).collect())
|
|
|
|
.unwrap_or(vec![]);
|
|
|
|
|
2020-11-18 17:06:39 +03:00
|
|
|
let excluded_derived_data_types = matches
|
|
|
|
.values_of(ARG_EXCLUDE_DERIVED_DATA_TYPE)
|
|
|
|
.map_or(vec![], |v| v.map(|d| d.to_string()).collect());
|
|
|
|
|
|
|
|
for v in &excluded_derived_data_types {
|
|
|
|
if derived_data_types.contains(v) {
|
|
|
|
return Err(format_err!("Unexpected exclusion of requested {}", v));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure filenodes derived unless specifically excluded since public hg changesets must have filenodes derived
|
2020-01-27 12:09:21 +03:00
|
|
|
let filenodes_derived_name = FilenodesOnlyPublic::NAME.to_string();
|
2020-11-18 17:06:39 +03:00
|
|
|
if !derived_data_types.contains(&filenodes_derived_name)
|
|
|
|
&& !excluded_derived_data_types.contains(&filenodes_derived_name)
|
|
|
|
{
|
2020-01-27 12:09:21 +03:00
|
|
|
derived_data_types.push(filenodes_derived_name);
|
|
|
|
}
|
|
|
|
|
2019-10-30 20:42:39 +03:00
|
|
|
let has_globalrev = matches.is_present("has-globalrev");
|
2020-03-26 18:07:55 +03:00
|
|
|
|
2020-12-02 18:25:35 +03:00
|
|
|
let (_repo_name, repo_config) = args::get_config(config_store, matches)?;
|
2020-02-21 16:39:24 +03:00
|
|
|
let populate_git_mapping = repo_config.pushrebase.populate_git_mapping.clone();
|
2020-03-26 18:07:55 +03:00
|
|
|
|
2020-12-02 18:25:35 +03:00
|
|
|
let small_repo_id = args::get_source_repo_id_opt(config_store, matches)?;
|
2019-11-25 16:09:58 +03:00
|
|
|
|
2021-04-28 21:13:50 +03:00
|
|
|
let globalrevs_store = args::open_sql::<SqlBonsaiGlobalrevMapping>(fb, config_store, matches)?;
|
|
|
|
let synced_commit_mapping =
|
|
|
|
args::open_sql::<SqlSyncedCommitMapping>(fb, config_store, matches)?;
|
|
|
|
let mutable_counters = args::open_sql::<SqlMutableCounters>(fb, config_store, matches)?;
|
|
|
|
|
2021-06-09 15:14:14 +03:00
|
|
|
let blobrepo: BlobRepo = if matches.is_present("no-create") {
|
2021-04-28 21:13:50 +03:00
|
|
|
args::open_repo_unredacted(fb, &ctx.logger(), matches).await?
|
|
|
|
} else {
|
|
|
|
args::create_repo_unredacted(fb, &ctx.logger(), matches).await?
|
|
|
|
};
|
2020-03-26 18:07:55 +03:00
|
|
|
|
2021-03-25 16:44:16 +03:00
|
|
|
let origin_repo =
|
|
|
|
if matches.is_present(BACKUP_FROM_REPO_ID) || matches.is_present(BACKUP_FROM_REPO_NAME) {
|
|
|
|
let repo_id = args::get_repo_id_from_value(
|
|
|
|
config_store,
|
|
|
|
matches,
|
|
|
|
BACKUP_FROM_REPO_ID,
|
|
|
|
BACKUP_FROM_REPO_NAME,
|
|
|
|
)?;
|
|
|
|
Some(args::open_repo_with_repo_id(fb, &logger, repo_id, matches).await?)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2020-11-10 19:44:53 +03:00
|
|
|
|
2020-03-26 18:07:55 +03:00
|
|
|
let globalrevs_store = Arc::new(globalrevs_store);
|
|
|
|
let synced_commit_mapping = Arc::new(synced_commit_mapping);
|
|
|
|
|
2020-08-06 23:07:14 +03:00
|
|
|
let find_latest_imported_rev_only = matches.is_present(ARG_FIND_ALREADY_IMPORTED_REV_ONLY);
|
2020-03-26 18:07:55 +03:00
|
|
|
async move {
|
2020-08-06 23:07:14 +03:00
|
|
|
let blobimport = blobimport_lib::Blobimport {
|
2020-04-07 01:22:12 +03:00
|
|
|
ctx,
|
2020-08-12 18:48:16 +03:00
|
|
|
blobrepo: blobrepo.clone(),
|
2020-03-26 18:07:55 +03:00
|
|
|
revlogrepo_path,
|
|
|
|
changeset,
|
|
|
|
skip,
|
|
|
|
commits_limit,
|
|
|
|
bookmark_import_policy,
|
|
|
|
globalrevs_store,
|
|
|
|
synced_commit_mapping,
|
|
|
|
lfs_helper,
|
|
|
|
concurrent_changesets,
|
|
|
|
concurrent_blobs,
|
|
|
|
concurrent_lfs_imports,
|
|
|
|
fixed_parent_order,
|
|
|
|
has_globalrev,
|
|
|
|
populate_git_mapping,
|
|
|
|
small_repo_id,
|
|
|
|
derived_data_types,
|
2020-11-10 19:44:53 +03:00
|
|
|
origin_repo,
|
2020-08-06 23:07:14 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
let maybe_latest_imported_rev = if find_latest_imported_rev_only {
|
|
|
|
blobimport.find_already_imported_revision().await?
|
|
|
|
} else {
|
|
|
|
blobimport.import().await?
|
|
|
|
};
|
2020-03-26 18:07:55 +03:00
|
|
|
|
2020-07-13 12:58:20 +03:00
|
|
|
match maybe_latest_imported_rev {
|
2020-08-12 18:48:16 +03:00
|
|
|
Some((latest_imported_rev, latest_imported_cs_id)) => {
|
2020-07-13 12:58:20 +03:00
|
|
|
info!(
|
|
|
|
ctx.logger(),
|
|
|
|
"latest imported revision {}",
|
|
|
|
latest_imported_rev.as_u32()
|
|
|
|
);
|
|
|
|
#[cfg(fbcode_build)]
|
|
|
|
{
|
2020-03-26 18:07:55 +03:00
|
|
|
if let Some((manifold_key, bucket)) = manifold_key_bucket {
|
2021-04-28 11:02:26 +03:00
|
|
|
facebook::update_manifold_key(
|
|
|
|
fb,
|
|
|
|
latest_imported_rev,
|
|
|
|
&manifold_key,
|
|
|
|
&bucket,
|
|
|
|
)
|
|
|
|
.await?
|
2020-03-26 18:07:55 +03:00
|
|
|
}
|
|
|
|
}
|
2020-07-13 12:58:20 +03:00
|
|
|
#[cfg(not(fbcode_build))]
|
|
|
|
{
|
|
|
|
assert!(
|
|
|
|
manifold_key_bucket.is_none(),
|
|
|
|
"Using Manifold is not supported in non fbcode builds"
|
|
|
|
);
|
2020-01-28 20:39:05 +03:00
|
|
|
}
|
2020-08-12 18:48:16 +03:00
|
|
|
|
|
|
|
maybe_update_highest_imported_generation_number(
|
|
|
|
&ctx,
|
|
|
|
&blobrepo,
|
|
|
|
&mutable_counters,
|
|
|
|
latest_imported_cs_id,
|
|
|
|
)
|
|
|
|
.await?;
|
2020-03-26 18:07:55 +03:00
|
|
|
}
|
2020-07-13 12:58:20 +03:00
|
|
|
None => info!(ctx.logger(), "didn't import any commits"),
|
|
|
|
};
|
2020-03-26 18:07:55 +03:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
.map_err({
|
|
|
|
move |err| {
|
|
|
|
// NOTE: We log the error immediatley, then provide another one for main's
|
|
|
|
// Result (which will set our exit code).
|
|
|
|
error!(ctx.logger(), "error while blobimporting"; SlogKVError(err));
|
|
|
|
Error::msg("blobimport exited with a failure")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2020-08-12 18:48:16 +03:00
|
|
|
// Updating mutable_counters table to store the highest generation number that was imported.
|
|
|
|
// This in turn can be used to track which commits exist on both mercurial and Mononoke.
|
|
|
|
// For example, WarmBookmarkCache might consider a bookmark "warm" only if a commit is in both
|
|
|
|
// mercurial and Mononoke.
|
|
|
|
//
|
|
|
|
// Note that if a commit with a lower generation number was added (e.g. if this commit forked off from
|
|
|
|
// the main branch) then this hint will be misleading - i.e. the hint would store a higher generation
|
|
|
|
// number then the new commit which might not be processed by blobimport yet. In that case there are
|
|
|
|
// two options:
|
|
|
|
// 1) Use this hint only in single-branch repos
|
|
|
|
// 2) Accept that the hint might be incorrect sometimes.
|
|
|
|
async fn maybe_update_highest_imported_generation_number(
|
|
|
|
ctx: &CoreContext,
|
|
|
|
blobrepo: &BlobRepo,
|
|
|
|
mutable_counters: &SqlMutableCounters,
|
|
|
|
latest_imported_cs_id: ChangesetId,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let maybe_highest_imported_gen_num = mutable_counters
|
|
|
|
.get_counter(
|
|
|
|
ctx.clone(),
|
|
|
|
blobrepo.get_repoid(),
|
|
|
|
blobimport_lib::HIGHEST_IMPORTED_GEN_NUM,
|
|
|
|
)
|
|
|
|
.compat();
|
2020-11-27 22:09:33 +03:00
|
|
|
let new_gen_num = blobrepo.get_generation_number(ctx.clone(), latest_imported_cs_id);
|
2020-08-12 18:48:16 +03:00
|
|
|
let (maybe_highest_imported_gen_num, new_gen_num) =
|
|
|
|
try_join(maybe_highest_imported_gen_num, new_gen_num).await?;
|
|
|
|
|
|
|
|
let new_gen_num = new_gen_num.ok_or(format_err!("generation number is not set"))?;
|
|
|
|
let new_gen_num = match maybe_highest_imported_gen_num {
|
|
|
|
Some(highest_imported_gen_num) => {
|
|
|
|
if new_gen_num.value() as i64 > highest_imported_gen_num {
|
|
|
|
Some(new_gen_num)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => Some(new_gen_num),
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(new_gen_num) = new_gen_num {
|
|
|
|
mutable_counters
|
|
|
|
.set_counter(
|
|
|
|
ctx.clone(),
|
|
|
|
blobrepo.get_repoid(),
|
|
|
|
blobimport_lib::HIGHEST_IMPORTED_GEN_NUM,
|
|
|
|
new_gen_num.value() as i64,
|
|
|
|
maybe_highest_imported_gen_num,
|
|
|
|
)
|
|
|
|
.compat()
|
|
|
|
.await?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-03-26 18:07:55 +03:00
|
|
|
#[fbinit::main]
|
|
|
|
fn main(fb: FacebookInit) -> Result<()> {
|
2021-04-16 20:26:03 +03:00
|
|
|
let matches = setup_app().get_matches(fb)?;
|
2020-03-26 18:07:55 +03:00
|
|
|
|
2021-04-16 20:26:03 +03:00
|
|
|
let logger = matches.logger();
|
2021-05-06 21:38:54 +03:00
|
|
|
let scuba = matches.scuba_sample_builder();
|
2021-02-16 03:29:16 +03:00
|
|
|
|
|
|
|
let ctx = &SessionContainer::new_with_defaults(fb).new_context(logger.clone(), scuba);
|
2018-07-19 13:58:24 +03:00
|
|
|
|
2020-01-29 20:39:49 +03:00
|
|
|
block_execute(
|
2021-04-16 20:26:03 +03:00
|
|
|
run_blobimport(fb, ctx, logger, &matches),
|
2020-01-29 20:39:49 +03:00
|
|
|
fb,
|
|
|
|
"blobimport",
|
2021-04-16 20:26:03 +03:00
|
|
|
logger,
|
2020-01-29 20:39:49 +03:00
|
|
|
&matches,
|
|
|
|
cmdlib::monitoring::AliveService,
|
|
|
|
)
|
2018-07-19 13:58:24 +03:00
|
|
|
}
|