Home > database >  How Can I keep a object forever?
How Can I keep a object forever?

Time:01-01

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 5s to read, i run this project 100 times a day. the project running cost 10s. 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.

  • Related