static inline void persist_meta(char *meta, size_t sz) { char buf[PATHLEN]; char *path = vbsnprintf(buf, sizeof buf, "%s/%s.bin", DBPATH, METAFILE); persist_data(meta, sz, sizeof (char), path); if (path != buf) free(path); return; }
static inline void persist_col(struct column *col, const char *tname) { if (col->status == ONDISK || col->status == INMEMORY) return; char buf[PATHLEN]; char *path = vbsnprintf(buf, sizeof buf, "%s/%s.%s.bin", DBPATH, tname, col->name); cs165_log(stderr, "%s: %s\n", tname, path); persist_data(col->data.vals, col->data.sz, sizeof (int), path); if (path != buf) free(path); if (col->index) persist_index(col, col->table->name); }
static inline void persist_index(struct column *col, const char *tname) { char buf[PATHLEN]; char *path; switch(col->index->type) { case SORTED: path = vbsnprintf(buf, sizeof buf, "%s/%s.%s.sorted.bin", DBPATH, tname, col->name); cs165_log(stderr, "%s: %s\n", tname, path); persist_data(col->index->index, col->data.sz, sizeof (struct sindex), path); if (path != buf) free(path); case BTREE: break; // TODO: expensive, easier to fully reconstruct case IDX_INVALID: break; } }
/** * handle_client(client_socket) * This is the execution routine after a client has connected. * It will continually listen for messages from the client and execute queries. **/ void handle_client(int client_socket) { int done = 0; int length = 0; log_info("Connected to socket: %d.\n", client_socket); // Create two messages, one from which to read and one from which to receive message send_message; message recv_message; // Continually receive messages from client and execute queries. // 1. Parse the command // 2. Handle request if appropriate // 3. Send status of the received message (OK, UNKNOWN_QUERY, etc) // 4. Send response of request. do { length = recv(client_socket, &recv_message, sizeof(message), 0); if (length < 0) { log_err("Client connection closed!\n"); exit(1); } else if (length == 0) { done = 1; } if (recv_message.status == LOAD_REQUEST) { char recv_buffer[recv_message.length]; length = recv(client_socket, recv_buffer, recv_message.length,0); recv_message.payload = recv_buffer; recv_message.payload[recv_message.length] = '\0'; char* col_name = strtok(recv_buffer, ","); int tbl_idx = find_table_from_col_name(col_name); if (tbl_idx == -1) { log_err("Cannot find table.\n"); exit(1); } table* tbl = global_db->tables[tbl_idx]; while((length = recv(client_socket, &recv_message, sizeof(message), 0)) > 0) { if (recv_message.status == OK_WAIT_FOR_RESPONSE && (int) recv_message.length > 0) { // Calculate number of bytes in response package size_t num_bytes = recv_message.length; char payload[num_bytes + 1]; if ((length = recv(client_socket, payload, num_bytes, 0)) > 0) { db_operator* dbo = init_dbo(); status s = relational_insert(tbl_idx, payload, dbo); if (s.code != OK) { log_err(s.error_message); exit(1); } char* result = execute_db_operator(dbo); log_info("%s\n", result); } } else if (recv_message.status == LOAD_DONE) { status s = process_indexes(tbl); char* result = "Bulk load done"; if (s.code != OK) { result = s.error_message; } send_message.status = OK_WAIT_FOR_RESPONSE; send_message.type = CHAR; send_message.length = strlen(result); // 3. Send status of the received message (OK, UNKNOWN_QUERY, etc) if (send(client_socket, &(send_message), sizeof(message), 0) == -1) { log_err("Failed to send message."); exit(1); } // 4. Send response of request if (send(client_socket, result, send_message.length, 0) == -1) { log_err("Failed to send message."); exit(1); } break; } } continue; } if (!done) { char recv_buffer[recv_message.length]; length = recv(client_socket, recv_buffer, recv_message.length,0); recv_message.payload = recv_buffer; recv_message.payload[recv_message.length] = '\0'; // 1. Parse command status parse_status; db_operator* query = parse_command(&recv_message, &send_message, &parse_status); // 2. Handle request char* result = NULL; if (parse_status.code != OK) { // Something went wrong result = parse_status.error_message; send_message.type = CHAR; send_message.length = strlen(result); } else if (query->type == TUPLE) { send_message.type = query->tups->type; send_message.num_rows = query->tups->num_rows; send_message.num_cols = query->tups->num_cols; send_message.length = (int) (send_message.num_rows * send_message.num_cols); if (send_message.type == INT) { send_message.length *= sizeof(int); } else if (send_message.type == LONG) { send_message.length *= sizeof(long); } else if (send_message.type == LONG_DOUBLE) { send_message.length *= sizeof(long double); } else { send_message.length *= sizeof(char); } // 3. Send status of the received message (OK, UNKNOWN_QUERY, etc) if (send(client_socket, &(send_message), sizeof(message), 0) == -1) { log_err("Failed to send message."); exit(1); } // 4. Send response of request for(size_t i = 0; i < send_message.num_cols; i++) { char* result = (char*)query->tups->payloads[i]; int length = send_message.length/(int)send_message.num_cols; if (send(client_socket, result, length, 0) == -1) { log_err("Failed to send message."); exit(1); } } continue; } else if (query->type == SHUTDOWN) { status s = persist_data(); if (s.code != OK) { log_err("Error persisting data\n"); } // free what you can // s = free_catalogs(); if (s.code != OK) { log_err("Error shutting down\n"); } send_message.status = SHUTDOWN_CLIENT; if (send(client_socket, &(send_message), sizeof(message), 0) == -1) { log_err("Failed to send message."); close(client_socket); } return; } else { result = execute_db_operator(query); send_message.type = CHAR; send_message.length = strlen(result); } // 3. Send status of the received message (OK, UNKNOWN_QUERY, etc) if (send(client_socket, &(send_message), sizeof(message), 0) == -1) { log_err("Failed to send message."); exit(1); } // 4. Send response of request if (send(client_socket, result, send_message.length, 0) == -1) { log_err("Failed to send message."); exit(1); } } } while (!done); log_info("Connection closed at socket %d!\n", client_socket); close(client_socket); }