Skip to content

Commit 13b4aa4

Browse files
committed
Add MetadataLocation struct
Signed-off-by: DerGut <jannik.steinmann@gmx.de>
1 parent cd5dd5e commit 13b4aa4

File tree

2 files changed

+217
-80
lines changed

2 files changed

+217
-80
lines changed

crates/catalog/memory/src/catalog.rs

Lines changed: 23 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//! This module contains memory catalog implementation.
1919
2020
use std::collections::HashMap;
21+
use std::str::FromStr;
2122

2223
use async_trait::async_trait;
2324
use futures::lock::{Mutex, MutexGuard};
@@ -29,9 +30,8 @@ use iceberg::{
2930
TableIdent, TableUpdate,
3031
};
3132
use itertools::Itertools;
32-
use uuid::Uuid;
3333

34-
use crate::namespace_state::NamespaceState;
34+
use crate::namespace_state::{MetadataLocation, NamespaceState};
3535

3636
/// namespace `location` property
3737
const LOCATION: &str = "location";
@@ -71,7 +71,11 @@ impl MemoryCatalog {
7171
.build()
7272
}
7373

74-
async fn update_table(&self, table: &Table, updates: Vec<TableUpdate>) -> Result<Table> {
74+
async fn update_table(
75+
&self,
76+
table: &Table,
77+
updates: Vec<TableUpdate>,
78+
) -> Result<(Table, MetadataLocation)> {
7579
let (new_metadata, new_metadata_location) = apply_table_updates(table, updates)?;
7680

7781
self.write_metadata(&new_metadata, &new_metadata_location)
@@ -84,11 +88,11 @@ impl MemoryCatalog {
8488
.file_io(self.file_io.clone())
8589
.build()?;
8690

87-
Ok(new_table)
91+
Ok((new_table, new_metadata_location))
8892
}
8993

90-
async fn read_metadata(&self, location: &str) -> Result<TableMetadata> {
91-
let input_file = self.file_io.new_input(location)?;
94+
async fn read_metadata(&self, location: &MetadataLocation) -> Result<TableMetadata> {
95+
let input_file = self.file_io.new_input(location.to_string())?;
9296
let metadata_content = input_file.read().await?;
9397
let metadata = serde_json::from_slice::<TableMetadata>(&metadata_content)?;
9498

@@ -98,10 +102,10 @@ impl MemoryCatalog {
98102
async fn write_metadata(
99103
&self,
100104
metadata: &TableMetadata,
101-
metadata_location: &str,
105+
metadata_location: &MetadataLocation,
102106
) -> Result<()> {
103107
self.file_io
104-
.new_output(metadata_location)?
108+
.new_output(metadata_location.to_string())?
105109
.write(serde_json::to_vec(metadata)?.into())
106110
.await
107111
}
@@ -249,20 +253,15 @@ impl Catalog for MemoryCatalog {
249253
let metadata = TableMetadataBuilder::from_table_creation(table_creation)?
250254
.build()?
251255
.metadata;
252-
let metadata_location = format!(
253-
"{}/metadata/{}-{}.metadata.json",
254-
&location,
255-
0,
256-
Uuid::new_v4()
257-
);
256+
let metadata_location = MetadataLocation::new(&location);
258257

259258
self.write_metadata(&metadata, &metadata_location).await?;
260259

261260
root_namespace_state.insert_new_table(&table_ident, metadata_location.clone())?;
262261

263262
Table::builder()
264263
.file_io(self.file_io.clone())
265-
.metadata_location(metadata_location)
264+
.metadata_location(metadata_location.to_string())
266265
.metadata(metadata)
267266
.identifier(table_ident)
268267
.build()
@@ -281,7 +280,7 @@ impl Catalog for MemoryCatalog {
281280
let mut root_namespace_state = self.root_namespace_state.lock().await;
282281

283282
let metadata_location = root_namespace_state.remove_existing_table(table_ident)?;
284-
self.file_io.delete(&metadata_location).await
283+
self.file_io.delete(metadata_location.to_string()).await
285284
}
286285

287286
/// Check if a table exists in the catalog.
@@ -322,17 +321,11 @@ impl Catalog for MemoryCatalog {
322321
requirement.check(Some(current_table.metadata()))?;
323322
}
324323

325-
let updated_table = self
324+
let (updated_table, new_metadata_location) = self
326325
.update_table(&current_table, commit.take_updates())
327326
.await?;
328327

329-
root_namespace_state.update_table(
330-
updated_table.identifier(),
331-
updated_table
332-
.metadata_location()
333-
.ok_or(empty_metadata_location_err(&updated_table))?
334-
.to_string(),
335-
)?;
328+
root_namespace_state.update_table(updated_table.identifier(), new_metadata_location)?;
336329

337330
Ok(updated_table)
338331
}
@@ -341,10 +334,11 @@ impl Catalog for MemoryCatalog {
341334
fn apply_table_updates(
342335
table: &Table,
343336
updates: Vec<TableUpdate>,
344-
) -> Result<(TableMetadata, String)> {
345-
let metadata_location = table
346-
.metadata_location()
347-
.ok_or(empty_metadata_location_err(table))?;
337+
) -> Result<(TableMetadata, MetadataLocation)> {
338+
let metadata_location = table.metadata_location().ok_or(Error::new(
339+
ErrorKind::DataInvalid,
340+
format!("Table metadata location is not set: {}", table.identifier()),
341+
))?;
348342

349343
let mut builder = TableMetadataBuilder::new_from_metadata(
350344
table.metadata().clone(),
@@ -355,55 +349,11 @@ fn apply_table_updates(
355349
builder = update.apply(builder)?;
356350
}
357351

358-
let new_metadata_location = bump_metadata_version(metadata_location)?;
352+
let new_metadata_location = MetadataLocation::from_str(metadata_location)?.with_next_version();
359353

360354
Ok((builder.build()?.metadata, new_metadata_location))
361355
}
362356

363-
fn empty_metadata_location_err(table: &Table) -> Error {
364-
Error::new(
365-
ErrorKind::DataInvalid,
366-
format!("Table metadata location is not set: {}", table.identifier()),
367-
)
368-
}
369-
/// Parses a metadata location of format `<prefix>/metadata/<version>-<uuid>.metadata.json`,
370-
/// increments the version and generates a new UUID.
371-
/// It returns an error if the format is invalid.
372-
fn bump_metadata_version(metadata_location: &str) -> Result<String> {
373-
let (path, file_name) = metadata_location.rsplit_once('/').ok_or(Error::new(
374-
ErrorKind::Unexpected,
375-
format!("Invalid metadata location: {}", metadata_location),
376-
))?;
377-
378-
let prefix = path.strip_suffix("/metadata").ok_or(Error::new(
379-
ErrorKind::Unexpected,
380-
format!(
381-
"Metadata location not under /metadata/ subdirectory: {}",
382-
metadata_location
383-
),
384-
))?;
385-
386-
let (version, _id) = file_name
387-
.strip_suffix(".metadata.json")
388-
.ok_or(Error::new(
389-
ErrorKind::Unexpected,
390-
format!("Invalid metadata file ending: {}", file_name),
391-
))?
392-
.split_once('-')
393-
.ok_or(Error::new(
394-
ErrorKind::Unexpected,
395-
format!("Invalid metadata file name: {}", file_name),
396-
))?;
397-
398-
let new_version = version.parse::<i32>()? + 1;
399-
let new_id = Uuid::new_v4();
400-
401-
Ok(format!(
402-
"{}/metadata/{}-{}.metadata.json",
403-
prefix, new_version, new_id
404-
))
405-
}
406-
407357
#[cfg(test)]
408358
mod tests {
409359
use std::collections::HashSet;

0 commit comments

Comments
 (0)