/* * _genders_copy_attrvalslist * * Copy contents of the attrvalslist list into the handlecopy. * */ static int _genders_copy_attrvalslist(genders_t handle, genders_t handlecopy) { ListIterator attrvalslistitr = NULL; ListIterator attrvalsitr = NULL; genders_attrvals_container_t avc; genders_attrvals_container_t newavc = NULL; genders_attrval_t newav = NULL; int rv = -1; __list_iterator_create(attrvalslistitr, handle->attrvalslist); while ((avc = list_next(attrvalslistitr))) { genders_attrval_t av = NULL; __list_iterator_create(attrvalsitr, avc->attrvals); __xmalloc(newavc, genders_attrvals_container_t, sizeof(struct genders_attrvals_container)); __list_create(newavc->attrvals, _genders_list_free_genders_attrval); newavc->index = avc->index; while ((av = list_next(attrvalsitr))) { __xmalloc(newav, genders_attrval_t, sizeof(struct genders_attrval)); __xstrdup(newav->attr, av->attr); if (av->val) __xstrdup(newav->val, av->val); else newav->val = NULL; newav->val_contains_subst = av->val_contains_subst; __list_append(newavc->attrvals, newav); newav = NULL; } __list_append(handlecopy->attrvalslist, newavc); newavc = NULL; } rv = 0; cleanup: if (rv < 0) { if (newav) { free(newav->attr); free(newav->val); free(newav); } if (newavc) { __list_destroy(newavc->attrvals); free(newavc); } } __list_iterator_destroy(attrvalslistitr); __list_iterator_destroy(attrvalsitr); return rv; }
/* * _genders_copy_nodeslist * * Copy contents of the nodeslist list into the handlecopy. * */ static int _genders_copy_nodeslist(genders_t handle, genders_t handlecopy) { ListIterator itr = NULL; genders_node_t n = NULL; genders_node_t newn = NULL; int rv = -1; __list_iterator_create(itr, handle->nodeslist); while ((n = list_next(itr))) { __xmalloc(newn, genders_node_t, sizeof(struct genders_node)); __xstrdup(newn->name, n->name); __list_create(newn->attrlist, NULL); newn->attrcount = n->attrcount; newn->attrlist_index_size = n->attrlist_index_size; __hash_create(newn->attrlist_index, newn->attrlist_index_size, (hash_key_f)hash_key_string, (hash_cmp_f)strcmp, NULL); __list_append(handlecopy->nodeslist, newn); newn = NULL; } rv = 0; cleanup: if (rv < 0) { if (newn) { free(newn->name); __list_destroy(newn->attrlist); __hash_destroy(newn->attrlist_index); free(newn); } } __list_iterator_destroy(itr); return rv; }
int beginSlavery(int fd) { uint16_t randContext[3]; for(int i = 0; i < 3; i++) { randContext[i] = time(NULL) ^ getpid(); } int returnCode = -1; json_t* params = NULL; json_t* nextCommand = NULL; char** values = NULL; struct workerTask* tasks = NULL; uint32_t connPoolSize = 128; uint32_t connPoolCount = 0; void** connPool = __xmalloc(sizeof(void*) * connPoolSize); memset(connPool, 0, sizeof(void*) * connPoolSize); //recieve initial parameters params = readCommand(fd, 5000); if(!params) { fprintf(stderr, "No initialization packet\n"); goto exit; } //make sure the initial packet has all of the required info uint64_t slaveID; const char* command; const char* address; const char* username; const char* password; const char* tableName; int port; int errorChecking; int valueLength; int result = json_unpack(params, "{s:s, s:s, s:i, s:I, s:s, s:s, s:s, s:b, s:i}", "command", &command, "address", &address, "port", &port, "slave-id", &slaveID, "username", &username, "password", &password, "table", &tableName, "error-checking", &errorChecking, "value-length", &valueLength); if(result != 0 || strcmp(command, "init") || port <= 0 || port > 65535) { fprintf(stderr, "Invalid initialization packet recieved\n"); goto exit; } uint64_t numKeys = 0; //loop and execute commands from the master while(1) { nextCommand = readCommand(fd, 15000); if(!nextCommand) { fprintf(stderr, "Invalid next command\n"); goto exit; } const char* command; int result = json_unpack(nextCommand, "{s:s}", "command", &command); if(result == -1) { fprintf(stderr, "Packet missing command field\n"); goto exit; } //parse commands and modify keyRange array if needed struct workerTask task; if(!strcmp(command, "add")) { uint64_t numKeysToAdd; int result = json_unpack(nextCommand, "{s:I}", "amount", &numKeysToAdd); if(result == -1) { goto exit; } if(errorChecking) { values = __xrealloc(values, sizeof(char*) * (numKeys + numKeysToAdd)); for(uint64_t i = 0; i < numKeysToAdd; i++) { values[numKeys + i] = __xmalloc(valueLength + 1); for(int j = 0; j < valueLength; j++) { values[numKeys + i][j] = (erand48(randContext) * 26) + 'A'; } values[numKeys + i][valueLength] = '\0'; } } task.startingKey = slaveID + numKeys; task.numKeys = numKeysToAdd; task.type = kClientAddKeys; task.values = values; numKeys += task.numKeys; } else if(!strcmp(command, "remove")) { uint64_t numKeysToRemove; int result = json_unpack(nextCommand, "{s:I}", "amount", &numKeysToRemove); if(result == -1) { goto exit; } if(errorChecking) { uint64_t position = numKeys - numKeysToRemove; for(uint64_t i = 0; i < numKeysToRemove; i++) { free(values[position + i]); } values = __xrealloc(&values, sizeof(char*) * (numKeys - numKeysToRemove)); } if(numKeysToRemove > numKeys) { goto exit; } task.startingKey = slaveID + numKeys - numKeysToRemove; task.numKeys = numKeysToRemove; task.type = kClientRemoveKeys; task.values = NULL; numKeys -= numKeysToRemove; } else if(!strcmp(command, "test")) { json_t* array = json_object_get(nextCommand, "workload"); //right now we only need 1 workload type if(!(json_is_array(array) && json_array_size(array) == kWorkloadTypes)) { goto exit; } for(int i = 0; i < kWorkloadTypes; i++) { task.workloadComposition[i] = json_number_value(json_array_get(array, i)); } int result = json_unpack(nextCommand, "{s:I}", "amount", &task.count); if(result == -1) { goto exit; } task.startingKey = slaveID; task.numKeys = numKeys; task.values = values; task.type = kClientRunWorkload; } else if(!strcmp(command, "quit")) { returnCode = 0; goto exit; } else { fprintf(stderr, "unknown command from client: %s\n", command); goto exit; } int numClients; result = json_unpack(nextCommand, "{s:i, s:F}", "num-clients", &numClients, "throughput", &task.throughput); if(result == -1) { fprintf(stderr, "Packet missing number of clients or throughput value\n"); goto exit; } task.connOpenDelay = 0; //fill out the generic task information task.table = tableName; task.valueSize = valueLength; task.workerID = slaveID; task.hostname = address; task.username = username; task.password = password; task.port = port; //split the request between the clients while(numClients >= connPoolSize) { size_t oldSize = connPoolSize; connPoolSize *= 8; connPool = __xrealloc(connPool, connPoolSize * sizeof(void*)); memset(&connPool[oldSize], 0, sizeof(void*) * oldSize * 7); } if(numClients < connPoolCount) { for(int i = connPoolCount - 1; i >= numClients; i--) { storage_disconnect(connPool[i]); connPool[i] = NULL; } } tasks = __xmalloc(sizeof(struct workerTask) * numClients); splitTasks(&task, tasks, numClients, connPool); //perform the request json_t* requestResponse; performRequest(tasks, numClients, &requestResponse); //save the connections for next time for(int i = 0; i < numClients; i++) { connPool[i] = tasks[i].conn; } connPoolCount = numClients; //send the result back to the master char* serialResponse = json_dumps(requestResponse, JSON_COMPACT); json_decref(requestResponse); size_t len = strlen(serialResponse); if(len > 1048576) { fprintf(stderr, "Response too large (%zd)\n", len); free(serialResponse); goto exit; } char sizeBuf[9]; sprintf(sizeBuf, "%08d", (int)len); sendAll(fd, sizeBuf, 8); if(sendAll(fd, serialResponse, strlen(serialResponse)) == -1) { free(serialResponse); goto exit; } free(serialResponse); free(tasks); tasks = NULL; //free the parsed command json_decref(nextCommand); nextCommand = NULL; } exit: for(uint32_t i = 0; i < connPoolCount; i++) { storage_disconnect(connPool[i]); } free(connPool); free(tasks); json_decref(nextCommand); json_decref(params); if(values) { for(uint64_t i = 0; i < numKeys; i++) { free(values[i]); } free(values); } return returnCode; }
void performRequest(struct workerTask* tasks, int taskCount, json_t** result) { uint64_t* latencyResults = __xmalloc(sizeof(uint64_t) * kNumLatencyBuckets); memset(latencyResults, 0, sizeof(uint64_t) * kNumLatencyBuckets); //create a thread for each client pthread_t* threads = __xmalloc(sizeof(pthread_t) * taskCount); for(int i = 0; i < taskCount; i++) { //don't start a worker if it does'nt have any keys if(tasks[i].numKeys == 0) { taskCount = i; break; } tasks[i].latencyResults = latencyResults; //TODO - possibly reduce stack size for clients pthread_attr_t attributes; pthread_attr_init(&attributes); int result = pthread_attr_setstacksize(&attributes, 512*1024); if(result) { char buf[256]; strerror_r(result, buf, sizeof(buf)); fprintf(stderr, "Error setting stack size of thread: %s\n", buf); taskCount = i; break; } result = pthread_create(&threads[i], &attributes, testClient, &tasks[i]); if(result) { char buf[256]; strerror_r(result, buf, sizeof(buf)); fprintf(stderr, "Error creating thread %d: %s\n", i, buf); taskCount = i; break; } } //get the results //TODO add a timeout to allow the forceful killing of threads //create a json object to store the results *result = json_object(); json_t* errorArray = json_array(); json_t* resultArray = json_array(); json_object_set_new(*result, "errors", errorArray); json_object_set_new(*result, "latency", resultArray); for(int i = 0; i < taskCount; i++) { void* threadResult; pthread_join(threads[i], &threadResult); //returns a pointer to an error message - NULL means no error if(threadResult) { json_t* newError = json_object(); json_object_set_new(newError, "cause", json_string(threadResult)); json_object_set_new(newError, "client-id", json_integer(tasks[i].workerID)); json_array_append_new(errorArray, newError); } } //add the latency stats to the json object for(int i = 0; i < kNumLatencyBuckets; i++) { if(latencyResults[i]) { json_array_append_new(resultArray, json_integer(i)); json_array_append_new(resultArray, json_integer(latencyResults[i])); } } free(threads); free(latencyResults); }