-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an object_store backed metadata store
- Loading branch information
1 parent
6d189c1
commit 96c304d
Showing
11 changed files
with
1,112 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
175 changes: 175 additions & 0 deletions
175
crates/core/src/metadata_store/providers/objstore/glue.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
// Copyright (c) 2024 - Restate Software, Inc., Restate GmbH. | ||
// All rights reserved. | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the LICENSE file. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0. | ||
|
||
use std::pin; | ||
|
||
use bytestring::ByteString; | ||
use restate_types::Version; | ||
use tokio::sync::oneshot::Sender; | ||
use tracing::warn; | ||
|
||
use crate::cancellation_watcher; | ||
use crate::metadata_store::providers::objstore::optimistic_store::OptimisticLockingMetadataStoreBuilder; | ||
use crate::metadata_store::{MetadataStore, Precondition, ReadError, VersionedValue, WriteError}; | ||
|
||
#[derive(Debug)] | ||
pub(crate) enum Commands { | ||
Get { | ||
key: ByteString, | ||
tx: Sender<Result<Option<VersionedValue>, ReadError>>, | ||
}, | ||
GetVersion { | ||
key: ByteString, | ||
tx: Sender<Result<Option<Version>, ReadError>>, | ||
}, | ||
Put { | ||
key: ByteString, | ||
value: VersionedValue, | ||
precondition: Precondition, | ||
tx: Sender<Result<(), WriteError>>, | ||
}, | ||
Delete { | ||
key: ByteString, | ||
precondition: Precondition, | ||
tx: Sender<Result<(), WriteError>>, | ||
}, | ||
} | ||
|
||
pub(crate) struct Server { | ||
receiver: tokio::sync::mpsc::UnboundedReceiver<Commands>, | ||
builder: OptimisticLockingMetadataStoreBuilder, | ||
} | ||
|
||
impl Server { | ||
pub(crate) fn new( | ||
builder: OptimisticLockingMetadataStoreBuilder, | ||
receiver: tokio::sync::mpsc::UnboundedReceiver<Commands>, | ||
) -> Self { | ||
Self { builder, receiver } | ||
} | ||
|
||
pub(crate) async fn run(self) -> anyhow::Result<()> { | ||
let Server { | ||
mut receiver, | ||
builder, | ||
} = self; | ||
|
||
let mut shutdown = pin::pin!(cancellation_watcher()); | ||
|
||
let mut delegate = match builder.build().await { | ||
Ok(delegate) => delegate, | ||
Err(err) => { | ||
warn!(error = ?err, "error while loading latest metastore version."); | ||
return Err(err); | ||
} | ||
}; | ||
|
||
loop { | ||
tokio::select! { | ||
_ = &mut shutdown => { | ||
// stop accepting messages | ||
return Ok(()); | ||
} | ||
Some(cmd) = receiver.recv() => { | ||
match cmd { | ||
Commands::Get{key,tx } => { | ||
let res = delegate.get(key).await; | ||
let _ = tx.send(res); | ||
} | ||
Commands::GetVersion{key,tx } => { | ||
let _ = tx.send(delegate.get_version(key).await); | ||
} | ||
Commands::Put{key,value,precondition,tx } => { | ||
let _ = tx.send(delegate.put(key, value, precondition).await); | ||
} | ||
Commands::Delete{key,precondition,tx } => { | ||
let _ = tx.send(delegate.delete(key, precondition).await); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct Client { | ||
sender: tokio::sync::mpsc::UnboundedSender<Commands>, | ||
} | ||
|
||
impl Client { | ||
pub fn new(sender: tokio::sync::mpsc::UnboundedSender<Commands>) -> Self { | ||
Self { sender } | ||
} | ||
} | ||
|
||
#[async_trait::async_trait] | ||
impl MetadataStore for Client { | ||
async fn get(&self, key: ByteString) -> Result<Option<VersionedValue>, ReadError> { | ||
let (tx, rx) = tokio::sync::oneshot::channel(); | ||
|
||
self.sender | ||
.send(Commands::Get { key, tx }) | ||
.map_err(|_| ReadError::Internal("Object store fetch channel ".into()))?; | ||
|
||
rx.await.map_err(|_| { | ||
ReadError::Internal("Object store fetch channel disconnected".to_string()) | ||
})? | ||
} | ||
|
||
async fn get_version(&self, key: ByteString) -> Result<Option<Version>, ReadError> { | ||
let (tx, rx) = tokio::sync::oneshot::channel(); | ||
|
||
self.sender | ||
.send(Commands::GetVersion { key, tx }) | ||
.map_err(|_| ReadError::Internal("Object store fetch channel ".into()))?; | ||
|
||
rx.await.map_err(|_| { | ||
ReadError::Internal("Object store fetch channel disconnected".to_string()) | ||
})? | ||
} | ||
|
||
async fn put( | ||
&self, | ||
key: ByteString, | ||
value: VersionedValue, | ||
precondition: Precondition, | ||
) -> Result<(), WriteError> { | ||
let (tx, rx) = tokio::sync::oneshot::channel(); | ||
|
||
self.sender | ||
.send(Commands::Put { | ||
key, | ||
value, | ||
precondition, | ||
tx, | ||
}) | ||
.map_err(|_| WriteError::Internal("Object store channel ".into()))?; | ||
|
||
rx.await | ||
.map_err(|_| WriteError::Internal("Object store channel disconnected".to_string()))? | ||
} | ||
|
||
async fn delete(&self, key: ByteString, precondition: Precondition) -> Result<(), WriteError> { | ||
let (tx, rx) = tokio::sync::oneshot::channel(); | ||
|
||
self.sender | ||
.send(Commands::Delete { | ||
key, | ||
precondition, | ||
tx, | ||
}) | ||
.map_err(|_| WriteError::Internal("Object store fetch channel ".into()))?; | ||
|
||
rx.await.map_err(|_| { | ||
WriteError::Internal("Object store fetch channel disconnected".to_string()) | ||
})? | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright (c) 2024 - Restate Software, Inc., Restate GmbH. | ||
// All rights reserved. | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the LICENSE file. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0. | ||
|
||
use crate::metadata_store::providers::objstore::object_store_version_repository::ObjectStoreVersionRepository; | ||
use crate::metadata_store::providers::objstore::optimistic_store::OptimisticLockingMetadataStoreBuilder; | ||
use crate::metadata_store::providers::objstore::version_repository::VersionRepository; | ||
use crate::metadata_store::MetadataStore; | ||
use crate::{TaskCenter, TaskKind}; | ||
use restate_types::config::MetadataStoreClient; | ||
use restate_types::errors::GenericError; | ||
|
||
mod glue; | ||
mod object_store_version_repository; | ||
mod optimistic_store; | ||
mod version_repository; | ||
|
||
pub async fn create_object_store_based_meta_store( | ||
configuration: MetadataStoreClient, | ||
) -> Result<impl MetadataStore, GenericError> { | ||
// obtain an instance of a version repository from the configuration. | ||
// we use an object_store backed version repository. | ||
let version_repository = Box::new(ObjectStoreVersionRepository::from_configuration( | ||
configuration.clone(), | ||
)?) as Box<dyn VersionRepository>; | ||
|
||
// postpone the building of the store to the background task, | ||
// the runs at the task center. | ||
let store_builder = OptimisticLockingMetadataStoreBuilder { | ||
version_repository, | ||
configuration, | ||
}; | ||
// | ||
// setup all the glue code, the forwarding client and the event loop server. | ||
// | ||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); | ||
let server = glue::Server::new(store_builder, rx); | ||
TaskCenter::spawn( | ||
TaskKind::MetadataStore, | ||
"metadata-store-client", | ||
server.run(), | ||
) | ||
.expect("unable to spawn a task"); | ||
|
||
let client = glue::Client::new(tx); | ||
Ok(client) | ||
} |
Oops, something went wrong.