int main(int argc, const  char* argv[] ) {
	char key[KEY_SIZE], value[KEY_SIZE], value2[KEY_SIZE];
	char* v;
	int i,j;
	int client_id=0;

	kos_init(1,1,NUM_SHARDS);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=NUM_EL; i>=0; i--) {
			sprintf(key, "k%d",i);
			sprintf(value, "val:%d",i);
			DEBUG("Element <%s,%s> being inserted in shard %d....\n", key, value, j);
			fflush(stdin);
			v=kos_put(client_id,j, key,value);
			if (v!=NULL) {
				printf("TEST FAILED - SHOULD RETURN NULL AND HAS RETURNED %s",v);
				exit(-1);
			}
		}
	}

	printf("------------------ ended inserting --------------------------------\n");

	for (j=0; j<NUM_SHARDS; j++) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k%d",i);
			sprintf(value, "val:%d",i);
			v=kos_get(client_id,j, key);
			if (v==NULL || strncmp(v,value,KEY_SIZE)!=0) {
				printf("TEST FAILED - Error on key %s, shard %d value should be %s and was returned %s",key,j,value,v);
				exit(-1);
			}			
		}
	}
	
	printf("------------------- ended querying -------------------------------\n");


	printf("\n--> TEST PASSED <--\n");

	return 0;
}
void *client_thread(void *arg) {

	char key[KEY_SIZE], value[KEY_SIZE], value2[KEY_SIZE];
	char* v;
	int i,j;
	int client_id=*( (int*)arg);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=NUM_EL; i>=0; i--) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i);
			v=kos_put(client_id, j, key,value);
			DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("------------------- %d:1/2 ENDED INSERTING -----------------------\n",client_id);

	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i);
			v=kos_get(client_id, j, key);
			if (strncmp(v,value,KEY_SIZE)!=0) {
				printf("Error on key %s value should be %s and was returned %s",key,value,v);
				exit(1);
			}
			DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),j,
									( v==NULL ? "<missing>" : v ) );
	
		}
	}
	
	printf("------------------ %d:2/2 ENDED READING  ---------------------\n",client_id);



	return NULL;
}
void *client_thread(void *arg) {

	char key[KEY_SIZE], value[KEY_SIZE];
	char* v;
	int i;
	long now, time();
	char *ctime();
	int client_id=*( (int*)arg);
	KV_t* dump;


/* 3 different sequences put-get-remove:
	1 - each client thread invokes a different shard
	2 - all client threads invoke the same shard
	3 - all client threads colide in a few list of the same shard */


/* 1st sequence - Each client thread generates requests for its "own" different shard */
	if(client_id==0) {
		time(&now);
		printf("STEP 1 - EACH CLIENT REQUESTS ITS OWN SHARD @ %s\n", ctime (&now));
	}


	for (i=NUM_EL-1; i>=0; i--) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_put(client_id, client_id%NUM_SHARDS, key,value);
		DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
	}

	printf("------------------- %d:1/7 ENDED INSERTING -----------------------\n",client_id);

	for (i=0; i<NUM_EL; i++) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_get(client_id, client_id%NUM_SHARDS, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error on key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );	
	}

	
	printf("------------------ %d:2/7 ENDED READING  ---------------------\n",client_id);


	for (i=NUM_EL-1; i>=0; i--) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_remove(client_id, client_id%NUM_SHARDS, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error when removing key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s removed from shard %d. value =%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );
	}



	printf("----------------- %d-4/7 ENDED REMOVING -------------------------\n",client_id);



