Steps to implement the distributed annex from scratch

I’ve spent a little time looking into this since @dmitry-kazakov question in the other recent Polyorb topic, since I am also very curious.

Let me begin by admitting that my ‘advisor’ AIn’t all that reliable, so please take with a grAIn (or 2) of salt.

It appears that to implement DSA, you need to provide several DSA-related ‘System’ packages in a folder which is listed in the Source_Dirs in your gnat project file (or in a GPR which is ‘with’ed). In the standard runtime, these packages are just stubs. If Gprbuild/Gnatmake detect your own versions within the ‘Source_Dirs’, they will go into ‘distributed’ mode and generate the necessary ‘glue’ code to enable a distributed build.

By comparing Polyorb and Garlic implementations, the following files appear to be required …

  • s-dsaser.ads/b (System.DSA_Services)

    s-dsatyp.ads/b (System.DSA_Types)

    s-parint.ads/b (System.Partition_Interface)

    s-shasto.ads/b (System.Shared_Storage)

Only in Garlic are …

  • s-rpc.ads/b (System.RPC)

    s-shasto.ads/b (System.Shared_Storage)

Frankly, I’m not certain how reliable any of this is. I’m hoping it might provoke some better informed discussion. Perhaps @Max (who maintains the Garlic repo) might be able to help/elucidate.

Regards.

3 Likes

My attempt was this. I implemented s-rpc. Then I tried to compile a client with the interface package like this:

package Test_DSA_Server_Interface is
   pragma Remote_Call_Interface;

   procedure Increment_Count;
   function Get_Count return Natural;
   procedure Publish (Text : String);

end Test_DSA_Server_Interface;

Building fails with:

Compile
   [Ada]          test_dsa_server_interface.ads
cannot generate code for file test_dsa_server_interface.ads (package spec)

s-rpc is ignored. E.g. when modified, gprbuild does not compile it.

It depends on the functionality needed. For example, shared passive implementations only require a couple of routines that are called before/after reading/writing an object.

To build the distributed system, the compiler is invoked twice with different switches. The -gnatzc switch is used to create a stub on the client when compiling the remote module specification (.ads). The -gnatzr switch is used to create a wrapper on the server when compiling the body (.adb).

-gnatzc   Distribution stub generation for caller stubs
-gnatzr   Distribution stub generation for receiver stubs

The resulting binary modules call DSA routines; their approximate appearance can be viewed in the expanded code using the -gnatD switch.

There are two DSA support systems: the older Garlic and the more recent PolyORB. The compiler first determines which one is active by checking the s-parint.ads module, namely

PCS_Version : constant := 1; – means Garlic

Note, to let compiler find DSA support files they should be located in a special way. All .ali, .ad[sb] and libgarlic.a should be in the same folder (${PREFIX}/lib/garlic in my case).

Garlic is based on Ada.Streams. You need to provide a Stream implementation that the compiler will use to serialize arguments/results of remote routine calls. This should be written in System.RPC (type Params_Stream_Type). Then you’ll need to write a system for keeping track of remote units and partitions. The compiler identifies compilation units by name using a string type, and partitions by numeric identifiers. To avoid messing with compiler invocations and the -gnatzc/-gnatzr switches, they created the gnatdist utility. (Now that gprbuild is available, it’s probably not difficult to make it work without gnatdist.) It manages the system build, but the Garlic version is outdated, doesn’t handle project files, and requires an update. (Perhaps we should try the PolyORB version and see if it still works with Garlic, then turn it into an Alire crate.) I don’t know how PolyORB DSA works, because I focused on a simplest solution.

If you’re interested, we can start by creating a trivial DSA support system.

3 Likes

I did not understand anything of this complicated stuff. I do not want to use DSA, Garlic or PolyORB. I have a full implementation of System.RPC totally independent on these. Partitions are identified by numbers as they start. I can change that to the system process IDs. The backend supports both ways. So far my problem is that System.RPC is not recognized as such.

The purpose of stubs is unclear to me. In my simple mind if Remote_Call_Interface is specified the calls must go through my System.RPC. On the server side my RPC_Receiver is called. That is, no?

GNAT supports two DSA (Garlic, PolyORB). If you want your own you can 1) emulate one of these or 2) write new Ada compiler/hack GNAT. In my point of view the simplest way is to emulate Garlic. To make GNAT believe that there is Garlic installed you need PCS_Version in s-parint.ads, then place s-parint.ads, s-parint.adb, s-parint.ali in a folder findable by compiler.

The purpose of stubs is unclear to me.

Perhaps if you read Garlic docs you will understand better

Client’s stub is executed to make remote call instead of execution local implementation. Server’s side stub is executed by server’s thread in response on remote invocation. The first one serializes parameters into a stream and send it to the second. Server’s stub deserialize stream into arguments and call users code on the server side.

I think it would be better to have a better api which could allow people to provide their own implementation. GNAT would need to use this api and garlic/polyorb would be modified to fit the api.

1 Like

We could try to make adapter from Garlic to a better API as the first step.

So the answer is, the stuff is hard wired and cannot be replaced. :unamused:

To me System.PC specification in ARM is pretty clear. If the pragma provided the compiler must serialize parameters into a stream and then call Do_RPC or Do_APC. On the server side RPC_Receiver is called.

The term stub confused me. Normally, “stub” means an implementation that does nothing to be replaced later.

Yes. System.RPC must have an abstract tagged type to derive from. The DSA pragmas/aspects must have the derived type as a parameter.

An interface is a better api.

That error happens when you’re trying to compile the spec for a package which requires a body.

IIRC, the Ada spec allows for this already.

1 Like

It does not requires body because of:

pragma Remote_Call_Interface

Yes, of course, if possible.

Not really. Hacking system packages is not proper API.

This should be a GSOC project. Abstract out the Distributed Annex into an interface to allow for multiple back ends. Look for extensions to add to the next version of Ada.

2 Likes

?
That has almost nothing at all to do with what the Ada LRM says about the DSA.
A compiler could have a system that uses user-defined bodies if present in the project, defaulting to the current default; kind of like having a generic with an is null procedure parameter: you can override the default ‘do nothing’ with what you instantiate with.

I was sure there was some explicit things in the LRM, check out Section E.5.

It’s limited and should be updated.

See ARM E.5. It provides no means to provide implementation in a legal Ada way = per instantiation be it generic or tagged extension.

= hacking system packages.

There is a very easy way to confirm this. Just provide steps to implement the annex. It is actually the topic of this discussion.

That would be ideal. I’m very interested and willing to spend considerable time coding/documenting, if given direction. Maybe we could start a git repo, perhaps named mini_DSA or similar ?

3 Likes