A gem amongst gems

In the process of reviewing the Ada Gems, I was amazed by this feature:

Who knew about this one? (Honestly ^^)

12 Likes

I did not know it, though I worked on persistency a lot.

However there are issues with that:

  1. In practice you want to use some other backend than arbitrary files, typically a database or a configuration file in a certain format like registry or XML;
  2. Portability is a big issue. You want to access storage from different platforms and move it across the platforms;
  3. You need a lot of work for linked structures, like graphs, links etc;
  4. You also need to handle tagged types, i.e. you need some means to store and restore tags and then construct objects from;
  5. External references is another problem. You might have not only internal links that can be stored as offsets to the first allocated element, but also a closure of objects your persistent object refers to. Since objects can be shared you need to handle multiple references and maintain a catalogue of objects in the persistent storage. Then you need some policy of updating shared objects.

I really like the Ada gems series for things just like this. I hope they never take the archive down as it is a really valuable resource.

3 Likes

I did.
I used it to implement configuration for a bit of custom logging. — Basically a store of Pascal-style strings (256-bytes: 1 length byte, followed by the string data), plus the integral data.

I don’t know that I agree; for many things, yes… but for small things with very few parameters?

I mean, you’re using Shared_Passive, which means that you should be able to hook it into a DSA program easily. (Though, TBF, I think the LRM stance on DSA programs are that it’s implementation-defined; which makes sense: incorporating a truly portable RPC/data-communication protocol would be (a) constraining all DSA programs to those protocols, and (b) would entail incorporation-by-reference to something that would likely be ASN.1 or something of similar capability.)

This is perhaps the place that current Ada disappoints the most: it’s rather obvious that the original (Ada83) design was done with the idea of being able to incorporate self-referential datastructures like the aforementioned, when “compiler/language technology caught up”, such that you could make lists/graphs/links. (Actually, I suspect that the access type was always meant to be key: that the Cursor-type in the Ada.Containers.* packages should be access types, discriminated by the container.)

Honestly, at that point what would be useful is a common Ada+PL/SQL runtime, with the runtime containing a full database-engine.

That is why pragma does not scale. You need a primitive operations implementing storing/restoring, just like stream attributes that do same thing for serialization.

Recursive types simply do not work. The ugly truth is that you need forward and backward links, strong and weak references. For example, I frequently implement graphs that share subgraphs for performance reasons. When a subgraph is updated by one client it is cloned when referenced by other clients.

No, it is just a wrong design. The implementation must support whatever user-provided persistency layer rather than forcing certain engine.

Consider cases when some updates happen in situ rather than the whole thing is stored/restored. You might have gigabytes of persistent objects.

No, you don’t.
(Off the top of my head, using this for extremely simple config.)

Package Example_Config with Shared_Private is
  Type Pascal_String is private;
   Procedure Set( Value : String; Object : in out Pascal_String )
     with Pre => Value'Length in 0..255;
   Procedure Get( Object : Pascal_String ) return String;

  Login    : Constant Pascal_String;
  Password : Constant Pascal_String;
  Port     : Constant Integer;
Private
  Subtype Byte is Interfaces.Unsigned_8;
  Type Internal_String_Data is Array(Byte range <>) of Character;
  Type Internal_String( Length : Byte ) is Record
    Data : Internal_String_Data( 1..Length );
  End record with Size => 8*256;

  Type Pascal_String is null record with Size => 8*256;
  -- And all the conversion routines.

  -- We set these with a config routine, they stay until re-configured or deleted.
  Login    : Constant Pascal_String:= (0, (others => ASCII.NUL));
  Password : Constant Pascal_String:= (0, (others => ASCII.NUL));
  Port     : Constant Integer:= 0;
End Example_Config;

In-situ is a non-issue.
SQL’s the PSM (Persistent Storage Module) —colloquially “PL/SQL”— is more about triggers, stored procedures, etc, and SQL is about providing query to database/storage. There’s nothing preventing the “database” from being a single file, an external-link/-object, or anything else… indeed, Part 9 of the SQL standard is “Management of External Data”.

The word “extremely” is the key here. You can start with versioning config versions, language support and types other than string. Even primitive init-file engines are capable of more.

You missed the point. When dealing with persistency there are two choices: #1 to restore the object update the proxy and store it back or #2 to update the object directly in the store.

In your example consider updating the password without restoring login and conversely restoring all user authentication, updating and storing it back.

P.S. The bottom up way of thinking and designing is poor engineering which will inevitably hit you back once faced real life.

Yes; that’s exactly the point.

I think you misunderstand: the logging-system only needed the login/password to access internal (literally a local server) e-mail; throwing the config in shared-passive (not quite “in the exe”; as it’s a flat-file that is generated w/ the defaults if it doesn’t exist), and was the perfect choice for something that needed minimal config. (i.e. an INI or XML file would have been overkill.)

I did. I saw the gem many years ago, and used it to keep track of a sequence number in a communication process. The protocol wants the telegrams order by sequence num, which increases by 1 for each tgm. To make the other side happy I saved the sequence num on disk through this pragma, so I did not need to serialize it myself. It is read upon restart which was the point.
That protocol was later changed to accept 0 as a restart marker.
I also customized the storage format. at firs it was just 4 integers (32 bit num) but I made it human readable.
It is still running on that site.

1 Like