// Mutation log iterator
// ----------------------------------------------------------------------
-MutationLog::iterator::iterator(const MutationLog& l, bool e)
+MutationLog::iterator::iterator(const MutationLog* l, bool e)
: log(l),
entryBuf(),
buf(),
p(nullptr),
- offset(l.header().blockSize() * l.header().blockCount()),
+ offset(l->header().blockSize() * l->header().blockCount()),
items(0),
isEnd(e)
{
isEnd(mit.isEnd)
{
if (mit.buf != NULL) {
- buf.reset(new uint8_t[log.header().blockSize()]());
- memcpy(buf.get(), mit.buf.get(), log.header().blockSize());
+ buf.reset(new uint8_t[log->header().blockSize()]());
+ memcpy(buf.get(), mit.buf.get(), log->header().blockSize());
p = buf.get() + (mit.p - mit.buf.get());
}
}
}
+MutationLog::iterator& MutationLog::iterator::operator=(const MutationLog::iterator& other)
+{
+ log = other.log;
+ if (other.buf != nullptr) {
+ buf.reset(new uint8_t[log->header().blockSize()]());
+ memcpy(buf.get(), other.buf.get(), log->header().blockSize());
+ p = buf.get() + (other.p - other.buf.get());
+ } else {
+ buf = nullptr;
+ p = nullptr;
+ }
+
+ if (other.entryBuf != nullptr) {
+ entryBuf.reset(new uint8_t[LOG_ENTRY_BUF_SIZE]());
+ memcpy(entryBuf.get(), other.entryBuf.get(), LOG_ENTRY_BUF_SIZE);
+ } else {
+ entryBuf = nullptr;
+ }
+
+ offset = other.offset;
+ items = other.items;
+ isEnd = other.isEnd;
+
+ return *this;
+}
+
MutationLog::iterator::~iterator() {
}
}
bool MutationLog::iterator::operator==(const MutationLog::iterator& rhs) const {
- return log.fd() == rhs.log.fd()
+ return log->fd() == rhs.log->fd()
&& (
(isEnd == rhs.isEnd)
|| (offset == rhs.offset
}
size_t MutationLog::iterator::bufferBytesRemaining() {
- return log.header().blockSize() - (p - buf.get());
+ return log->header().blockSize() - (p - buf.get());
}
void MutationLog::iterator::nextBlock() {
- if (log.isEnabled() && !log.isOpen()) {
+ if (log->isEnabled() && !log->isOpen()) {
throw std::logic_error("MutationLog::iterator::nextBlock: "
"log is enabled and not open");
}
if (buf == NULL) {
- buf.reset(new uint8_t[log.header().blockSize()]());
+ buf.reset(new uint8_t[log->header().blockSize()]());
}
p = buf.get();
- ssize_t bytesread = pread(log.fd(), buf.get(), log.header().blockSize(),
+ ssize_t bytesread = pread(log->fd(), buf.get(), log->header().blockSize(),
offset);
if (bytesread < 1) {
isEnd = true;
return;
}
- if (bytesread != (ssize_t)(log.header().blockSize())) {
+ if (bytesread != (ssize_t)(log->header().blockSize())) {
LOG(EXTENSION_LOG_WARNING, "FATAL: too few bytes read in access log"
- "'%s': %s", log.getLogFile().c_str(), strerror(errno));
+ "'%s': %s", log->getLogFile().c_str(), strerror(errno));
throw ShortReadException();
}
offset += bytesread;
- uint32_t crc32(crc32buf(buf.get() + 2, log.header().blockSize() - 2));
+ uint32_t crc32(crc32buf(buf.get() + 2, log->header().blockSize() - 2));
uint16_t computed_crc16(crc32 & 0xffff);
uint16_t retrieved_crc16;
memcpy(&retrieved_crc16, buf.get(), sizeof(retrieved_crc16));
iterator(const iterator& mit);
+ iterator& operator=(const iterator& other);
+
~iterator();
iterator& operator++();
friend class MutationLog;
- iterator(const MutationLog& l, bool e=false);
+ iterator(const MutationLog* l, bool e=false);
void nextBlock();
size_t bufferBytesRemaining();
void prepItem();
- const MutationLog& log;
+ const MutationLog* log;
std::unique_ptr<uint8_t[]> entryBuf;
std::unique_ptr<uint8_t[]> buf;
uint8_t *p;
* An iterator pointing to the beginning of the log file.
*/
iterator begin() {
- iterator it(iterator(*this));
+ iterator it(iterator(this));
it.nextBlock();
return it;
}
* An iterator pointing at the end of the log file.
*/
iterator end() {
- return iterator(*this, true);
+ return iterator(this, true);
}
//! Items logged by type.
set_file_perms(FilePerms::Read | FilePerms::Write);
}
+// Test that the MutationLog::iterator class obeys expected iterator behaviour.
+TEST_F(MutationLogTest, Iterator) {
+ // Create a simple mutation log to work on.
+ {
+ MutationLog ml(tmp_log_filename.c_str());
+ ml.open();
+ ml.newItem(0, "key1", 0);
+ ml.newItem(0, "key2", 1);
+ ml.newItem(0, "key3", 2);
+ ml.commit1();
+ ml.commit2();
+
+ EXPECT_EQ(3, ml.itemsLogged[ML_NEW]);
+ EXPECT_EQ(1, ml.itemsLogged[ML_COMMIT1]);
+ EXPECT_EQ(1, ml.itemsLogged[ML_COMMIT2]);
+ }
+
+ // Now check the iterators.
+ MutationLog ml(tmp_log_filename.c_str());
+ ml.open();
+
+ // Can copy-construct.
+ auto iter = ml.begin();
+ EXPECT_EQ(ml.begin(), iter);
+
+ // Can copy-assign.
+ iter = ml.end();
+ EXPECT_EQ(ml.end(), iter);
+
+ // Can advance the correct number.
+ size_t count = 0;
+ for (auto iter2 = ml.begin(); iter2 != ml.end(); ++iter2) {
+ count++;
+ }
+ EXPECT_EQ(5, count);
+}
+
// @todo
// Test Read Only log
// Test close / open / close / open