void Row_mvcc::update_buffer(TxnManager * txn) { MVReqEntry * ready_read = debuffer_req(R_REQ, NULL); MVReqEntry * req = ready_read; MVReqEntry * tofree = NULL; while (req != NULL) { // find the version for the request MVHisEntry * whis = writehis; while (whis != NULL && whis->ts > req->ts) whis = whis->next; row_t * row = (whis == NULL)? _row : whis->row; req->txn->cur_row = row; insert_history(req->ts, NULL); assert(row->get_data() != NULL); assert(row->get_table() != NULL); assert(row->get_schema() == _row->get_schema()); req->txn->ts_ready = true; uint64_t timespan = get_sys_clock() - req->starttime; req->txn->txn_stats.cc_block_time += timespan; req->txn->txn_stats.cc_block_time_short += timespan; txn_table.restart_txn(txn->get_thd_id(),req->txn->get_txn_id(),0); tofree = req; req = req->next; // free ready_read return_req_entry(tofree); } }
RC Row_ts::access(txn_man * txn, TsType type, row_t * row) { RC rc; ts_t ts = txn->get_ts(); if (g_central_man) glob_manager.lock_row(_row); else pthread_mutex_lock( latch ); if (type == R_REQ) { if (ts < wts) { rc = Abort; } else if (ts > min_pts) { // insert the req into the read request queue buffer_req(R_REQ, txn, NULL); txn->ts_ready = false; rc = WAIT; } else { // return the value. txn->cur_row->copy(_row); if (rts < ts) rts = ts; rc = RCOK; } } else if (type == P_REQ) { if (ts < rts) { rc = Abort; } else { #if TS_TWR buffer_req(P_REQ, txn, NULL); rc = RCOK; #else if (ts < wts) { rc = Abort; } else { buffer_req(P_REQ, txn, NULL); rc = RCOK; } #endif } } else if (type == W_REQ) { // write requests are always accepted. rc = RCOK; #if TS_TWR // according to TWR, this write is already stale, ignore. if (ts < wts) { TsReqEntry * req = debuffer_req(P_REQ, txn); assert(req != NULL); update_buffer(); return_req_entry(req); row->free_row(); mem_allocator.free(row, sizeof(row_t)); goto final; }
TsReqEntry * Row_ts::debuffer_req(TsType type, ts_t ts) { return debuffer_req(type, NULL, ts); }
TsReqEntry * Row_ts::debuffer_req(TsType type, txn_man * txn) { return debuffer_req(type, txn, UINT64_MAX); }
RC Row_mvcc::access(TxnManager * txn, TsType type, row_t * row) { RC rc = RCOK; ts_t ts = txn->get_timestamp(); uint64_t starttime = get_sys_clock(); if (g_central_man) glob_manager.lock_row(_row); else pthread_mutex_lock( latch ); if (type == R_REQ) { // figure out if ts is in interval(prewrite(x)) bool conf = conflict(type, ts); if ( conf && rreq_len < g_max_read_req) { rc = WAIT; //txn->wait_starttime = get_sys_clock(); DEBUG("buf R_REQ %ld %ld\n",txn->get_txn_id(),_row->get_primary_key()); buffer_req(R_REQ, txn); txn->ts_ready = false; } else if (conf) { rc = Abort; printf("\nshould never happen. rreq_len=%ld", rreq_len); } else { // return results immediately. rc = RCOK; MVHisEntry * whis = writehis; while (whis != NULL && whis->ts > ts) whis = whis->next; row_t * ret = (whis == NULL)? _row : whis->row; txn->cur_row = ret; insert_history(ts, NULL); assert(strstr(_row->get_table_name(), ret->get_table_name())); } } else if (type == P_REQ) { if ( conflict(type, ts) ) { rc = Abort; } else if (preq_len < g_max_pre_req){ DEBUG("buf P_REQ %ld %ld\n",txn->get_txn_id(),_row->get_primary_key()); buffer_req(P_REQ, txn); rc = RCOK; } else { rc = Abort; } } else if (type == W_REQ) { rc = RCOK; // the corresponding prewrite request is debuffered. insert_history(ts, row); DEBUG("debuf %ld %ld\n",txn->get_txn_id(),_row->get_primary_key()); MVReqEntry * req = debuffer_req(P_REQ, txn); assert(req != NULL); return_req_entry(req); update_buffer(txn); } else if (type == XP_REQ) { DEBUG("debuf %ld %ld\n",txn->get_txn_id(),_row->get_primary_key()); MVReqEntry * req = debuffer_req(P_REQ, txn); assert (req != NULL); return_req_entry(req); update_buffer(txn); } else assert(false); if (rc == RCOK) { if (whis_len > g_his_recycle_len || rhis_len > g_his_recycle_len) { ts_t t_th = glob_manager.get_min_ts(txn->get_thd_id()); if (readhistail && readhistail->ts < t_th) clear_history(R_REQ, t_th); // Here is a tricky bug. The oldest transaction might be // reading an even older version whose timestamp < t_th. // But we cannot recycle that version because it is still being used. // So the HACK here is to make sure that the first version older than // t_th not be recycled. if (whis_len > 1 && writehistail->prev->ts < t_th) { row_t * latest_row = clear_history(W_REQ, t_th); if (latest_row != NULL) { assert(_row != latest_row); _row->copy(latest_row); } } } } uint64_t timespan = get_sys_clock() - starttime; txn->txn_stats.cc_time += timespan; txn->txn_stats.cc_time_short += timespan; if (g_central_man) glob_manager.release_row(_row); else pthread_mutex_unlock( latch ); return rc; }