/* 2nd sequence - All client threads generate requests for the same shard (0) */
if(client_id==0) {
		time(&now);
		printf("STEP 2 - ALL CLIENTS REQUEST THE SAME SHARD @ %s\n", ctime (&now));
	}



	for (i=NUM_EL-1; i>=0; i--) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_put(client_id, 0, key,value);
		DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
	}

	printf("------------------- %d:1/7 ENDED INSERTING -----------------------\n",client_id);

	for (i=0; i<NUM_EL; i++) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_get(client_id, 0, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error on key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );	
	}

	
	printf("------------------ %d:2/7 ENDED READING  ---------------------\n",client_id);


	for (i=NUM_EL-1; i>=0; i--) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_remove(client_id, 0, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error when removing key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s removed from shard %d. value =%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );
	}



	printf("----------------- %d-4/7 ENDED REMOVING -------------------------\n",client_id);




/* 3rd sequence - All client threads generate requests for the same list in the same shard - more contention */
if(client_id==0) {
		time(&now);
		printf("STEP 3 - ALL CLIENTS REQUEST THE SAME LIST IN THE SAME SHARD @ %s\n", ctime (&now));
	}



	for (i=NUM_EL-1; i>=0; i--) {
		sprintf(key, "k-c%d-%d",client_id+10, de_hash(client_id,i));
		sprintf(value, "val:%d",i);
		v=kos_put(client_id, 0, key,value);
		DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
	}

	printf("------------------- %d:1/7 ENDED INSERTING -----------------------\n",client_id);

	for (i=0; i<NUM_EL; i++) {
		sprintf(key, "k-c%d-%d",client_id+10, de_hash(client_id,i));
		sprintf(value, "val:%d",i);
		v=kos_get(client_id, 0, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error on key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );	
	}

	
	printf("------------------ %d:2/7 ENDED READING  ---------------------\n",client_id);


	for (i=NUM_EL-1; i>=0; i--) {
		sprintf(key, "k-c%d-%d",client_id+10, de_hash(client_id,i));
		sprintf(value, "val:%d",i);
		v=kos_remove(client_id, 0, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error when removing key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s removed from shard %d. value =%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );
	}



	printf("----------------- %d-4/7 ENDED REMOVING -------------------------\n",client_id);




	return NULL;
}
void *client_thread(void *arg) {

	char key[KEY_SIZE], value[KEY_SIZE], value2[KEY_SIZE];
	char* v;
	int i,dim;
	int client_id=*( (int*)arg);
	KV_t* dump;

// Check if shard is empty or already written. Check the first <key,value> usually inserted //
	i=0;
	sprintf(key, "k-c%d-%d", client_id, i);
	sprintf(value, "val:%d", i);
	v=kos_get(client_id, client_id, key);

	if (v == NULL) {
		printf("Shard seems to be empty - Run all tests 1 to 6");
		// Otherwise goes directly to test 7 - the final getAllKeys //


	for (i=NUM_EL-1; i>=0; i--) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_put(client_id, client_id, key,value);
		DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
	}

	printf("------------------- %d:1/7 ENDED INSERTING -----------------------\n",client_id);

	for (i=0; i<NUM_EL; i++) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_get(client_id, client_id, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error on key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );	
	}

	
	printf("------------------ %d:2/7 ENDED READING  ---------------------\n",client_id);


	dump=kos_getAllKeys(client_id, client_id, &dim);
	if (dim!=NUM_EL) {
		printf("TEST FAILED - SHOULD RETURN %d ELEMS AND HAS RETURNED %d",NUM_EL,dim);
		exit(-1);
	}
		
	for (i=0; i<NUM_EL; i++) {
		sprintf(key, "k-c%d-%d", client_id, i);
		sprintf(value, "val:%d",i);
		if (lookup(key,value,dump, dim)!=0) {
			printf("TEST FAILED - Error on <%s,%s>, shard %d - not returned in dump\n",key,value,client_id);
			exit(-1);
		}			

	}


	printf("----------------- %d-3/7 ENDED GET ALL KEYS -------------------------\n",client_id);


	for (i=NUM_EL-1; i>=NUM_EL/2; i--) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_remove(client_id, client_id, key);
		if (strncmp(v,value,KEY_SIZE)!=0) {
			printf("Error when removing key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s removed from shard %d. value =%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),client_id,
								( v==NULL ? "<missing>" : v ) );
	}



	printf("----------------- %d-4/7 ENDED REMOVING -------------------------\n",client_id);


	for (i=0; i<NUM_EL; i++) {
		sprintf(key, "k-c%d-%d",client_id,i);
		sprintf(value, "val:%d",i);
		v=kos_get(client_id, client_id, key);
		if (i>=NUM_EL/2 && v!=NULL) {
			printf("Error when gettin key %s value should be NULL and was returned %s",key,v);
			exit(1);
		}
		if (i<NUM_EL/2 && strncmp(v,value,KEY_SIZE)!=0 ) {
			printf("Error on key %s value should be %s and was returned %s",key,value,v);
			exit(1);
		}
		DEBUG("C:%d  %s %s found in shard %d. value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ) ,client_id, ( v==NULL ? "<missing>" : v ) );
	}

	printf("----------------- %d-5/7 ENDED CHECKING AFTER REMOVE -----------------\n",client_id);


	printf("----------------- %d-6/7 TROIKA CUT THIS TEST OFF ----------------\n",client_id);


} // adaptation to getAllKeys from file //


		dump=kos_getAllKeys(client_id, client_id, &dim);
		if (dim!=NUM_EL/2) {
			printf("TEST FAILED - SHOULD RETURN %d ELEMS AND HAS RETURNED %d",NUM_EL,dim);
			exit(-1);
		}
			
		for (i=0; i<NUM_EL/2; i++) {
			sprintf(key, "k-c%d-%d", client_id, i);
			sprintf(value, "val:%d",i);
			if (lookup(key,value,dump, dim)!=0) {
				printf("TEST FAILED - Error on <%s,%s>, shard %d - not returned in dump\n",key,value,client_id);
				exit(-1);
			}			

		}

	

	printf("----------------- %d-7/7 ENDED FINAL ALL KEYS CHECK ----------------------\n",client_id);

	return NULL;
}
void *client_thread(void *arg) {

	char key[KEY_SIZE], value[KEY_SIZE], value2[KEY_SIZE];
	char* v;
	int i,j;
	int client_id=*( (int*)arg);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=NUM_EL; i>=0; i--) {
			sprintf(key, "k-%d",i);
			sprintf(value, "val:%d",i);
			v=kos_put(client_id, j, key,value);
			DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("------------------- %d:1/6 ENDED INSERTING -----------------------\n",client_id);

	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-%d",i);
			sprintf(value, "val:%d",i);
			v=kos_get(client_id, j, key);
			DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),j,
									( v==NULL ? "<missing>" : v ) );
	
		}
	}
	
	printf("------------------ %d:2/6 ENDED READING  ---------------------\n",client_id);

	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=NUM_EL-1; i>=NUM_EL/2; i--) {
			sprintf(key, "k-%d",i);
			sprintf(value, "val:%d",i);
			v=kos_remove(client_id, j, key);
			DEBUG("C:%d  %s %s removed from shard %d. value =%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),j,
									( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("----------------- %d-3/6 ENDED REMOVING -------------------------\n",client_id);

	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-%d",i);
			sprintf(value, "val:%d",i);
			v=kos_get(client_id, j, key);
			DEBUG("C:%d  %s %s found in shard %d. value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ) ,j, ( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("----------------- %d-4/6 ENDED CHECKING AFTER REMOVE -----------------\n",client_id);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-%d",i);
			sprintf(value, "val:%d",i*10);
			sprintf(value2, "val:%d",i*1);
			v=kos_put(client_id, j, key,value);

			DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("----------------- %d-5/6 ENDED 2nd PUT WAVE ----------------\n",client_id);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-%d",i);
			sprintf(value, "val:%d",i*10);
			v=kos_get(client_id, j, key);

			DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),j,
									( v==NULL ? "<missing>" : v ) );
	
		}
	}
	

	printf("----------------- %d-6/6 THE END ----------------------\n",client_id);

	return NULL;
}
void *client_thread(void *arg) {

	char key[KV_SIZE], value[KV_SIZE], value2[KV_SIZE];
	char* v;
	int i,j;
	int client_id=*( (int*)arg);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=NUM_EL; i>=0; i--) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i);
			v=kos_put(client_id, j, key,value);
			DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
		}
	}

