static bool add_keys(int count) { static const ssize_t sz = 10; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; for (int i = 0; i < count; i++) { KineticEntry entry = { .key = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_%d", i), .tag = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag_%d", i), .value = ByteBuffer_CreateAndAppendFormattedCString(value_buf, sz, "val_%d", i), .algorithm = KINETIC_ALGORITHM_SHA1, .force = true, }; KineticStatus status = KineticClient_Put(Fixture.session, &entry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); } return true; } typedef enum { CMD_NEXT, CMD_PREVIOUS } GET_CMD; static void compare_against_offset_key(GET_CMD cmd, bool metadataOnly) { static const ssize_t sz = 10; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; char key_exp_buf[sz]; char value_exp_buf[sz]; const int count = 3; TEST_ASSERT_TRUE(add_keys(count)); /* add keys [key_X -> test_X] */ int low = 0; int high = count; int8_t offset = 0; switch (cmd) { case CMD_NEXT: low = 1; offset = -1; break; case CMD_PREVIOUS: high = count - 1; offset = +1; break; default: TEST_ASSERT(false); } for (int i = low; i < high; i++) { ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_%d", i + offset); ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag_%d", i + offset); ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0); printf("KEY '%s'\n", key_buf); KineticEntry entry = { .key = keyBuffer, .tag = tagBuffer, .value = valueBuffer, .algorithm = KINETIC_ALGORITHM_SHA1, .metadataOnly = metadataOnly, }; KineticStatus status = KINETIC_STATUS_INVALID; switch (cmd) { case CMD_NEXT: status = KineticClient_GetNext(Fixture.session, &entry, NULL); break; case CMD_PREVIOUS: status = KineticClient_GetPrevious(Fixture.session, &entry, NULL); break; default: TEST_ASSERT(false); } TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); ByteBuffer expectedKeyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_exp_buf, sz, "key_%d", i); ByteBuffer expectedValueBuffer = ByteBuffer_CreateAndAppendFormattedCString(value_exp_buf, sz, "val_%d", i); TEST_ASSERT_EQUAL_ByteBuffer(expectedKeyBuffer, entry.key); if (!metadataOnly) { TEST_ASSERT_EQUAL_ByteBuffer(expectedValueBuffer, entry.value); } } } void test_GetNext_should_retrieve_object_and_metadata_from_device(void) { compare_against_offset_key(CMD_NEXT, false); }
static void do_put_and_getprevious_getnext(KineticSession *session) { for (int i = 0; i < 3; i++) { char key[] = "keyX"; key[3] = '0' + i; ByteBuffer put_key_buf = ByteBuffer_MallocAndAppend(key, strlen(key)); uint8_t value[] = "valueX"; value[5] = '0' + i; ByteBuffer put_value_buf = ByteBuffer_MallocAndAppend(value, sizeof(value)); /* Populate tag with SHA1 of value */ ByteBuffer put_tag_buf = ByteBuffer_Malloc(20); uint8_t sha1[20]; SHA1(put_value_buf.array.data, put_value_buf.bytesUsed, &sha1[0]); ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1)); KineticEntry put_entry = { .key = put_key_buf, .value = put_value_buf, .tag = put_tag_buf, .algorithm = KINETIC_ALGORITHM_SHA1, /* Set sync to WRITETHROUGH, which will wait to complete * until the drive has persistend the write. (WRITEBACK * returns as soon as the drive has buffered the write.) */ .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; /* Put "keyX" => "valueX", where 'X' is 0..4. * This will block, because the callback field (arg 3) is NULL. */ KineticStatus status = KineticClient_Put(session, &put_entry, NULL); printf("Put status: %s\n", Kinetic_GetStatusDescription(status)); ByteBuffer_Free(put_key_buf); ByteBuffer_Free(put_value_buf); ByteBuffer_Free(put_tag_buf); } printf("\n\n\n"); for (int i = 1; i < 3; i++) { KineticStatus status = KINETIC_STATUS_INVALID; static const ssize_t sz = 100; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key%d", i); ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag%d", i); ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0); KineticEntry entry = { .key = keyBuffer, .tag = tagBuffer, .value = valueBuffer, .algorithm = KINETIC_ALGORITHM_SHA1, }; if (i > 0) { status = KineticClient_GetPrevious(session, &entry, NULL); printf("GetPrevious status: %s\n", Kinetic_GetStatusDescription(status)); if (status == KINETIC_STATUS_SUCCESS) { printf("Previous key before 'key%d': '%s', value '%s'\n", i, key_buf, value_buf); } } } for (int i = 0; i < 2; i++) { KineticStatus status = KINETIC_STATUS_INVALID; static const ssize_t sz = 100; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key%d", i); ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag%d", i); ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0); KineticEntry entry = { .key = keyBuffer, .tag = tagBuffer, .value = valueBuffer, .algorithm = KINETIC_ALGORITHM_SHA1, }; if (i < 2) { status = KineticClient_GetNext(session, &entry, NULL); printf("GetNext status: %s\n", Kinetic_GetStatusDescription(status)); if (status == KINETIC_STATUS_SUCCESS) { printf("Next key after 'key%d': '%s', value '%s'\n", i, key_buf, value_buf); } } } /* No cleanup necessary */ }
int main(int argc, char** argv) { (void)argc; (void)argv; // Initialize kinetic-c and configure sessions KineticSession* session; KineticClientConfig clientConfig = { .logFile = "stdout", .logLevel = 1, }; KineticClient * client = KineticClient_Init(&clientConfig); if (client == NULL) { return 1; } const char HmacKeyString[] = "asdfasdf"; KineticSessionConfig sessionConfig = { .host = "localhost", .port = KINETIC_PORT, .clusterVersion = 0, .identity = 1, .hmacKey = ByteArray_CreateWithCString(HmacKeyString), }; KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n", Kinetic_GetStatusDescription(status)); exit(1); } // Create some entries so that we can query the keys printf("Storing some entries on the device...\n"); const size_t numKeys = 3; if (!create_entries(session, numKeys)) { return 2; } // Query a range of keys const size_t keyLen = 64; uint8_t startKeyData[keyLen], endKeyData[keyLen]; KineticKeyRange range = { .startKey = ByteBuffer_CreateAndAppendCString(startKeyData, sizeof(startKeyData), "key_prefix_00"), .endKey = ByteBuffer_CreateAndAppendCString(endKeyData, sizeof(endKeyData), "key_prefix_01"), .startKeyInclusive = true, .endKeyInclusive = true, .maxReturned = 3, }; uint8_t keysData[numKeys][keyLen]; ByteBuffer keyBuff[] = { ByteBuffer_Create(&keysData[0], keyLen, 0), ByteBuffer_Create(&keysData[1], keyLen, 0), ByteBuffer_Create(&keysData[2], keyLen, 0), }; ByteBufferArray keys = {.buffers = &keyBuff[0], .count = numKeys}; status = KineticClient_GetKeyRange(session, &range, &keys, NULL); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "FAILURE: Failed retrieving key range from device!\n"); return 3; } if (keys.used != 2) { fprintf(stderr, "FAILURE: Unexpected number of keys in returned range!\n"); return 4; }; if (keyBuff[0].bytesUsed != strlen("key_prefix_00")) { fprintf(stderr, "FAILURE: Key 0 length check failed!\n"); return 4; } if (keyBuff[1].bytesUsed != strlen("key_prefix_01")) { fprintf(stderr, "FAILURE: Key 1 length check failed!\n"); return 4; } if (keyBuff[2].bytesUsed != 0) { fprintf(stderr, "FAILURE: Key 2 was not empty as expected!\n"); return 4; } // Shutdown client connection and cleanup KineticClient_DestroySession(session); KineticClient_Shutdown(client); printf("Key range retrieved successfully!\n"); return 0; } static bool create_entries(KineticSession * const session, const int count) { static const ssize_t sz = 20; char key_buf[sz]; char value_buf[sz]; for (int i = 0; i < count; i++) { ByteBuffer KeyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_prefix_%02d", i); ByteBuffer ValueBuffer = ByteBuffer_CreateAndAppendFormattedCString(value_buf, sz, "val_%02d", i); /* Populate tag with SHA1 of value */ ByteBuffer put_tag_buf = ByteBuffer_Malloc(20); uint8_t sha1[20]; SHA1(ValueBuffer.array.data, ValueBuffer.bytesUsed, &sha1[0]); ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1)); KineticEntry entry = { .key = KeyBuffer, .value = ValueBuffer, .tag = put_tag_buf, .algorithm = KINETIC_ALGORITHM_SHA1, .force = true, .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; KineticStatus status = KineticClient_Put(session, &entry, NULL); if (KINETIC_STATUS_SUCCESS != status) { return false; } } return true; }