I am writing a simple in-memory database. It should support transaction
, meaning that BEGIN
command creates a new block, the operations in which can be canceled by ROLLBACK
command.
I am implementing the list of transaction block
s using a vector
. In case of BEGIN
a new block is created by push_back()
ing an unordered_set
of all keys in that transaction block. This is defined as vector<unordered_set<string>> key_in_blocks
What follows is an example of the commands. SET
sets value to a variable, GET
gets the value of the variable.
BEGIN
SET a 10
GET a <-- this prints 10
BEGIN
SET a 20
GET a <-- this prints 20
ROLLBACK
GET a <-- this prints 10
ROLLBACK <-- Segmentation Fault here!
So there is a default block
at first, and keys_in_block would look like [()]
, here () is denoting set
, [] denotes vector
.
When BEGIN
is issued, a new block is created, and SET
adds a key a
to the block, so keys_in_block = [(), ('a')]
.
The next BEGIN
& SET
part is similar, making keys_in_block
look like [(), ('a'), ('a')]
.
Now ROLLBACK
undoes operations done in the last block, and keys_in_block
should be [(), ('a')]
, because it is pop_back()
ed.
I think my program does what it needs to do up to this point.
On the second ROLLBACK
, it throws segmentation fault, and it looks like I cannot even access the keys_in_block
variable at all.
Below is my code snippet. It runs inside an infinite while loop, taking commands from user.
} else if (command == "BEGIN") {
int num_blocks = keys_in_block.size();
keys_in_block.resize(num_blocks + 1); //new transaction block
} else if (command == "ROLLBACK") {
if (keys_in_block.size() <= 1) {
cout << "NO TRANSACTION" << endl;
}
else {
auto &recent_keys = keys_in_block.back();
// undo operations for keys in the most recent transaction block
for (const string &key : recent_keys) {
//...
//... a bunch of operations that undoes what's done
//... in the most recent transaction block.
recent_keys.erase(key); // erase all keys in the last entry in `keys_in_block`.
}
auto & aa = keys_in_block; //***Just for testing, not relevant to the program.
//This throws Segmentation Fault on second ROLLBACK.
keys_in_block.pop_back(); //Pop back the last transaction block.
}
}
In the code snippet, I marked where the segmentation fault is thrown using //***
.
I added that line to because keys_in_block.pop_back()
threw segmentation fault, and wanted to see if it throws seg fault just by accessing it.
To me, the algorithm looked absolutely correct, and I couldn't find out what the cause of the problem was.
ROLLBACK
doesn't execute when keys_in_block
has one block
or less, so pop_back()
cannot be an issue.
If you need the code for the SET
command part, let me know, but I don't think there is a problem in that code.