I have a class, which is very similiar with a database.
It read a lot of file, and record the data. waiting to be used to search.
For Example:
std::vector<std::string> files = {"a", "b", ....}; // not real code, just to show, there is a lot of files
Class BigBuddy {
private:
BigBuddy() { read();}
public:
static BigBuddy& Inst() {static BigBuddy b; return b;}
void read() {
for (const auto & file : files) {
// read the file, and save data into unordered_map
}
}
// this class is created once in constructor
// then it only can be used to find/search
std::string get(int i) const { return data.at(i); }
std::unordered_map<int, std::string> data;
};
This is a singleton
class, becuase it may be used in several place in my project.
for user, it may be:
int main() {
BigBuddy& b = BigBuddy::Inst();
b.get(3);
}
the problem is:
I may run this project many times a day, the BigBuddy
will be created for each time, which cost long time. (create BigBuddy
is slow, because the heavy read
function)
For Example, BigBuddy
cost 5
s to read, i run this project 100
times a day. the project running cost 10
s. the total running time is (10 5) * 100
, but i think i can decrese to 10*100 5
. Because the BigBuddy class's data changed every friday.
So, my question is: Is there any method can make the BigBuddy
class stay in memory, only update in friday?
ps. I have tried boost.serialization
, but i perfer not to use it, because link external library boost
is not good for my project, and, the serialization gives me a lot of error, because the real BigBuddy
in my project has many complex class inside.
CodePudding user response:
So, my question is: Is there any method can make the BigBuddy class stay in memory, only update in friday?
Yes: Instead of running the program multiple times, keep the program running constantly. That way to object will remain in memory.
If the premise of stopping and re-running the program is necessary, then: No, there is no way to keep the object in memory in standard C .
You could of course split the program into two programs. One program that runs constantly and keeps the object in memory, and another program that is run on request.
A program that runs constantly and keeps objects in memory is called "in-memory database". There are existing projects that implement such database, so you don't need to bother building it from the ground up. Since your data is an unordered map, a key-value database would be appropriate.
This is a singleton class, becuase it may be used in several place in my project.
That's not a good reason to use a singleton class.
CodePudding user response:
You can use named shared memory, which will survive until a reboot. However, the standard containers won't work with shared memory, unless you implement a custom allocator and can guarantee a fixed memory location, which is difficult to do.
The best choice is to either write new containers yourself, or use a library. Fortunately, I found a library on GitHub that provides such containers (shame it seems kinda abandoned).
#include "shmc/shm_hash_map.h"
#include <iostream>
#include <string>
// Tweak these values to your needs
#define SHM_KEY "0x123456"
#define SHM_MAX_KEYS 100 // max number of keys
#define SHM_NODE_SIZE 100 // size of each node used to store values
#define SHM_NUM_NODES 100 // total number of nodes for values storage
class BigBuddy {
private:
BigBuddy() { read(); }
public:
static BigBuddy &Inst() {
static BigBuddy b;
return b;
}
void read() {
if (!data.InitForRead(SHM_KEY)) {
if (!data.InitForWrite(SHM_KEY, SHM_MAX_KEYS, SHM_NODE_SIZE,
SHM_NUM_NODES)) {
throw std::runtime_error("failed to initialized shm");
}
std::cout << "Reading data from disk\n";
// put some dummy data in the map
data.Insert(-50, "negative fifty");
data.Insert(5, "five");
data.Insert(123, "one hundred and twenty-three");
data.Insert(999, "nine hundred and ninety-nine");
} else {
std::cout << "Read data from memory\n";
}
}
// this class is created once in constructor
// then it only can be used to find/search
std::string get(int i) const {
std::string r;
if (!data.Find(i, &r)) {
throw std::out_of_range(std::to_string(i));
}
return r;
}
shmc::ShmHashMap<int> data;
};
int main() {
std::cout << BigBuddy::Inst().get(-50) << "\n";
std::cout << BigBuddy::Inst().get(5) << "\n";
std::cout << BigBuddy::Inst().get(123) << "\n";
std::cout << BigBuddy::Inst().get(999) << "\n";
}
First run:
Reading data from disk
negative fifty
five
one hundred and twenty-three
nine hundred and ninety-nine
Second run:
Read data from memory
negative fifty
five
one hundred and twenty-three
nine hundred and ninety-nine
It uses shmget
by default (which is why the key is hexadecimal), but you can also use normal POSIX shared memory too.