void *db_worker(void *data) { int id = *((int *) data); /* Whoa... */ struct transaction_queue_node_t *node; struct db_context_t *dbc; char code; double response_time; struct timeval rt0, rt1; int local_seed; pid_t pid; pthread_t tid; extern unsigned int seed; int status; /* Each thread needs to seed in Linux. */ tid = pthread_self(); pid = getpid(); if (seed == -1) { struct timeval tv; unsigned long junk; /* Purposely used uninitialized */ local_seed = pid; gettimeofday(&tv, NULL); local_seed ^= tid ^ tv.tv_sec ^ tv.tv_usec ^ junk; } else { local_seed = seed; } set_random_seed(local_seed); /* Open a connection to the database. */ dbc = db_init(); if (!exiting && connect_to_db(dbc) != OK) { LOG_ERROR_MESSAGE("connect_to_db() error, terminating program"); printf("cannot connect to database(see details in error.log file, exiting...\n"); exit(1); } while (!exiting) { /* * I know this loop will prevent the program from exiting * because of the dequeue... */ node = dequeue_transaction(); if (node == NULL) { LOG_ERROR_MESSAGE("dequeue was null"); continue; } /* Execute transaction and record the response time. */ if (gettimeofday(&rt0, NULL) == -1) { perror("gettimeofday"); } status = process_transaction(node->client_data.transaction, dbc, &node->client_data.transaction_data); if (status == ERROR) { LOG_ERROR_MESSAGE("process_transaction() error on %s", transaction_name[ node->client_data.transaction]); /* * Assume this isn't a fatal error, send the results * back, and try processing the next transaction. */ while (need_reconnect_to_db(dbc)) { LOG_ERROR_MESSAGE("try to reconnect to database"); disconnect_from_db(dbc); if (connect_to_db(dbc) != OK) { LOG_ERROR_MESSAGE("reconnect to database error, try again after sleep 5 seconds"); sleep(5); } } } if (status == OK) { code = 'C'; } else if (status == STATUS_ROLLBACK) { code = 'R'; } else if (status == ERROR) { code = 'E'; } if (gettimeofday(&rt1, NULL) == -1) { perror("gettimeofday"); } response_time = difftimeval(rt1, rt0); log_transaction_mix(node->client_data.transaction, code, response_time, mode_altered > 0 ? node->termworker_id : node->term_id); enqueue_terminal(node->termworker_id, node->term_id); /* Keep track of how many transactions this thread has done. */ ++worker_count[id]; /* Keep track of then the last transaction was execute. */ time(&last_txn[id]); } /* Disconnect from the database. */ disconnect_from_db(dbc); free(dbc); sem_wait(&db_worker_count); return NULL; /* keep compiler quiet */ }
void *db_worker(void *data) { int id = *((int *) data); /* Whoa... */ #ifndef STANDALONE int length; #endif /* NOT STANDALONE */ struct transaction_queue_node_t *node; struct db_context_t dbc; #ifdef STANDALONE struct timeval rt0, rt1; double response_time; #endif /* STANDALONE */ /* Open a connection to the database. */ #ifdef ODBC printf("connect to ODBC server with parameters: DSN: |%s| user: |%s| pass: |%s|\n", sname, dbt2_user, dbt2_pass); db_init(sname, dbt2_user, dbt2_pass); #endif /* ODBC */ #ifdef LIBPQ db_init(DB_NAME, sname, postmaster_port); #endif /* LIBPQ */ #ifdef LIBMYSQL printf("connect to mysql server with parameters: db_name: |%s| host: |%s| user: |%s| pass: |%s| port: |%s| socket: |%s|\n", sname, dbt2_mysql_host, dbt2_user, dbt2_pass, dbt2_mysql_port, dbt2_mysql_socket); db_init(sname, dbt2_mysql_host , dbt2_user, dbt2_pass, dbt2_mysql_port, dbt2_mysql_socket); #endif /* LIBMYSQL */ if (!exiting && connect_to_db(&dbc) != OK) { LOG_ERROR_MESSAGE("connect_to_db() error, terminating program"); printf("cannot connect to database(see details in error.log file, exiting...\n"); exit(1); } while (!exiting) { /* * I know this loop will prevent the program from exiting * because of the dequeue... */ node = dequeue_transaction(); if (node == NULL) { LOG_ERROR_MESSAGE("dequeue was null"); continue; } #ifdef STANDALONE if (gettimeofday(&rt0, NULL) == -1) { perror("gettimeofday"); } #endif /* STANDALONE */ node->client_data.status = process_transaction(node->client_data.transaction, &dbc, &node->client_data.transaction_data); if (node->client_data.status == ERROR) { LOG_ERROR_MESSAGE("process_transaction() error on %s", transaction_name[ node->client_data.transaction]); /* * Assume this isn't a fatal error, send the results * back, and try processing the next transaction. */ } else { if (node->client_data.status == ERROR_FATAL) { LOG_ERROR_MESSAGE("process_transaction() fatal error on %s", transaction_name[ node->client_data.transaction]); LOG_ERROR_MESSAGE("stopping db_thread"); exiting=1; } } #ifdef STANDALONE if (gettimeofday(&rt1, NULL) == -1) { perror("gettimeofday"); } response_time = difftimeval(rt1, rt0); pthread_mutex_lock(&mutex_mix_log); fprintf(log_mix, "%d,%c,%f,%d\n", (int) time(NULL), transaction_short_name[node->client_data.transaction], response_time, (int) pthread_self()); fflush(log_mix); pthread_mutex_unlock(&mutex_mix_log); #endif /* STANDALONE */ #ifndef STANDALONE length = send_transaction_data(node->s, &node->client_data); if (length == ERROR) { LOG_ERROR_MESSAGE("send_transaction_data() error"); /* * Assume this isn't a fatal error and try processing * the next transaction. */ } #endif /* NOT STANDALONE */ pthread_mutex_lock(&mutex_transaction_counter[REQ_EXECUTING][ node->client_data.transaction]); --transaction_counter[REQ_EXECUTING][ node->client_data.transaction]; pthread_mutex_unlock(&mutex_transaction_counter[REQ_EXECUTING][ node->client_data.transaction]); recycle_node(node); /* Keep track of how many transactions this thread has done. */ ++worker_count[id]; /* Keep track of then the last transaction was execute. */ time(&last_txn[id]); } /* Disconnect from the database. */ disconnect_from_db(&dbc); sem_wait(&db_worker_count); return NULL; /* keep compiler quiet */ }