bool Copy_Com__Seagate__Kinetic__Proto__Command__Range_to_ByteBufferArray(Com__Seagate__Kinetic__Proto__Command__Range* keyRange, ByteBufferArray* keys) { bool bufferOverflow = false; LOGF2("Copying: keyRange=0x%0llX, keys=0x%0llX, max_keys=%lld", keyRange, keys->buffers, keys->count); if (keyRange != NULL && keys->count > 0 && keys != NULL) { for (size_t i = 0; i < MIN((size_t)keys->count, (size_t)keyRange->n_keys); i++) { ByteBuffer_Reset(&keys->buffers[i]); if (ByteBuffer_Append(&keys->buffers[i], keyRange->keys[i].data, keyRange->keys[i].len) == NULL) { LOGF2("WANRNING: Buffer overrun for keys[%zd]", i); bufferOverflow = true; } } keys->used = keyRange->n_keys; } return !bufferOverflow; }
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 */ }
static void do_put_and_getkeyrange(KineticSession * const session) { for (int i = 0; i < 5; 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); } const size_t max_key_count = 5; const size_t max_key_length = 64; uint8_t first_key[max_key_length]; uint8_t last_key[max_key_length]; KineticKeyRange range = { .startKey = ByteBuffer_CreateAndAppendCString(first_key, sizeof(first_key), "key"), .endKey = ByteBuffer_CreateAndAppendCString(last_key, sizeof(last_key), "key\xFF"), .startKeyInclusive = true, .endKeyInclusive = true, .maxReturned = max_key_count, }; uint8_t key_mem[max_key_count][max_key_length]; memset(key_mem, 0, sizeof(key_mem)); ByteBuffer key_buffers[max_key_count]; for (size_t i = 0; i < max_key_count; i++) { key_buffers[i] = ByteBuffer_Create(&key_buffers[i], max_key_length, 0); } ByteBufferArray keys = { .buffers = key_buffers, .count = max_key_count, }; /* Request the key range as specified in &range, populating the keys in &keys. */ KineticStatus status = KineticClient_GetKeyRange(session, &range, &keys, NULL); printf("GetKeyRange status: %s\n", Kinetic_GetStatusDescription(status)); if (status == KINETIC_STATUS_SUCCESS) { for (size_t i = 0; i < max_key_count; i++) { printf("%zd: %s\n", i, key_buffers[i].array.data); } } /* 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); } do_put_and_getkeyrange(session); // Shutdown client connection and cleanup KineticClient_DestroySession(session); KineticClient_Shutdown(client); return 0; }
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); } // some dummy data to PUT uint8_t value_data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; ByteBuffer value = ByteBuffer_MallocAndAppend(value_data, sizeof(value_data)); // a dummy key uint8_t key_data[] = {0x00, 0x01, 0x02, 0x03, 0x04}; ByteBuffer key = ByteBuffer_MallocAndAppend(key_data, sizeof(key_data)); // Populate tag with SHA1 ByteBuffer tag = ByteBuffer_Malloc(20); uint8_t sha1[20]; SHA1(value.array.data, value.bytesUsed, &sha1[0]); ByteBuffer_Append(&tag, sha1, sizeof(sha1)); KineticEntry entry = { .key = key, .tag = tag, .algorithm = KINETIC_ALGORITHM_SHA1, .value = value, .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; // Do a blocking put to make sure there is something there to read back KineticStatus put_status = KineticClient_Put(session, &entry, NULL); if (put_status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Put failed w/status: %s\n", Kinetic_GetStatusDescription(put_status)); return 1; } // Create structure to populate with GET status in callback // a semaphore is used to notify the main thread that it's // safe to proceed. GetStatus get_status = { .sem = KineticSemaphore_Create(), .status = KINETIC_STATUS_INVALID, }; ByteBuffer getTag = ByteBuffer_Malloc(tag.bytesUsed); ByteBuffer getValue = ByteBuffer_Malloc(value.bytesUsed); // Because I'm passing a pointer to this entry to KineticClient_Put(), this entry must not // go out of scope until the GET completes KineticEntry get_entry = { .key = key, .tag = getTag, .algorithm = KINETIC_ALGORITHM_SHA1, .value = getValue, .force = true, }; status = KineticClient_Get( session, &get_entry, &(KineticCompletionClosure) { .callback = get_finished, .clientData = &get_status, } ); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Get failed w/status: %s\n", Kinetic_GetStatusDescription(status)); return 1; } // Wait for GET to finish KineticSemaphore_WaitForSignalAndDestroy(get_status.sem); if (get_status.status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "GET failed w/status: %s\n", Kinetic_GetStatusDescription(get_status.status)); return 1; } if ((value.bytesUsed == getValue.bytesUsed) && (memcmp(value.array.data, getValue.array.data, getValue.bytesUsed) != 0)) { fprintf(stderr, "GET completed but returned unexpected value"); return 1; } printf("GET completed successfully!\n"); // Free malloc'd buffers ByteBuffer_Free(value); ByteBuffer_Free(key); ByteBuffer_Free(tag); ByteBuffer_Free(getValue); ByteBuffer_Free(getTag); // Shutdown client connection and cleanup KineticClient_DestroySession(session); KineticClient_Shutdown(client); return 0; } static void get_finished(KineticCompletionData* kinetic_data, void* clientData) { GetStatus * get_status = clientData; // Save GET result status get_status->status = kinetic_data->status; // Signal that we're done KineticSemaphore_Signal(get_status->sem); }
static void do_put_and_get(KineticSession *session) { const char key[] = "key"; ByteBuffer put_key_buf = ByteBuffer_MallocAndAppend(key, strlen(key)); const uint8_t value[] = "value\x01\x02\x03\x04"; 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 "key" => "value\x01\x02\x03\x04". * 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)); /* Allocate a tag large enough for the SHA1. */ ByteBuffer get_tag_buf = ByteBuffer_Malloc(put_tag_buf.bytesUsed); /* Allocate a buffer large enough for the value. */ ByteBuffer get_value_buf = ByteBuffer_Malloc(put_value_buf.bytesUsed); KineticEntry get_entry = { .key = put_key_buf, .value = get_value_buf, .tag = get_tag_buf, .algorithm = KINETIC_ALGORITHM_SHA1, }; status = KineticClient_Get(session, &get_entry, NULL); printf("Get status: %s\n", Kinetic_GetStatusDescription(status)); printf("Get value: %zd bytes\n ", get_entry.value.bytesUsed); for (size_t i = 0; i < get_entry.value.bytesUsed; i++) { printf("%02x ", get_entry.value.array.data[i]); } printf(" "); for (size_t i = 0; i < get_entry.value.bytesUsed; i++) { char c = get_entry.value.array.data[i]; printf("%c", isprint(c) ? c : '.'); } printf("\n"); /* Cleanup */ ByteBuffer_Free(put_key_buf); ByteBuffer_Free(put_value_buf); ByteBuffer_Free(put_tag_buf); ByteBuffer_Free(get_entry.value); ByteBuffer_Free(get_tag_buf); }
ByteArray ProtobufCBinaryData_to_ByteArray( ProtobufCBinaryData protoData) { return (ByteArray) { .data = protoData.data, .len = protoData.len }; } bool Copy_ProtobufCBinaryData_to_ByteBuffer(ByteBuffer dest, ProtobufCBinaryData src) { if (src.data == NULL || src.len == 0) { return false; } if (dest.array.data == NULL || dest.array.len < src.len) { return false; } bool success = (memcpy(dest.array.data, src.data, src.len) == dest.array.data); if (success) { dest.bytesUsed = src.len; } return success; } bool Copy_Com__Seagate__Kinetic__Proto__Command__KeyValue_to_KineticEntry(Com__Seagate__Kinetic__Proto__Command__KeyValue* key_value, KineticEntry* entry) { bool bufferOverflow = false; if (key_value != NULL && entry != NULL) { ByteBuffer_Reset(&entry->dbVersion); if (key_value->has_dbversion && key_value->dbversion.len > 0) { if (entry->dbVersion.array.data == NULL || entry->dbVersion.array.len < key_value->dbversion.len) { entry->dbVersion.bytesUsed = key_value->dbversion.len; LOG1(" BUFFER_OVERRUN: dbVersion"); bufferOverflow = true; } else { ByteBuffer_Append(&entry->dbVersion, key_value->dbversion.data, key_value->dbversion.len); } } ByteBuffer_Reset(&entry->key); if (key_value->has_key && key_value->key.len > 0) { if (entry->key.array.data == NULL || entry->key.array.len < key_value->key.len) { entry->key.bytesUsed = key_value->key.len; LOG1(" BUFFER_OVERRUN: key"); bufferOverflow = true; } else { ByteBuffer_Append(&entry->key, key_value->key.data, key_value->key.len); } } ByteBuffer_Reset(&entry->tag); if (key_value->has_tag && key_value->tag.len > 0) { if (entry->tag.array.data == NULL || entry->tag.array.len < key_value->tag.len) { entry->tag.bytesUsed = key_value->tag.len; LOG1(" BUFFER_OVERRUN: tag"); bufferOverflow = true; } else { ByteBuffer_Append(&entry->tag, key_value->tag.data, key_value->tag.len); } } if (key_value->has_algorithm) { entry->algorithm = KineticAlgorithm_from_Com__Seagate__Kinetic__Proto__Command__Algorithm( key_value->algorithm); } } return !bufferOverflow; }
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; }