Skip to content

Commit

Permalink
fix: ensure defaulted options are set prior to ObjectStore creation
Browse files Browse the repository at this point in the history
The options handling must occur before the ObjectStore is actually
created in order for the object_store crate to properly inherit the
conditional_put configuration setting.

Otherwise an OSError is returned (object_store NotImplemented error)

Signed-off-by: R. Tyler Croy <[email protected]>
  • Loading branch information
rtyler committed Jan 1, 2025
1 parent 0015d7b commit 64c1b1a
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 28 deletions.
24 changes: 1 addition & 23 deletions crates/aws/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ use aws_sdk_dynamodb::{
Client,
};
use deltalake_core::logstore::{default_logstore, logstores, LogStore, LogStoreFactory};
use deltalake_core::storage::object_store::aws::AmazonS3ConfigKey;
use deltalake_core::storage::{factories, url_prefix_handler, ObjectStoreRef, StorageOptions};
use deltalake_core::{DeltaResult, Path};
use errors::{DynamoDbConfigError, LockClientError};
use lazy_static::lazy_static;
use object_store::aws::AmazonS3ConfigKey;
use regex::Regex;
use std::{
collections::HashMap,
Expand Down Expand Up @@ -78,28 +78,6 @@ impl LogStoreFactory for S3LogStoreFactory {
store,
)?));
}

// All S3-like Object Stores use conditional put, object-store crate however still requires you to explicitly
// set this behaviour. We will however assume, when a locking provider/copy-if-not-exists keys are not provided
// that PutIfAbsent is supported.
// With conditional put in S3-like API we can use the deltalake default logstore which use PutIfAbsent
let inner = if !options.0.keys().any(|key| {
let key = key.to_ascii_lowercase();
[
AmazonS3ConfigKey::ConditionalPut.as_ref(),
"conditional_put",
]
.contains(&key.as_str())
}) {
let mut inner = options.0.clone();
inner.insert("aws_conditional_put".to_string(), "etag".to_string());
inner
} else {
options.0.clone()
};

let options = StorageOptions::from(inner);
debug!("S3LogStoreFactory has been asked to create a default LogStore where the underlying store has Conditonal Put enabled - no locking provider required");
Ok(default_logstore(store, location, &options))
}
}
Expand Down
30 changes: 25 additions & 5 deletions crates/aws/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ impl S3ObjectStoreFactory {
}
}
}

// All S3-like Object Stores use conditional put, object-store crate however still requires you to explicitly
// set this behaviour. We will however assume, when a locking provider/copy-if-not-exists keys are not provided
// that PutIfAbsent is supported.
// With conditional put in S3-like API we can use the deltalake default logstore which use PutIfAbsent
if !options.0.keys().any(|key| {
let key = key.to_ascii_lowercase();
[
AmazonS3ConfigKey::ConditionalPut.as_ref(),
"conditional_put",
]
.contains(&key.as_str())
}) {
options.0.insert("conditional_put".into(), "etag".into());
}
options
}
}
Expand Down Expand Up @@ -772,10 +787,13 @@ mod tests {
let combined_options =
S3ObjectStoreFactory {}.with_env_s3(&StorageOptions(raw_options));

assert_eq!(combined_options.0.len(), 4);
// Four and then the conditional_put built-in
assert_eq!(combined_options.0.len(), 5);

for v in combined_options.0.values() {
assert_eq!(v, "env_key");
for (key, v) in combined_options.0 {
if key != "conditional_put" {
assert_eq!(v, "env_key");
}
}
});
}
Expand All @@ -799,8 +817,10 @@ mod tests {
let combined_options =
S3ObjectStoreFactory {}.with_env_s3(&StorageOptions(raw_options));

for v in combined_options.0.values() {
assert_eq!(v, "options_key");
for (key, v) in combined_options.0 {
if key != "conditional_put" {
assert_eq!(v, "options_key");
}
}
});
}
Expand Down

0 comments on commit 64c1b1a

Please sign in to comment.