New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[15721] Logging and Recovery #1348

Open
wants to merge 95 commits into
base: master
from

Conversation

Projects
None yet
6 participants
@aaron-tian
Contributor

aaron-tian commented May 5, 2018

This PR implements logging and recovery for robustness to crashes.

Logging:

  • Create log records and write them into log buffers in TimestampOrderingTransactionManager as executing transactions. Submit the buffer when it is full and then acquire a new one for the current transaction.
  • Push the callback for committing transactions from the network level to the worker level. Set logging callbacks and return QUEUING in CommitTransaction and AbortTransaction.
  • Adopt delta logging for updates. Pass values_buf, values_size and offsets all the way down to PerformUpdate.
  • Use tokens to guarantee the FIFO order in the logical queue for multiple workers. The logic queue consists of a few sub-queues, each per worker. Buffers belonging to the same transaction will be put into the same sub-queue.
  • Support the default codegen engine only.

Recovery:

  • Implement two-pass recovery. The first pass filters out transactions that are not committed while the second one classifies recods by txn_id. After two passes, all the transactions are replayed.
  • Support Create Table, Create Database, Insert and Delete currently.

gandeevan and others added some commits Feb 20, 2018

1. added support for logging BEGIN_TXN
2. removed logging for read-only TXN.

@aaron-tian aaron-tian force-pushed the aaron-tian:logging branch from 0ef86bd to 5a73bcf May 6, 2018

latelatif added some commits May 8, 2018

Merge branch 'master' into logging
Conflicts:
	src/codegen/updater.cpp
	src/concurrency/timestamp_ordering_transaction_manager.cpp
	src/storage/data_table.cpp
	test/brain/query_logger_test.cpp
case LogRecordType::TRANSACTION_BEGIN:{
if(all_txns_.find(txn_id) != all_txns_.end()){
LOG_ERROR("Duplicate transaction");
PELOTON_ASSERT(false);

This comment has been minimized.

@Zeninma

Zeninma May 12, 2018

Contributor

In the beginning, upon log file reading failure, the StartRecovery writes a LOG_ERROR and returns. I am wondering whether it should behave the same here - return after writing LOG_ERROR instead of using PELOTON_ASSERT(false) to abort?

buf_curr += (record_len + sizeof(record_len));
buf_rem -= (record_len + sizeof(record_len));
} else {
break;

This comment has been minimized.

@Zeninma

Zeninma May 12, 2018

Contributor

Might directly log an error and abort/return instead of using break.

LOG_INFO("Replaying TXN_COMMIT");
}
else if(record_type==LogRecordType::TRANSACTION_ABORT) {

This comment has been minimized.

@Zeninma

Zeninma May 12, 2018

Contributor

This check might need to be moved to ParseFromDisk and files an error there.
If a TRANSACTION_ABORT record were found at then at this time, then the previous changes in this transaction would have been made (which should not be, if I got this correctly).
On the other hand, if the transaction could reach here, then it should also have a TRANSACTION_COMMIT record. I wonder if it is possible for a transaction to have both records. If not, then such check can be redundant.

}
// Pass 2
log_buffer_ = new char[log_buffer_size_];

This comment has been minimized.

@Zeninma

Zeninma May 12, 2018

Contributor

I wonder if the recovery needs to read the log file twice from the disk. Since log_buffer_ is constructed here after the first pass.
If this is the case, will it be better to populate the log_buffer_ in the first phase and save the second disk read in the second phase?

@nwang57

Logging looks good. recovery seems not finished yet. Add some tests for the recovery part so that correctness can be easily verified.

@@ -862,7 +862,9 @@ void PostgresProtocolHandler::ExecExecuteMessageGetResult(ResultType status) {
}
void PostgresProtocolHandler::GetResult() {
traffic_cop_->ExecuteStatementPlanGetResult();
// traffic_cop_->ExecuteStatementPlanGetResult();

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

why this is commented out

current_txn->GetEpochId(), current_txn->GetTransactionId(),
current_txn->GetCommitId(), schema_oid);
record.SetOldItemPointer(location);

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

You already set the old item pointer once during the log record constructor why do you need to set it explicitly?

LogRecordType::TUPLE_UPDATE, location, new_location, current_txn->GetEpochId(),
current_txn->GetTransactionId(), current_txn->GetCommitId(), schema_oid);
record.SetOldItemPointer(location);

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

You already set the old item pointer once during the log record constructor why do you need to set it explicitly?

LogRecordType::TRANSACTION_COMMIT, current_txn->GetEpochId(),
current_txn->GetTransactionId(), current_txn->GetCommitId());
current_txn->GetLogBuffer()->WriteRecord(record);

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

Will the log_buffer exceeds its threshold after this write?

LogRecordType::TRANSACTION_ABORT, current_txn->GetEpochId(),
current_txn->GetTransactionId(), current_txn->GetCommitId());
current_txn->GetLogBuffer()->WriteRecord(record);

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

Will the log_buffer exceeds its threshold after this write?

stream->flush();
if(stream->fail()){
PELOTON_ASSERT(false);

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

why not PELOTON_ASSERT(!stream->fail())? Do we really want to crash the system if the stream fails or is there any mechanism to rewrite the log to file?

}
// Pass 2
log_buffer_ = new char[log_buffer_size_];

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

This memory may not be freed

if(it->second.first != LogRecordType::TRANSACTION_COMMIT)
continue;
auto offset_pair = std::make_pair(curr_txn_offset, curr_txn_offset);

This comment has been minimized.

@nwang57

nwang57 May 12, 2018

Contributor

Why making a pair of two identical size_t values?

@cmu-db cmu-db deleted a comment from nwang57 May 13, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment