Constants/Tweaks

Object Methods

Synchronous, asynchronous and transactional programming

Most APIs will be synchronous. APIs that would block for significant time should be (such as those that send a message and wait for a reply) offered as both synchronous and asynchronous flavors. This shall be implemented as follows:

Example:

Version HelloExchange(int node, Version myVersion, Wakeable& wake); // Returns other node's version, raises exception on error

Application code can call this function in the following ways:

   1 HelloExchange(1,"1.0.0");

   1 ThreadSemaphore sem;
   2 HelloExchange(1,"1.0.0",sem);
   3 sem.take();  // Blocks until hello exchange "gives" the semaphore
   4 







Configuration

All SAFplus components manage their configuration via the SAFplus::Mgt objects and backing database. SAFplus will convert XML configuration files from and to the database (automatically on startup if the DB does not exist) so no direct use of XML is necessary.

Statistics

Statistics are reported through the same SAFplus::Mgt objects (but statistics are not stored to the Database)

Fault

If a component takes a fault, it may assert. If a component detects a fault, timeout or other error in another component, it must report that error to the Fault Manager component and then retry. It may not assume that the other component is faulted, failed or dead until it receives a notification from the Fault Manager announcing the component's failure.

The Fault Manager is authoritative:

If a component is working fine and receives an announcement reporting its own failure, it must quit. If a component thinks that another component is working but receives a fault manager notification of its death, it must behave as though the component has failed.

Allocation/Free

Reduce use of new/delete or malloc/free. These operations are inefficient, and often turn an O(1) operation to O(log(n)) where n is the number of memory fragments in the program.

Use "intrusive" data structures whereever possible, since other data structures must malloc metadata.

One common design pattern is to reuse objects. Define the object with an intrusive list, and add "Object* allocObject()" and "void freeObject(Object*)" helper functions. The "freeObject" function puts the object onto a "free list". The allocObject removes an object from the free list (if one exists). If no object exists on the list, it creates a new object using new or malloc. This technique has a few advantages:

  1. Performance: reduced use of malloc/free or new/delete
  2. Memory corruption: Use-after-free bugs do not corrupt a random block of memory, but an instance of Object*. This causes the bug to be located nearer to its source. Also, you have the option to add debugging code to freeObject(). This code could record the file/line of the caller to freeObject, it could clear the object being freed to force a seg fault in the case of use-after-free.
  3. allocObject can return the most recently used object, increasing data locality (reducing cache misses).
  4. Memory leaks: allocObject and freeObject can keep call counts which should on average be =. Also, after some time, allocObject should never need to call "new" or "malloc".

Note, you can have allocObject/freeObject delete some of the objects on the list if they are not used for a significant period of time to reduce memory use.

SAFplus: General Design Requirements (last edited 2015-03-03 19:29:29 by AndrewStone)