Search code examples
c++object-persistencesubtree

Is it possible to write a truly generic disk-baked B+Tree implementation?


I wrote a generic in-memory B+Tree implementation in C++ few times ago, and I'm thinking about making it persistent on disk (which is why B+Tree have been designed for initially). My first thought was to use mmap (I'm under Linux) to be able to manipulate the file as normal memory and just rewrite the new operator of my nodes classes so that it returns pointers in the mapped portion and create a smart pointer which can convert RAM adresses to file offset to link my nodes with others. But I want my implementation to be generic, so the user can store an int, an std::string, or whatever custom class he wants in the B+tree. That's where the problem occurs: for primitive types or aggregated types that do not contain pointers that's all good, but as soon as the object contains a pointer/reference to an heap allocated object, this approach no longer works.

So my question is: is there some known way to overcome this difficulty? My personnal searches on the topic end up unsuccessful, but maybe I missed something.


Solution

  • As far as I know, there are three (somewhat) easy ways to solve this.

    Approach 1: write a std::streambuf that points to some pre-allocated memory.

    This approach allows you to use operator<< and use whatever existing code already exists to get a string representation of what you want.

    • Pro: re-use loads of existing code.
    • Con: no control over how operator<< spits out content.
    • Con: text-based representations only.

    Approach 2: write your own (many times overloaded) output function.

    • Pro: can come up with binary representation.
    • Pro: exact control over every single output format.
    • Con: re-write so many output functions... writing overloads for new types by clients is a pain because they shouldn't write functions that fall in your library's namespace... unless you resort to Koenig (argument dependant) lookup!

    Approach 3: write a btree_traits<> template.

    • Pro: can come up with binary representation.
    • Pro: exact control over every single output format.
    • Pro: more control on output and format that a function, may contain meta data and all.
    • Con: still requires you / your library's users to write lots of custom overloads.
    • Pro: have the btree_traits<> detault to use operator<< unless someone overrides the traits?