Skip to content

Commit 5a157af

Browse files
Add config delete
1 parent 7f9d5a2 commit 5a157af

14 files changed

Lines changed: 459 additions & 6 deletions

File tree

configtest/bin/configtest.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,50 @@ static void test_get(
291291
}
292292
}
293293

294+
static void test_delete(GglList key_path, GglError expected_result) {
295+
GGL_LOGD(
296+
"test_delete %s, expecting %s",
297+
print_key_path(&key_path),
298+
ggl_strerror(expected_result)
299+
);
300+
GglBuffer server = GGL_STR("gg_config");
301+
302+
GglMap params = GGL_MAP({ GGL_STR("key_path"), GGL_OBJ_LIST(key_path) }, );
303+
304+
GglError remote_error = GGL_ERR_OK;
305+
GglError error = ggl_call(
306+
server, GGL_STR("delete"), params, &remote_error, NULL, NULL
307+
);
308+
if (expected_result != GGL_ERR_OK && error != GGL_ERR_REMOTE) {
309+
GGL_LOGE(
310+
"delete key %s expected result %s but there was not a remote error",
311+
print_key_path(&key_path),
312+
ggl_strerror(expected_result)
313+
);
314+
assert(0);
315+
}
316+
if (expected_result == GGL_ERR_OK && error != GGL_ERR_OK) {
317+
GGL_LOGE(
318+
"delete key %s did not expect error but got error %s and remote "
319+
"error %s",
320+
print_key_path(&key_path),
321+
ggl_strerror(error),
322+
ggl_strerror(remote_error)
323+
);
324+
assert(0);
325+
}
326+
if (remote_error != expected_result) {
327+
GGL_LOGE(
328+
"delete key %s expected result %s but got %s",
329+
print_key_path(&key_path),
330+
ggl_strerror(expected_result),
331+
ggl_strerror(remote_error)
332+
);
333+
assert(0);
334+
return;
335+
}
336+
}
337+
294338
static GglError subscription_callback(
295339
void *ctx, unsigned int handle, GglObject data
296340
) {
@@ -899,6 +943,68 @@ int main(int argc, char **argv) {
899943
GGL_ERR_OK
900944
);
901945

946+
// Test to ensure a key can be deleted, not affecting its parent
947+
test_insert(
948+
GGL_LIST(
949+
GGL_OBJ_BUF(GGL_STR("component13")), GGL_OBJ_BUF(GGL_STR("key"))
950+
),
951+
GGL_OBJ_BUF(GGL_STR("value")),
952+
-1,
953+
GGL_ERR_OK
954+
);
955+
test_delete(
956+
GGL_LIST(
957+
GGL_OBJ_BUF(GGL_STR("component13")), GGL_OBJ_BUF(GGL_STR("key"))
958+
),
959+
GGL_ERR_OK
960+
);
961+
test_get(
962+
GGL_LIST(
963+
GGL_OBJ_BUF(GGL_STR("component13")), GGL_OBJ_BUF(GGL_STR("key"))
964+
),
965+
GGL_OBJ_NULL(),
966+
GGL_ERR_NOENTRY
967+
);
968+
test_get(
969+
GGL_LIST(GGL_OBJ_BUF(GGL_STR("component13"))),
970+
GGL_OBJ_MAP(GGL_MAP()),
971+
GGL_ERR_OK
972+
);
973+
974+
// Test to ensure deletes are recursive
975+
test_insert(
976+
GGL_LIST(
977+
GGL_OBJ_BUF(GGL_STR("component14")),
978+
GGL_OBJ_BUF(GGL_STR("foo")),
979+
GGL_OBJ_BUF(GGL_STR("bar"))
980+
),
981+
GGL_OBJ_BUF(GGL_STR("value")),
982+
-1,
983+
GGL_ERR_OK
984+
);
985+
test_delete(GGL_LIST(GGL_OBJ_BUF(GGL_STR("component14"))), GGL_ERR_OK);
986+
test_get(
987+
GGL_LIST(
988+
GGL_OBJ_BUF(GGL_STR("component14")),
989+
GGL_OBJ_BUF(GGL_STR("foo")),
990+
GGL_OBJ_BUF(GGL_STR("bar"))
991+
),
992+
GGL_OBJ_NULL(),
993+
GGL_ERR_NOENTRY
994+
);
995+
test_get(
996+
GGL_LIST(
997+
GGL_OBJ_BUF(GGL_STR("component14")), GGL_OBJ_BUF(GGL_STR("foo"))
998+
),
999+
GGL_OBJ_NULL(),
1000+
GGL_ERR_NOENTRY
1001+
);
1002+
test_get(
1003+
GGL_LIST(GGL_OBJ_BUF(GGL_STR("component14"))),
1004+
GGL_OBJ_NULL(),
1005+
GGL_ERR_NOENTRY
1006+
);
1007+
9021008
// Test to ensure an empty map can be written and read
9031009
test_insert(
9041010
GGL_LIST(GGL_OBJ_BUF(GGL_STR("component15"))),
@@ -1004,6 +1110,55 @@ int main(int argc, char **argv) {
10041110
GGL_ERR_FAILURE
10051111
);
10061112

1113+
// Test to check subscriber behavior on deleted keys
1114+
test_insert(
1115+
GGL_LIST(
1116+
GGL_OBJ_BUF(GGL_STR("component20")),
1117+
GGL_OBJ_BUF(GGL_STR("foo")),
1118+
GGL_OBJ_BUF(GGL_STR("key"))
1119+
),
1120+
GGL_OBJ_BUF(GGL_STR("value1")),
1121+
-1,
1122+
GGL_ERR_OK
1123+
);
1124+
test_subscribe(
1125+
GGL_LIST(
1126+
GGL_OBJ_BUF(GGL_STR("component20")),
1127+
GGL_OBJ_BUF(GGL_STR("foo")),
1128+
GGL_OBJ_BUF(GGL_STR("key"))
1129+
),
1130+
GGL_ERR_OK
1131+
);
1132+
test_subscribe(
1133+
GGL_LIST(
1134+
GGL_OBJ_BUF(GGL_STR("component20")), GGL_OBJ_BUF(GGL_STR("foo"))
1135+
),
1136+
GGL_ERR_OK
1137+
);
1138+
test_delete(
1139+
GGL_LIST(
1140+
GGL_OBJ_BUF(GGL_STR("component20")),
1141+
GGL_OBJ_BUF(GGL_STR("foo")),
1142+
GGL_OBJ_BUF(GGL_STR("key"))
1143+
),
1144+
GGL_ERR_OK
1145+
);
1146+
test_insert(
1147+
GGL_LIST(
1148+
GGL_OBJ_BUF(GGL_STR("component20")),
1149+
GGL_OBJ_BUF(GGL_STR("foo")),
1150+
GGL_OBJ_BUF(GGL_STR("key"))
1151+
),
1152+
GGL_OBJ_BUF(GGL_STR("value2")),
1153+
-1,
1154+
GGL_ERR_OK
1155+
); // Should see one `read component20/foo/key` on the callback handle
1156+
// created for component20/foo
1157+
// Currently, the other subscription callback for component20/foo/key is not
1158+
// notified. In the future, it would be good to have that behavior too. See
1159+
// the docs/design/ggconfigd.md section "Subscription behavior for keys
1160+
// which become deleted" for more info.
1161+
10071162
// test_insert(
10081163
// GGL_LIST(GGL_OBJ_BUF(GGL_STR("component")),
10091164
// GGL_OBJ_BUF(GGL_STR("bar"))), GGL_OBJ_MAP(GGL_MAP({ GGL_STR("foo"),

core-bus-gg-config/include/ggl/core_bus/gg_config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ GglError ggl_gg_config_write(
2828
GglBufList key_path, GglObject value, const int64_t *timestamp
2929
);
3030

31+
/// Wrapper for core-bus `gg_config` `delete`
32+
GglError ggl_gg_config_delete(GglBufList key_path);
33+
3134
/// Wrapper for core-bus `gg_config` `subscribe`
3235
GglError ggl_gg_config_subscribe(
3336
GglBufList key_path,

core-bus-gg-config/src/gg_config.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,34 @@ GglError ggl_gg_config_read(
4444
return err;
4545
}
4646

47+
GglError ggl_gg_config_delete(GglBufList key_path) {
48+
if (key_path.len > GGL_MAX_OBJECT_DEPTH) {
49+
GGL_LOGE("Key path depth exceeds maximum handled.");
50+
return GGL_ERR_UNSUPPORTED;
51+
}
52+
53+
GglObject path_obj[GGL_MAX_OBJECT_DEPTH] = { 0 };
54+
for (size_t i = 0; i < key_path.len; i++) {
55+
path_obj[i] = GGL_OBJ_BUF(key_path.bufs[i]);
56+
}
57+
58+
GglMap args = GGL_MAP(
59+
{ GGL_STR("key_path"),
60+
GGL_OBJ_LIST((GglList) { .items = path_obj, .len = key_path.len }) },
61+
);
62+
63+
GglError remote_err = GGL_ERR_OK;
64+
GglError err = ggl_call(
65+
GGL_STR("gg_config"), GGL_STR("delete"), args, &remote_err, NULL, NULL
66+
);
67+
68+
if ((err == GGL_ERR_REMOTE) && (remote_err != GGL_ERR_OK)) {
69+
err = remote_err;
70+
}
71+
72+
return err;
73+
}
74+
4775
GglError ggl_gg_config_read_str(GglBufList key_path, GglBuffer *result) {
4876
GglObject result_obj;
4977
GglBumpAlloc alloc = ggl_bump_alloc_init(*result);

docs/spec/core-bus-interface/gg_config.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ The `write` method does not have a response value.
6464

6565
## delete
6666

67-
The `delete` method removes the key and value associated with `key_path`. If the
68-
value is a map with subkeys, everything under it is also deleted recursively.
67+
The `delete` method removes the key and value associated with `key_path`, if
68+
present. If the value is a map with subkeys, everything under it is also deleted
69+
recursively. If the key does not exist, nothing happens.
6970

7071
- [gg-config-delete-1] `delete` can be invoked with call or notify.
7172

@@ -80,7 +81,8 @@ value is a map with subkeys, everything under it is also deleted recursively.
8081
The `delete` method does not have a response value.
8182

8283
- [gg-config-delete-resp-1] If the method returns without an error, the
83-
configuration has been successfully deleted.
84+
configuration key does not exist, either because it was deleted or it didn't
85+
exist when the call was made.
8486

8587
## subscribe
8688

ggconfigd/include/ggconfigd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ GglError ggconfig_write_value_at_key(
2020
GglList *key_path, GglBuffer *value, int64_t timestamp
2121
);
2222
GglError ggconfig_write_empty_map(GglList *key_path);
23+
GglError ggconfig_delete_key(GglList *key_path);
2324
GglError ggconfig_get_value_from_key(GglList *key_path, GglObject *value);
2425
GglError ggconfig_get_key_notification(GglList *key_path, uint32_t handle);
2526
GglError ggconfig_open(void);

ggconfigd/src/db_corebus.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,37 @@ static GglError rpc_read(void *ctx, GglMap params, uint32_t handle) {
133133
return GGL_ERR_OK;
134134
}
135135

136-
static GglError rpc_subscribe(void *ctx, GglMap params, uint32_t handle) {
136+
static GglError rpc_delete(void *ctx, GglMap params, uint32_t handle) {
137137
(void) ctx;
138138

139-
GGL_LOGD("subscribing");
139+
GglObject *key_path;
140+
if (!ggl_map_get(params, GGL_STR("key_path"), &key_path)
141+
|| (key_path->type != GGL_TYPE_LIST)) {
142+
GGL_LOGE("read received invalid key_path argument.");
143+
return GGL_ERR_INVALID;
144+
}
145+
146+
GglError err = ggl_list_type_check(key_path->list, GGL_TYPE_BUF);
147+
if (err != GGL_ERR_OK) {
148+
GGL_LOGE("key_path elements must be strings.");
149+
return GGL_ERR_RANGE;
150+
}
151+
152+
GGL_LOGD(
153+
"Processing request to delete key %s (recursively)",
154+
print_key_path(&key_path->list)
155+
);
156+
err = ggconfig_delete_key(&key_path->list);
157+
if (err != GGL_ERR_OK) {
158+
return err;
159+
}
160+
161+
ggl_respond(handle, GGL_OBJ_NULL());
162+
return GGL_ERR_OK;
163+
}
164+
165+
static GglError rpc_subscribe(void *ctx, GglMap params, uint32_t handle) {
166+
(void) ctx;
140167

141168
GglObject *key_path;
142169
if (!ggl_map_get(params, GGL_STR("key_path"), &key_path)
@@ -301,6 +328,7 @@ void ggconfigd_start_server(void) {
301328
GglRpcMethodDesc handlers[]
302329
= { { GGL_STR("read"), false, rpc_read, NULL },
303330
{ GGL_STR("write"), false, rpc_write, NULL },
331+
{ GGL_STR("delete"), false, rpc_delete, NULL },
304332
{ GGL_STR("subscribe"), true, rpc_subscribe, NULL } };
305333
size_t handlers_len = sizeof(handlers) / sizeof(handlers[0]);
306334

0 commit comments

Comments
 (0)