Allow reading tail across hosts

This commit is contained in:
Ellie Huxtable 2023-07-09 21:20:12 +01:00
parent 1a6e012295
commit 7b0c72e7e0
4 changed files with 24 additions and 11 deletions

View File

@ -101,7 +101,10 @@ impl KvStore {
let bytes = record.serialize()?;
let parent = store.tail(host_id, KV_TAG).await?.map(|entry| entry.id);
let parent = store
.tail(Some(host_id), KV_TAG)
.await?
.map(|entry| entry.id);
let record = atuin_common::record::Record::builder()
.host(host_id)
@ -127,15 +130,12 @@ impl KvStore {
namespace: &str,
key: &str,
) -> Result<Option<KvRecord>> {
// TODO: don't load this from disk so much
let host_id = Settings::host_id().expect("failed to get host_id");
// Currently, this is O(n). When we have an actual KV store, it can be better
// Just a poc for now!
// iterate records to find the value we want
// start at the end, so we get the most recent version
let Some(mut record) = store.tail(host_id, KV_TAG).await? else {
let Some(mut record) = store.tail(None, KV_TAG).await? else {
return Ok(None);
};

View File

@ -171,15 +171,28 @@ impl Store for SqliteStore {
Ok(res)
}
async fn tail(&self, host: Uuid, tag: &str) -> Result<Option<Record<EncryptedData>>> {
let res = sqlx::query(
// Get the tail for a given tag
// If a host is provided, get the tail for a tag for that host
// Otherwise, the latest record across hosts
async fn tail(&self, host: Option<Uuid>, tag: &str) -> Result<Option<Record<EncryptedData>>> {
let res = if let Some(host) = host {
sqlx::query(
"select * from records rp where tag=?1 and host=?2 and (select count(1) from records where parent=rp.id) = 0;",
)
.bind(tag)
.bind(host.as_simple().to_string())
.map(Self::query_row)
.fetch_optional(&self.pool)
.await?;
.await?
} else {
sqlx::query(
"select * from records rp where tag=?1 and (select count(1) from records where parent=rp.id) = 0;",
)
.bind(tag)
.map(Self::query_row)
.fetch_optional(&self.pool)
.await?
};
Ok(res)
}

View File

@ -30,7 +30,7 @@ pub trait Store {
/// Get the first record for a given host and tag
async fn head(&self, host: Uuid, tag: &str) -> Result<Option<Record<EncryptedData>>>;
/// Get the last record for a given host and tag
async fn tail(&self, host: Uuid, tag: &str) -> Result<Option<Record<EncryptedData>>>;
async fn tail(&self, host: Option<Uuid>, tag: &str) -> Result<Option<Record<EncryptedData>>>;
async fn tail_records(&self) -> Result<Vec<(Uuid, String, Uuid)>>;
}

View File

@ -49,7 +49,7 @@ pub async fn operations(diff: Diff, store: &impl Store) -> Result<Vec<Operation>
// if local has the ID, then we should find the actual tail of this
// store, so we know what we need to update the remote to.
let tail = store
.tail(host, tag.as_str())
.tail(Some(host), tag.as_str())
.await?
.expect("failed to fetch last record, expected tag/host to exist");
@ -163,7 +163,7 @@ async fn sync_download(
let remote_tail = remote_index
.get(op.0, op.1.clone())
.expect("remote index does not contain expected tail during download");
let local_tail = store.tail(op.0, op.1.as_str()).await?;
let local_tail = store.tail(Some(op.0), op.1.as_str()).await?;
//
// We expect that the operations diff will represent the desired state
// In this case, that contains the remote tail.