Skip to content

Commit

Permalink
Allow reading tail across hosts
Browse files Browse the repository at this point in the history
  • Loading branch information
ellie committed Jul 9, 2023
1 parent 1a6e012 commit 7b0c72e
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 11 deletions.
10 changes: 5 additions & 5 deletions atuin-client/src/kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
};

Expand Down
19 changes: 16 additions & 3 deletions atuin-client/src/record/sqlite_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion atuin-client/src/record/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)>>;
}
4 changes: 2 additions & 2 deletions atuin-client/src/record/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 7b0c72e

Please sign in to comment.