Skip to content

Commit

Permalink
Support in place update of group members (#3928) (#3940)
Browse files Browse the repository at this point in the history
This adds support for updating group members. We also modify the on disk format for a v2 group members in group details to facilitate the new updating support. A new API is not added in this PR but the act of removing and adding in the same group open is now supported.

I've also reshuffled the code to add a new GroupDetails object which is a missing layer of abstraction from the previous group implementation. This separates the on-disk format (GroupDetails) from the overarching group class.

---
TYPE: FEATURE
DESC: Support in place update of group members

Co-authored-by: Seth Shelnutt <[email protected]>
  • Loading branch information
github-actions[bot] and Shelnutt2 authored Mar 3, 2023
1 parent 5b3d42d commit 1fb59c4
Show file tree
Hide file tree
Showing 25 changed files with 1,457 additions and 465 deletions.
9 changes: 7 additions & 2 deletions format_spec/group.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Group

A group consists of [metadata](./metadata.md) and a file containing group members
A group consists of [metadata](./metadata.md) and a file containing group members.

The current group format version is `2`.

```
my_group # Group folder
Expand All @@ -24,7 +26,9 @@ my_group # Group folder

## Group Member

The group member is the content inside a [group](./group.md)
The group member is the content inside a [group](./group.md).

The current group member format version is `2`.

| **Field** | **Type** | **Description** |
| :--- | :--- | :--- |
Expand All @@ -33,3 +37,4 @@ The group member is the content inside a [group](./group.md)
| Relative | `uint8_t` | Is the URI relative to the group |
| URI length | `uint32_t` | Number of characters in URI |
| URI | `uint8_t[]` | URI character array |
| Deleted | `uint8_t` | Is the member deleted |
132 changes: 123 additions & 9 deletions test/src/unit-capi-group.cc
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ TEST_CASE_METHOD(
tiledb_group_put_metadata(ctx_, group, "key", TILEDB_INT32, 1, &v);
CHECK(rc == TILEDB_ERR);

// Write metadata on an group opened in READ mode
// Write metadata on a group opened in READ mode
set_group_timestamp(group, 1);
rc = tiledb_group_open(ctx_, group, TILEDB_READ);
REQUIRE(rc == TILEDB_OK);
Expand Down Expand Up @@ -630,6 +630,99 @@ TEST_CASE_METHOD(
remove_temp_dir(temp_dir);
}

TEST_CASE_METHOD(
GroupFx,
"C API: Group, write/read/update with named members",
"[capi][group][metadata][read]") {
// Create and open group in write mode
// TODO: refactor for each supported FS.
std::string temp_dir = fs_vec_[0]->temp_dir();
create_temp_dir(temp_dir);

const tiledb::sm::URI array1_uri(temp_dir + "array1");
const tiledb::sm::URI array2_uri(temp_dir + "array2");
create_array(array1_uri.to_string());
create_array(array2_uri.to_string());

tiledb::sm::URI group1_uri(temp_dir + "group1");
REQUIRE(tiledb_group_create(ctx_, group1_uri.c_str()) == TILEDB_OK);

// Set expected
std::vector<std::pair<tiledb::sm::URI, tiledb_object_t>> group1_expected = {
{array1_uri, TILEDB_ARRAY},
};

std::vector<std::pair<tiledb::sm::URI, tiledb_object_t>>
group1_expected_modified = {
{array2_uri, TILEDB_ARRAY},
};

tiledb_group_t* group1;
int rc = tiledb_group_alloc(ctx_, group1_uri.c_str(), &group1);
REQUIRE(rc == TILEDB_OK);
set_group_timestamp(group1, 1);
rc = tiledb_group_open(ctx_, group1, TILEDB_WRITE);
REQUIRE(rc == TILEDB_OK);

rc = tiledb_group_add_member(ctx_, group1, array1_uri.c_str(), false, "one");
REQUIRE(rc == TILEDB_OK);

// Close group from write mode
rc = tiledb_group_close(ctx_, group1);
REQUIRE(rc == TILEDB_OK);

// Reopen in read mode
rc = tiledb_group_open(ctx_, group1, TILEDB_READ);
REQUIRE(rc == TILEDB_OK);

uint8_t is_relative = 255;
rc = tiledb_group_get_is_relative_uri_by_name(
ctx_, group1, "one", &is_relative);
REQUIRE(rc == TILEDB_OK);
REQUIRE(is_relative == 0);

std::vector<std::pair<tiledb::sm::URI, tiledb_object_t>> group1_received =
read_group(group1);
REQUIRE_THAT(
group1_received, Catch::Matchers::UnorderedEquals(group1_expected));

// Close group
rc = tiledb_group_close(ctx_, group1);
REQUIRE(rc == TILEDB_OK);

// Remove assets from group
set_group_timestamp(group1, 2);
rc = tiledb_group_open(ctx_, group1, TILEDB_WRITE);
REQUIRE(rc == TILEDB_OK);

// Remove one
rc = tiledb_group_remove_member(ctx_, group1, "one");
REQUIRE(rc == TILEDB_OK);
// Add one back with different URI
rc = tiledb_group_add_member(ctx_, group1, array2_uri.c_str(), false, "one");
REQUIRE(rc == TILEDB_OK);

// Close group
rc = tiledb_group_close(ctx_, group1);
REQUIRE(rc == TILEDB_OK);

// Check read again
set_group_timestamp(group1, 2);
rc = tiledb_group_open(ctx_, group1, TILEDB_READ);
REQUIRE(rc == TILEDB_OK);

group1_received = read_group(group1);
REQUIRE_THAT(
group1_received,
Catch::Matchers::UnorderedEquals(group1_expected_modified));

// Close group
rc = tiledb_group_close(ctx_, group1);
REQUIRE(rc == TILEDB_OK);
tiledb_group_free(&group1);
remove_temp_dir(temp_dir);
}

TEST_CASE_METHOD(
GroupFx,
"C API: Group, write/read with named members",
Expand Down Expand Up @@ -1446,22 +1539,40 @@ TEST_CASE_METHOD(
REQUIRE_THAT(
group2_received, Catch::Matchers::UnorderedEquals(group2_expected));

// These tests are commented out because we need to introduce c-api
// serialization for the GroupUpdate structure
/*
// Now that we validated the groups were written correctly
// lets test taking a read, serializing it and writing
rc = tiledb_group_alloc(ctx_, group3_uri.c_str(), &group3_write_deserialized);
REQUIRE(rc == TILEDB_OK);
set_group_timestamp(group3_write_deserialized, 2);
set_group_timestamp(group3_write_deserialized, 3);
rc = tiledb_group_open(ctx_, group3_write_deserialized, TILEDB_WRITE);
REQUIRE(rc == TILEDB_OK);
// Setup serialized write with removed member
// Remove assets from group
tiledb_group_t* group3_write_setup;
rc = tiledb_group_alloc(ctx_, group3_uri.c_str(), &group3_write_setup);
REQUIRE(rc == TILEDB_OK);
set_group_timestamp(group3_write_setup, 2);
rc = tiledb_group_open(ctx_, group3_write_setup, TILEDB_WRITE);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_group_remove_member(ctx_, group3_write_setup, group2_uri.c_str());
REQUIRE(rc == TILEDB_OK);
// Close so changes are applied
rc = tiledb_group_close(ctx_, group3_write_setup);
rc = tiledb_group_serialize(
ctx_, group1_read, group3_write_deserialized, TILEDB_JSON);
ctx_, group3_write_setup, group3_write_deserialized, TILEDB_JSON);
REQUIRE(rc == TILEDB_OK);
// Close deserialized write group
rc = tiledb_group_close(ctx_, group3_write_deserialized);
REQUIRE(rc == TILEDB_OK);
tiledb_group_free(&group3_write_deserialized);
tiledb_group_free(&group3_write_setup);
rc = tiledb_group_alloc(ctx_, group4_uri.c_str(), &group4_write_deserialized);
REQUIRE(rc == TILEDB_OK);
Expand All @@ -1479,30 +1590,33 @@ TEST_CASE_METHOD(
tiledb_group_free(&group4_write_deserialized);
// Check deserialized group3
set_group_timestamp(group3_read, 2);
set_group_timestamp(group3_read, 3);
rc = tiledb_group_open(ctx_, group3_read, TILEDB_READ);
REQUIRE(rc == TILEDB_OK);
group3_received = read_group(group3_read);
REQUIRE_THAT(
group3_received, Catch::Matchers::UnorderedEquals(group3_expected));
// Check deserialized group4
set_group_timestamp(group4_read, 2);
set_group_timestamp(group4_read, 3);
rc = tiledb_group_open(ctx_, group4_read, TILEDB_READ);
REQUIRE(rc == TILEDB_OK);
group4_received = read_group(group4_read);
REQUIRE_THAT(
group4_received, Catch::Matchers::UnorderedEquals(group4_expected));
*/

// Close group
rc = tiledb_group_close(ctx_, group1_read);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_group_close(ctx_, group2_read);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_group_close(ctx_, group3_read);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_group_close(ctx_, group4_read);
REQUIRE(rc == TILEDB_OK);
/*
rc = tiledb_group_close(ctx_, group3_read);
REQUIRE(rc == TILEDB_OK);
rc = tiledb_group_close(ctx_, group4_read);
REQUIRE(rc == TILEDB_OK);
*/
tiledb_group_free(&group1_read);
tiledb_group_free(&group2_read);
tiledb_group_free(&group3_read);
Expand Down
5 changes: 4 additions & 1 deletion tiledb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,13 @@ set(TILEDB_CORE_SOURCES
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/global_state/signal_handlers.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/global_state/watchdog.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_details.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_details_v1.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_details_v2.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_directory.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_member.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_member_v1.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_v1.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/group/group_member_v2.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/metadata/metadata.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/misc/cancelable_tasks.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/misc/constants.cc
Expand Down
4 changes: 2 additions & 2 deletions tiledb/api/c_api/group/group_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "tiledb/api/c_api_support/c_api_support.h"
#include "tiledb/sm/c_api/tiledb_serialization.h"
#include "tiledb/sm/enums/serialization_type.h"
#include "tiledb/sm/group/group_v1.h"
#include "tiledb/sm/group/group_details_v1.h"
#include "tiledb/sm/serialization/array.h"
#include "tiledb/sm/serialization/group.h"

Expand Down Expand Up @@ -95,7 +95,7 @@ capi_return_t tiledb_group_alloc(
auto uri = tiledb::sm::URI(group_uri);
if (uri.is_invalid()) {
throw CAPIStatusException(
"Failed to create TileDB group object; Invalid URI");
"Failed to allocate TileDB group API object; Invalid URI");
}

*group = tiledb_group_handle_t::make_handle(uri, ctx->storage_manager());
Expand Down
5 changes: 2 additions & 3 deletions tiledb/api/c_api/group/group_api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#include "../../c_api_support/handle/handle.h"
#include "../error/error_api_internal.h"
#include "tiledb/sm/group/group.h"
#include "tiledb/sm/group/group_v1.h"

struct tiledb_group_handle_t
: public tiledb::api::CAPIHandle<tiledb_group_handle_t> {
Expand All @@ -46,7 +45,7 @@ struct tiledb_group_handle_t
static constexpr std::string_view object_type_name{"group"};

private:
tiledb::sm::GroupV1 group_;
tiledb::sm::Group group_;

public:
tiledb_group_handle_t() = delete;
Expand All @@ -62,7 +61,7 @@ struct tiledb_group_handle_t

[[nodiscard]] inline tiledb::sm::Group& group() const {
return static_cast<tiledb::sm::Group&>(
const_cast<tiledb::sm::GroupV1&>(group_));
const_cast<tiledb::sm::Group&>(group_));
}
};

Expand Down
6 changes: 3 additions & 3 deletions tiledb/sm/consolidator/group_meta_consolidator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include "tiledb/sm/enums/datatype.h"
#include "tiledb/sm/enums/query_type.h"
#include "tiledb/sm/group/group.h"
#include "tiledb/sm/group/group_v1.h"
#include "tiledb/sm/group/group_details_v1.h"
#include "tiledb/sm/misc/parallel_functions.h"
#include "tiledb/sm/stats/global_stats.h"
#include "tiledb/sm/storage_manager/storage_manager.h"
Expand Down Expand Up @@ -75,12 +75,12 @@ Status GroupMetaConsolidator::consolidate(

// Open group for reading
auto group_uri = URI(group_name);
GroupV1 group_for_reads(group_uri, storage_manager_);
Group group_for_reads(group_uri, storage_manager_);
RETURN_NOT_OK(group_for_reads.open(
QueryType::READ, config_.timestamp_start_, config_.timestamp_end_));

// Open group for writing
GroupV1 group_for_writes(group_uri, storage_manager_);
Group group_for_writes(group_uri, storage_manager_);
RETURN_NOT_OK_ELSE(
group_for_writes.open(QueryType::WRITE),
throw_if_not_ok(group_for_reads.close()));
Expand Down
2 changes: 1 addition & 1 deletion tiledb/sm/group/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ include(common NO_POLICY_SCOPE)
# linked standalone. As a result, this library is not defined with
# `commence(object_library)`, since that mandates a link-completeness test.
#
add_library(group OBJECT group_directory.cc group.cc group_member.cc group_v1.cc group_member_v1.cc)
add_library(group OBJECT group_directory.cc group.cc group_details.cc group_details_v1.cc group_details_v2.cc group_member.cc group_member_v1.cc group_member_v2.cc)
target_link_libraries(group PUBLIC baseline $<TARGET_OBJECTS:baseline>)
target_link_libraries(group PUBLIC buffer $<TARGET_OBJECTS:buffer>)

Expand Down
Loading

0 comments on commit 1fb59c4

Please sign in to comment.