printf("------------------- %d:1/6 ENDED INSERTING -----------------------\n",client_id);

	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i);
			v=kos_get(client_id, j, key);
			if (v==NULL || strncmp(v,value,KV_SIZE)!=0) {
				printf("TEST FAILED --> Error on key %s value should be %s and was returned %s",key,value,v);
				exit(1);
			}
			DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),j,
									( v==NULL ? "<missing>" : v ) );
	
		}
	}
	
	printf("------------------ %d:2/6 ENDED READING  ---------------------\n",client_id);

	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=NUM_EL-1; i>=NUM_EL/2; i--) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i);
			v=kos_remove(client_id, j, key);
			if (v==NULL || strncmp(v,value,KV_SIZE)!=0) {
				printf("TEST FAILED --> Error when removing key %s value should be %s and was returned %s",key,value,v);
				exit(1);
			}
			DEBUG("C:%d  %s %s removed from shard %d. value =%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),j,
									( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("----------------- %d-3/6 ENDED REMOVING -------------------------\n",client_id);

	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i);
			v=kos_get(client_id, j, key);
			if (i>=NUM_EL/2 && v!=NULL) {
				printf("TEST FAILED --> Error when gettin key %s value should be NULL and was returned %s",key,v);
				exit(1);
			}
			if (i<NUM_EL/2 && (v==NULL || strncmp(v,value,KV_SIZE)!=0) ) {
				printf("TEST FAILED --> Error on key %s value should be %s and was returned %s",key,value,v);
				exit(1);
			}
			DEBUG("C:%d  %s %s found in shard %d. value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ) ,j, ( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("----------------- %d-4/6 ENDED CHECKING AFTER REMOVE -----------------\n",client_id);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i*10);
			sprintf(value2, "val:%d",i*1);
			v=kos_put(client_id, j, key,value);

			if (i>=NUM_EL/2 && v!=NULL) {
				printf("TEST FAILED --> Error when getting key %s value should be NULL and was returned %s",key,v);
				exit(1);
			}
			if (i<NUM_EL/2 && (v==NULL ||  strncmp(v,value2,KV_SIZE)!=0 ) ) {
				printf("TEST FAILED --> Error on key %s value should be %s and was returned %s",key,value2,v);
				exit(1);
			}


			DEBUG("C:%d  <%s,%s> inserted in shard %d. Prev Value=%s\n", client_id, key, value, j, ( v==NULL ? "<missing>" : v ) );
		}
	}

	printf("----------------- %d-5/6 ENDED 2nd PUT WAVE ----------------\n",client_id);


	for (j=NUM_SHARDS-1; j>=0; j--) {	
		for (i=0; i<NUM_EL; i++) {
			sprintf(key, "k-c%d-%d",client_id,i);
			sprintf(value, "val:%d",i*10);
			v=kos_get(client_id, j, key);
			if (v==NULL || strncmp(v,value,KV_SIZE)!=0) {
				printf("TEST FAILED --> Error on key %s value should be %s and was returned %s",key,value,v);
				exit(1);
			}
			DEBUG("C:%d  %s %s found in shard %d: value=%s\n", client_id, key, ( v==NULL ? "has not been" : "has been" ),j,
									( v==NULL ? "<missing>" : v ) );
	
		}
	}
	

	printf("----------------- %d-6/6 THE END ----------------------\n",client_id);

	return NULL;
}