Skip to content
Snippets Groups Projects
Commit 725e8c52 authored by Georges Racinet's avatar Georges Racinet
Browse files

RHGitaly: reading keep-arounds state file

This time, because there is no arbitrary name to consider, hence
no bytes string, Tokio's `LinesStream` is perfectly suitable for
our needs.
parent bcab7028
No related branches found
No related tags found
2 merge requests!169Protocol v15.9 and stable branch merge",!166RHGitaly: reading GitLab ref state files, implementing RefService.RefExists
......@@ -19,7 +19,11 @@
//! As of this writing, the GitLab state is made of
//!
//! - refs, believed by other components to actually be Git refs. These are kept in several
//! files, due to vastly different read/write frequencies.
//! files, due to vastly different read/write frequencies. Among them are typed refs (branches,
//! tags etc), and keep-arounds (just hashes). These two cases are represented with different
//! Rust types in this implementation, whereas the Python reference would consider them all to be
//! typed refs with a different serialization format for keep-arounds (name would just be
//! repeating the hash, which is a waste).
//! - default branch, as ultimately defined by end users
//!
//! For a full documentation of the concepts, related file formats and atomicity properties, see the
......@@ -32,7 +36,8 @@
use std::io;
use std::path::Path;
use tokio::fs::File;
use tokio::io::{AsyncBufRead, AsyncReadExt, BufReader};
use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, BufReader};
use tokio_stream::wrappers::LinesStream;
use tokio_stream::StreamExt;
use tokio_util::codec::{Decoder, FramedRead};
......@@ -95,6 +100,7 @@
/// Convenience alias for actual type returned by streaming functions
pub type TypedRefsFileStream = Option<FramedRead<BufReader<File>, TypedRefDecoder>>;
pub type KeepAroundsFileStream = Option<LinesStream<BufReader<File>>>;
type TypedRefsFileStreamResult = Result<TypedRefsFileStream, StateFileError>;
......@@ -223,6 +229,47 @@
}
}
async fn stream_keep_arounds<R: AsyncBufRead + Unpin>(
mut buf: R,
) -> Result<LinesStream<R>, StateFileError> {
check_version_preamble(&mut buf).await?;
Ok(LinesStream::new(buf.lines()))
}
/// Open the keep-arounds state file and stream its content as a [`LinesStream`]
///
/// Returns `None` if the state file does not exist.
/// In particular, iterating on the stream yields [`String`] objects, not [`Vec<u8>`].
pub async fn stream_keep_arounds_file(
store_vfs: &Path,
) -> Result<KeepAroundsFileStream, StateFileError> {
Ok(
match io_error_not_found_as_none(File::open(store_vfs.join("gitlab.keep-arounds")).await)? {
None => None,
Some(f) => Some(stream_keep_arounds(BufReader::new(f)).await?),
},
)
}
/// Tell whether the repository has a keep-around, given in hexadecimal form
///
/// As other functions in this module, the repository is given just by its
/// `store` subdirectory.
pub async fn has_keep_around(store_vfs: &Path, ka: &[u8]) -> Result<bool, StateFileError> {
if let Some(mut stream) = stream_keep_arounds_file(store_vfs).await? {
// cannot use stream.any() and propagate error as it needs the closure to return `bool`,
// not some Result
while let Some(res) = stream.next().await {
if res?.as_bytes() == ka {
return Ok(true);
}
}
Ok(false)
} else {
Ok(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
......@@ -368,4 +415,45 @@
assert_eq!(map_lookup_typed_ref(tags, b"v1.3", |tr| tr).await?, None);
Ok(())
}
#[tokio::test]
async fn test_stream_keep_arounds_file() -> Result<(), StateFileError> {
let tmp_dir = tempdir().unwrap(); // not async, but it doesn't matter much in tests
let store_vfs = tmp_dir.path();
assert!(stream_keep_arounds_file(store_vfs).await?.is_none());
write_test_file(
store_vfs,
"gitlab.keep-arounds",
b"001\n437bd1bf68ac037eb6956490444e2d7f9a5655c9",
)
.await?;
let stream = stream_keep_arounds_file(store_vfs).await?.unwrap();
let res: Vec<String> = stream.map(|r| r.unwrap()).collect().await;
assert_eq!(
res,
vec!["437bd1bf68ac037eb6956490444e2d7f9a5655c9".to_owned()]
);
Ok(())
}
#[tokio::test]
async fn test_has_keep_around() -> Result<(), StateFileError> {
let tmp_dir = tempdir().unwrap(); // not async, but it doesn't matter much in tests
let store_vfs = tmp_dir.path();
assert!(!has_keep_around(store_vfs, b"437bd1bf68ac037eb6956490444e2d7f9a5655c9").await?);
write_test_file(
store_vfs,
"gitlab.keep-arounds",
b"001\n437bd1bf68ac037eb6956490444e2d7f9a5655c9",
)
.await?;
assert!(has_keep_around(store_vfs, b"437bd1bf68ac037eb6956490444e2d7f9a5655c9").await?);
assert!(!has_keep_around(store_vfs, b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").await?);
Ok(())
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment