Orthogonal Persistence of C++ Data Structures on the Internet Computer: A Study

Hello C++ developers,

I’ve been experimenting with orthogonal persistence of various C++ data structures in canisters on the Internet Computer (IC) and would like to share my findings with the community.

TL;DR
It works great!

Here are the key points:

  1. Data structures fully living in the global/static section of the stack are correctly persisted. This includes regular data types like int, float, uint64_t, etc. and the special STL container std::array, which keeps all its data on the stack.
  2. Self-managed dynamic data structures are correctly persisted too. This is when the data lives on the Heap, but the pointer to the data is in the global/static section of the stack. This was tested for both new/delete and calloc/free style memory management.
  3. Self-managed pointers to STL containers that use dynamic heap memory, like std::vector, std:string & std::unordered_map also work. As long as you self manage a pointer in the global/static memory, and then use new/delete on them inside your functions.
  4. Defining STL containers that use dynamic heap memory directly in global/static section is not working. Not only are they not persisted, just adding these to the global/static section corrupts the canister memory, even if you’re not using them at all… The tests show that the metadata for the std::vector (like its size and the Heap address pointed to by the vector) is persisted, but the actual values aren’t. I would love to get the perspective from the DFINITY team if they have any idea why adding STL containers like std::vector directly to the global/static section is not possible. Is this a bug in the Orthogonal Persistence code for canisters, or if not, can I enter a feature request to get it supported? It is not a blocker by any means, because options 1,2,3 all work perfect, but it would be good to support it.

To see the code & replicate this experiment, see GitHub: memory demo canister

3 Likes

Based on the outcome of this study, I updated/created these demos:

  • counter: An Orthogonal Persistence demo for uint64_t

  • counter4me: An Orthogonal Persistence demo for std::unordered_map<std::string, uint64_t>
    • With your principal as the key!!
    • dynamically create & grow the umap

  • counters: An Orthogonal Persistence demo for std::vector
    • dynamically create and grow the number of counters