void* broker(void * args){
    //pthread_mutex_lock(&mutex);
    char id[11];
    int type, shares, price;
    broker_info * info = (broker_info*) args;
    iterator * iterator = new_iterator(info -> batch_file);

    while(next_operation(iterator, id, &type, &shares, &price)>=0){
        pthread_mutex_lock(&mutex);

        while(operations_queue_full(info -> market -> stock_operations) == 1){
            pthread_cond_wait(&operations, &mutex);
        }
        new_operation(&op, id, type, shares, price);
        enqueue_operation(info -> market -> stock_operations, &op);
        pthread_cond_signal(&not_operations);
        pthread_mutex_unlock(&mutex);
    }
    destroy_iterator(iterator);
    //pthread_mutex_unlock(&mutex);
    pthread_exit(0);
}
// funzione per creare una transazione ed accodarla
transaction_descriptor *create_new_synthetic_transaction(state_type *state, int tx_id, double data_items_zipf_const) {

	// Get the client configuration from simulation state
	CLIENT_lp_state_type *pointer = &state->type.client_state;
	operation_descriptor *op = NULL;
	int number_of_operations = 0;
	int i, j;
	int tx_class_id = -1;
	double val;
	int local_access;
	transaction_descriptor *tx_descr = (transaction_descriptor *) malloc(sizeof(transaction_descriptor));

	tx_descr->tx_id = tx_id;
	tx_descr->next = NULL;
	tx_descr->first_operation = NULL;
	tx_descr->last_operation = NULL;
	tx_descr->current_operation = NULL;

	if (pointer->configuration.tlm_verbose) {
		printf("creazione nuova transazione tx_id %i\n", tx_id);
	}

	//crea le operazioni
	// seleziona la classe transazionale
	double rand_number = Random();
	float sum = 0;

	for (i = 0; i < pointer->configuration.number_of_tx_classes; i++) {
		sum += pointer->configuration.tx_class_probability[i];
		if (rand_number < sum) {
			tx_class_id = i;
			break;
		}
	}

	tx_descr->tx_class_id = tx_class_id;

	// seleziona la lunghezza delle transazioni in operazioni
	switch (pointer->configuration.transaction_length_type) {
	case FIXED:
		number_of_operations = pointer->configuration.tx_class_length[tx_class_id];
		//number_of_operations=5; //TODO rimettere la lungezza delle transazioni in modo corretto
		break;
	case UNIFORM:
		//number_of_operations=5;
		number_of_operations = RandomRange(0, pointer->configuration.tx_class_length[tx_class_id] - 1) + 1;
		break;
	case ZIPF:
	case SINGLE_BAR:
	default:
		fprintf(stderr, "Unsupported value %d at %s:%d\n", pointer->configuration.transaction_length_type, __FILE__, __LINE__);
	}

	for (j = 1; j <= number_of_operations; j++) {
		if (pointer->configuration.tlm_verbose) {
			printf("\tcreo operazione %i\n", j);
		}

		//crea l'operazione
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = j;
		// seleziona il tipo di accesso
		double r;
		do {
			r = Random();
		} while (r == 1);

		if (r <= pointer->configuration.tx_class_write_probability[tx_class_id]) {
			op->op_type = TX_PUT;
		} else {
			op->op_type = TX_GET;
		}

		operation_descriptor *l;

		//selezione distribuzione accesso ai data items
		//TODO

		switch (pointer->configuration.object_access_distribution_type[tx_class_id]) {
		//int dist=UNIFORM;
		//switch (dist) {

		case UNIFORM:

			// seleziona #pointer->cache_objects diversi
			do {
				op->object_key_id = RandomRange(0, state->cache_objects - 1);
				l = get_operation(tx_descr, op->object_key_id);
			} while (l);

			break;

		case LOCALITY:

			local_access=0;
			do {
				r = Random();
			} while (r == 1);
			if (r <= 1) {
				local_access=1;
			}
			do {
				do {
					op->object_key_id = RandomRange(0, state->cache_objects - 1);
					l = get_operation(tx_descr, op->object_key_id);
				} while (l);
			} while (
					local_access && !is_owner(op->object_key_id, get_server(state), state->num_servers, state->num_clients, state->object_replication_degree)
					||
					!local_access && is_owner(op->object_key_id, get_server(state), state->num_servers, state->num_clients, state->object_replication_degree)
			);



			break;

		case TOPKEYS:

			rand_number = Random();
			//printf("Random: %f\n", rand_number);
			float * objects_access_probability;
			op->object_key_id = -1;
			int id_item;
			int number_of_top_keys = 0;
			long double no_tk_probability;
			long double sum_tk = 0;
			bool top_key = false;

			//printf("%d - %d\n",op->op_type, TX_PUT);
			if (op->op_type == TX_GET) {
				objects_access_probability = pointer->configuration.topkeys_cache_objects_get_probability;
				number_of_top_keys = pointer->configuration.number_of_gets_topkeys;
			} else {
				objects_access_probability = pointer->configuration.topkeys_cache_objects_put_probability;
				number_of_top_keys = pointer->configuration.number_of_puts_topkeys;
			}

			for (id_item = 0; id_item < number_of_top_keys; id_item++) {
				sum_tk += objects_access_probability[id_item];
				//printf("sum: %f\n",sum);

				if (rand_number < sum_tk) {
					top_key = true;
					op->object_key_id = id_item;
					break;
				}
			}

			if (!top_key) {

				no_tk_probability = (1 - sum_tk) / (state->cache_objects - number_of_top_keys);

				for (; id_item < state->cache_objects; id_item++) {
					sum_tk += no_tk_probability;
					//printf("sum-no_tk: %f\n",sum);

					if (rand_number < sum_tk) {
						op->object_key_id = id_item;
						break;
					}
				}
			}

			break;

			//printf("Scelto: %d\n",op->object_key_id);

		case ZIPF:

			op->object_key_id = Zipf(data_items_zipf_const, state->cache_objects);

			break;

		case SINGLE_BAR:

			val = Random();

			if (val < 0.8) { // TODO: Alessandro: parametrizzare in una macro?!
				op->object_key_id = RandomRange(0, 10 - 1); //TODO va sul 20% dei data_item
			} else {
				op->object_key_id = RandomRange(0, state->cache_objects - 10 - 1) + 10; //restante 80%
			}

			break;
		}

		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo %i\n", op->op_type);
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		op->next = NULL;
		enqueue_operation(tx_descr, op);
	}

	//resetta lo stato della transazione
	reset_transaction_state(tx_descr);

	return tx_descr;
}
// funzione per creare una transazione ed accodarla // AGGIUNGERE ORDER STATUS
transaction_descriptor *create_new_tpcc_transaction(state_type *state, int tx_id) {

	// Get the client configuration from simulation state
	CLIENT_lp_state_type *pointer = &state->type.client_state;

	operation_descriptor *op = NULL;
	int i = 0;
	int op_number = 1;
	int tx_class_id = -1;
	transaction_descriptor *tx_descr = (transaction_descriptor *) malloc(sizeof(transaction_descriptor));

	tx_descr->tx_id = tx_id;
	tx_descr->next = NULL;
	tx_descr->first_operation = NULL;
	tx_descr->last_operation = NULL;
	tx_descr->current_operation = NULL;

	if (pointer->configuration.tlm_verbose) {
		printf("creazione nuova transazione tx_id %i\n", tx_id);
	}

	//crea le operazioni
	// seleziona la classe transazionale
	double rand_number = Random();
	double sum = 0;

	for (i = 0; i < pointer->configuration.number_of_tx_classes; i++) {
		sum += pointer->configuration.tx_class_probability[i];
		if (rand_number < sum) {
			tx_class_id = i;
			break;
		}
	}

	tx_descr->tx_class_id = tx_class_id;

	if (tx_class_id == NEW_ORDER) {
		/*
		 * NEW ORDER TRANSACTION
		 */

		int warehouse = select_warehouse();
		int district = select_district(warehouse);
		int customer = select_customer(district);

		//crea l'operazione customer
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_GET;
		op->object_key_id = customer;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_GET customer\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		//crea l'operazione warehouse
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_GET;
		op->object_key_id = warehouse;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_GET warehouse\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		//crea l'operazione district
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_GET;
		op->object_key_id = district;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_GET district\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		int i;
		int top = RandomRange(5, 15);
		for (i = 1; i <= top; i++) {

			//crea l'operazione item
			op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
			op->op_number = op_number++;
			op->op_type = TX_GET;
			int item = select_item();
			op->object_key_id = item;

			op->next = NULL;
			enqueue_operation(tx_descr, op);
			if (pointer->configuration.tlm_verbose) {
				printf("\t\ttipo TX_GET item\n");
				printf("\t\tdata_item %i\n", op->object_key_id);
			}

			//crea l'operazione stock
			op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
			op->op_number = op_number++;
			op->op_type = TX_GET;
			int stock = from_item_to_stock(item, warehouse);
			op->object_key_id = stock;

			op->next = NULL;
			enqueue_operation(tx_descr, op);
			if (pointer->configuration.tlm_verbose) {
				printf("\t\ttipo TX_GET stock\n");
				printf("\t\tdata_item %i\n", op->object_key_id);
			}

			//crea l'operazione stock
			op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
			op->op_number = op_number++;
			op->op_type = TX_PUT;
			op->object_key_id = stock;

			op->next = NULL;
			enqueue_operation(tx_descr, op);
			if (pointer->configuration.tlm_verbose) {
				printf("\t\ttipo TX_PUT stock\n");
				printf("\t\tdata_item %i\n", op->object_key_id);
			}
		}
		//crea l'operazione district
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_PUT;
		op->object_key_id = district;

	} else if (tx_class_id == PAYMENT) {

		/*
		 * PAYMENT TRANSACTION
		 */



		int warehouse = select_warehouse();
		int district = select_district(warehouse);
		int customer = select_customer(district);

		//crea l'operazione warehouse
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_GET;
		op->object_key_id = warehouse;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_GET warehouse\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		//crea l'operazione warehouse
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_PUT;
		op->object_key_id = warehouse;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_PUT warehouse\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		//crea l'operazione district
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_GET;
		op->object_key_id = district;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_GET district\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		//crea l'operazione district
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_PUT;
		op->object_key_id = district;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_PUT district\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		//crea l'operazione customer
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_GET;
		op->object_key_id = customer;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_GET customer\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

		//crea l'operazione customer
		op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
		op->op_number = op_number++;
		op->op_type = TX_PUT;
		op->object_key_id = customer;

		op->next = NULL;
		enqueue_operation(tx_descr, op);
		if (pointer->configuration.tlm_verbose) {
			printf("\t\ttipo TX_PUT customer\n");
			printf("\t\tdata_item %i\n", op->object_key_id);
		}

	} else if (tx_class_id == ORDER_STATUS) {


		// get orders
		for (i = 0; i < 3000; i++) {
			//crea l'operazione customer
			op = (operation_descriptor *) malloc(sizeof(operation_descriptor));
			memset(op, 0,sizeof(operation_descriptor));
			op->op_number = op_number++;
			op->op_type = TX_GET;
			op->object_key_id = RandomRange(0, 203010);
			enqueue_operation(tx_descr, op);
		}

	} else {
		printf("\nErrore: classe transazionale non corretta");
	}

	//resetta lo stato della transazione
	reset_transaction_state(tx_descr);

	return tx_descr;
}