polardbxengine/extra/IS/consensus/algorithm/mem_paxos_log.cc

245 lines
5.2 KiB
C++

/************************************************************************
*
* Copyright (c) 2016 Alibaba.com, Inc. All Rights Reserved
* $Id: mem_paxos_log.cc,v 1.0 12/22/2016 3:05:36 PM jarry.zj(jarry.zj@alibaba-inc.com) $
*
************************************************************************/
/**
* @file mem_paxos_log.cc
* @author jarry.zj(jarry.zj@alibaba-inc.com)
* @date 12/22/2016 3:05:36 PM
* @version 1.0
* @brief impl of memory based paxos log
*
**/
#include <chrono>
#include <easy_log.h>
#include "mem_paxos_log.h"
namespace alisql
{
MemPaxosLog::MemPaxosLog(uint64_t lastLogIndex, uint64_t readTimeout, uint64_t cacheSize)
:lastLogIndex_(lastLogIndex), cacheSize_(cacheSize), readTimeout_(readTimeout), appendTimeout_(500)
{
}
MemPaxosLog::~MemPaxosLog()
{
shutdown();
}
int MemPaxosLog::getEntry(uint64_t logIndex, LogEntry &entry, bool fastfail)
{
std::lock_guard<std::mutex> lg(lock_);
if (log_.size() == 0 || logIndex > lastLogIndex_ || logIndex < log_.front()->index())
{
if (fastfail)
return -1;
else
{
}
}
for (LogEntry *le: log_)
{
if (le->index() == logIndex)
{
entry.CopyFrom(*le);
return 0;
}
else if (le->index() > logIndex)
{
return -1;
}
}
return -1;
}
int MemPaxosLog::getEntry(LogEntry &entry)
{
std::unique_lock<std::mutex> ul(lock_);
if (readTimeout_ == 0)
{
isEmptyCond_.wait(ul, [this](){ return log_.size() > 0; });
} else {
bool ret = isEmptyCond_.wait_for(ul, std::chrono::milliseconds(readTimeout_), [this](){ return log_.size() > 0; });
if (ret == false)
{
easy_warn_log("MemPaxosLog: log is emtry, getEntry timeout.\n");
return -1;
}
}
if (log_.size() == 0) {
return -1;
}
LogEntry *fle = log_.front();
entry.CopyFrom(*fle);
delete fle;
log_.pop_front();
isFullCond_.notify_all();
return 0;
}
int MemPaxosLog::getEmptyEntry(LogEntry &entry)
{
entry.set_term(0);
entry.set_index(0);
entry.set_optype(kNormal);
entry.set_ikey("");
entry.set_value("");
return 0;
}
void MemPaxosLog::appendEmptyEntry()
{
LogEntry logEntry;
getEmptyEntry(logEntry);
append(logEntry);
}
uint64_t MemPaxosLog::getLastLogIndex()
{
return lastLogIndex_;
}
uint64_t MemPaxosLog::getLength()
{
std::lock_guard<std::mutex> lg(lock_);
return log_.size();
}
uint64_t MemPaxosLog::append(const LogEntry &entry)
{
std::unique_lock<std::mutex> ul(lock_);
if (appendTimeout_ == 0)
{
isFullCond_.wait(ul, [this](){ return log_.size() < cacheSize_; });
}
else
{
bool ret = isFullCond_.wait_for(ul, std::chrono::milliseconds(appendTimeout_), [this](){
return log_.size() < cacheSize_;
});
if (ret == false)
{
easy_warn_log("MemPaxosLog: log is full, append timeout.\n");
return lastLogIndex_;
}
}
LogEntry *le = new LogEntry(entry);
if (le->index() == 0)
{
le->set_index(lastLogIndex_+1);
}
assert(le->index() == (lastLogIndex_+1));
log_.push_back(le);
lastLogIndex_ = le->index();
isEmptyCond_.notify_all();
return lastLogIndex_;
}
uint64_t MemPaxosLog::append(const ::google::protobuf::RepeatedPtrField<LogEntry> &entries)
{
std::unique_lock<std::mutex> ul(lock_);
if (appendTimeout_ == 0)
{
isFullCond_.wait(ul, [this](){ return log_.size() < cacheSize_; });
}
else
{
bool ret = isFullCond_.wait_for(ul, std::chrono::milliseconds(appendTimeout_), [this](){
return log_.size() < cacheSize_;
});
if (ret == false)
{
easy_warn_log("MemPaxosLog: log is full, append timeout.\n");
return lastLogIndex_;
}
}
for (auto it=entries.begin(); it !=entries.end(); ++it)
{
LogEntry *le = new LogEntry(*it);
assert(le->index() == (lastLogIndex_+1));
log_.push_back(le);
lastLogIndex_ = le->index();
}
isEmptyCond_.notify_all();
return lastLogIndex_;
}
void MemPaxosLog::shutdown()
{
isFullCond_.notify_all();
isEmptyCond_.notify_all();
std::unique_lock<std::mutex> ul(lock_);
for (auto le: log_)
{
delete le;
}
log_.clear();
}
void MemPaxosLog::truncateBackward(uint64_t firstIndex)
{
// not impl
}
void MemPaxosLog::truncateForward(uint64_t lastIndex)
{
/* clear log before lastIndex (exclude!) */
if (lastIndex > lastLogIndex_)
{
lastIndex = lastLogIndex_;
}
std::unique_lock<std::mutex> ul(lock_);
uint64_t l = 0, r = 0;
while(!log_.empty())
{
LogEntry *fle = log_.front();
if (fle->index() < lastIndex)
{
if (l == 0)
l = fle->index();
r = fle->index();
delete fle;
log_.pop_front();
}
else
{
break;
}
}
easy_warn_log("truncate log index [%ld-%ld].\n", l, r);
isFullCond_.notify_all();
}
int MemPaxosLog::getMetaData(const std::string &key, uint64_t *value)
{
// not impl
return -1;
}
int MemPaxosLog::setMetaData(const std::string &key, const uint64_t value)
{
// not impl
return -1;
}
void MemPaxosLog::resetLastLogIndex(uint lli)
{
/*
* we already hold witness lock outside, so no concurrent append, nobody wait append
* we clear the log here, so if someone wait getEntry, keep waiting
*/
std::unique_lock<std::mutex> ul(lock_);
log_.clear();
lastLogIndex_ = lli;
}
} /* namespace */