forked from blue/lmdbal
better transaction tests
This commit is contained in:
parent
8be63d7551
commit
150a0b0da9
@ -1,5 +1,7 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
|
||||||
@ -12,6 +14,24 @@ protected:
|
|||||||
|
|
||||||
~StorageTransactionsTest() {}
|
~StorageTransactionsTest() {}
|
||||||
|
|
||||||
|
int waitForChildFork(int pid) {
|
||||||
|
int status;
|
||||||
|
if (0 > waitpid(pid, &status, 0)) {
|
||||||
|
std::cerr << "[----------] Waitpid error!" << std::endl;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
const int exit_status = WEXITSTATUS(status);
|
||||||
|
if (exit_status != 0) {
|
||||||
|
std::cerr << "[----------] Non-zero exit status " << exit_status << " from test!" << std::endl;
|
||||||
|
}
|
||||||
|
return exit_status;
|
||||||
|
} else {
|
||||||
|
std::cerr << "[----------] Non-normal exit from child!" << std::endl;
|
||||||
|
return (-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void SetUpTestSuite() {
|
static void SetUpTestSuite() {
|
||||||
if (db == nullptr) {
|
if (db == nullptr) {
|
||||||
db = new LMDBAL::Base("storageTrnansactionsTestBase");
|
db = new LMDBAL::Base("storageTrnansactionsTestBase");
|
||||||
@ -20,6 +40,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
db->open();
|
db->open();
|
||||||
|
db->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TearDownTestSuite() {
|
static void TearDownTestSuite() {
|
||||||
@ -109,3 +130,100 @@ TEST_F(StorageTransactionsTest, Reading) {
|
|||||||
|
|
||||||
db->abortTransaction(txn);
|
db->abortTransaction(txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StorageTransactionsTest, ConcurentReading) {
|
||||||
|
EXPECT_EQ(db->ready(), true);
|
||||||
|
|
||||||
|
LMDBAL::SizeType size = t1->count();
|
||||||
|
LMDBAL::TransactionID txn = db->beginTransaction();
|
||||||
|
EXPECT_EQ(t1->getRecord(5, txn), 13);
|
||||||
|
EXPECT_EQ(t1->getRecord(5), 13);
|
||||||
|
|
||||||
|
t1->removeRecord(5, txn);
|
||||||
|
|
||||||
|
EXPECT_FALSE(t1->checkRecord(5, txn));
|
||||||
|
EXPECT_EQ(t1->getRecord(5), 13);
|
||||||
|
|
||||||
|
t1->addRecord(5, 571, txn);
|
||||||
|
EXPECT_EQ(t1->getRecord(5, txn), 571);
|
||||||
|
EXPECT_EQ(t1->getRecord(5), 13);
|
||||||
|
|
||||||
|
t1->forceRecord(5, -472, txn);
|
||||||
|
EXPECT_EQ(t1->getRecord(5, txn), -472);
|
||||||
|
EXPECT_EQ(t1->getRecord(5), 13);
|
||||||
|
|
||||||
|
t1->replaceAll({
|
||||||
|
{1, 75}
|
||||||
|
}, txn);
|
||||||
|
EXPECT_FALSE(t1->checkRecord(5, txn));
|
||||||
|
EXPECT_EQ(t1->getRecord(5), 13);
|
||||||
|
EXPECT_EQ(t1->count(txn), 1);
|
||||||
|
EXPECT_EQ(t1->count(), size);
|
||||||
|
|
||||||
|
db->commitTransaction(txn);
|
||||||
|
|
||||||
|
EXPECT_FALSE(t1->checkRecord(5));
|
||||||
|
EXPECT_EQ(t1->count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StorageTransactionsTest, ConcurentModification) {
|
||||||
|
EXPECT_EQ(db->ready(), true);
|
||||||
|
|
||||||
|
//if you start one writable transaction after another
|
||||||
|
//in a single thread like so:
|
||||||
|
//
|
||||||
|
//LMDBAL::TransactionID txn1 = db->beginTransaction();
|
||||||
|
//LMDBAL::TransactionID txn2 = db->beginTransaction();
|
||||||
|
//
|
||||||
|
//the execution should block on the second transaction
|
||||||
|
//so this test should preform in a sequence
|
||||||
|
//first the parent, then the child
|
||||||
|
|
||||||
|
int pid = fork();
|
||||||
|
if (pid == 0) { // I am the child
|
||||||
|
std::cout << "beggining second transaction" << std::endl;
|
||||||
|
LMDBAL::TransactionID txn2 = db->beginTransaction(); //<--- this is where the execution should pause
|
||||||
|
//and wait for the first transaction to get finished
|
||||||
|
std::cout << "checking result of the first transaction value" << std::endl;
|
||||||
|
EXPECT_EQ(t1->getRecord(5, txn2), 812);
|
||||||
|
|
||||||
|
std::cout << "forcing second transaction value" << std::endl;
|
||||||
|
t1->forceRecord(5, -46, txn2);
|
||||||
|
|
||||||
|
std::cout << "checking second transaction value" << std::endl;
|
||||||
|
EXPECT_EQ(t1->getRecord(5, txn2), -46);
|
||||||
|
|
||||||
|
std::cout << "checking value independently" << std::endl;
|
||||||
|
EXPECT_EQ(t1->getRecord(5), 812);
|
||||||
|
|
||||||
|
std::cout << "commiting second transaction" << std::endl;
|
||||||
|
db->commitTransaction(txn2);
|
||||||
|
|
||||||
|
std::cout << "quitting child thread" << std::endl;
|
||||||
|
exit(testing::Test::HasFailure());
|
||||||
|
} else { // I am the parent
|
||||||
|
std::cout << "beggining first transaction" << std::endl;
|
||||||
|
LMDBAL::TransactionID txn1 = db->beginTransaction();
|
||||||
|
|
||||||
|
std::cout << "putting parent thread to sleep for 5 ms" << std::endl;
|
||||||
|
usleep(5);
|
||||||
|
|
||||||
|
std::cout << "adding first transaction value" << std::endl;
|
||||||
|
t1->addRecord(5, 812, txn1);
|
||||||
|
|
||||||
|
std::cout << "checking first transaction value" << std::endl;
|
||||||
|
EXPECT_EQ(t1->getRecord(5, txn1), 812);
|
||||||
|
|
||||||
|
std::cout << "checking value independently" << std::endl;
|
||||||
|
EXPECT_FALSE(t1->checkRecord(5));
|
||||||
|
|
||||||
|
std::cout << "commiting first transaction" << std::endl;
|
||||||
|
db->commitTransaction(txn1);
|
||||||
|
|
||||||
|
std::cout << "waiting for the other thread to finish" << std::endl;
|
||||||
|
ASSERT_EQ(0, waitForChildFork(pid)); //child process should have no problems
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "checking final result" << std::endl;
|
||||||
|
EXPECT_EQ(t1->getRecord(5), -46);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user