I would like to announce that OpenSAF now has a policy regarding
limits: limits should, in general, be possible to configure without
recompiling the source code. This means that we would like to move
away from using hard-coded limits, and we would like the code to be
designed in scalable way so that limits can be increased. This way, we
can ensure that OpenSAF is flexible enough to be used in a wide
variety of applications and deployments.

The rest of this message contains some detailed discussions around
limits. Read on if you are interested, but the main point of this
message has already been covered. :-)

First of all I would like to point out that instead of making a limit
configurable, the limit could be removed altogether. However, in many
cases there is a good reason to have a limit, especially in the case
of resource limits that I will describe in more details below. The
main reason for having a limit is to protect the system from a
misbehaving application. There are many reasons why an application may
misbehave so that it will exceed the limits we have set:

* Due to a resource leak
* Due to a fault in the program logic (e.g. miscalculating the size)
* Due to memory corruption
* Due to an attack

By having a limit, we can detect the problem early and stop it before
the whole system becomes unstable.

EXPLICIT LIMITS
===============

Resource limits
---------------

By a resource limit I mean a limit for something that the application
allocates and deallocates. Thus, if the application forgets to
deallocate the resource, we have a resource leak. We are mainly
concerned about resources that are visible outside the application
process: a resource that is allocated either in the memory of an
OpenSAF service, on disk, or in the Linux OS (e.g. a shared memory
segment). If the resource is allocated locally inside the application
then a resource leak could be regarded as an ordinary memory leak in
the application.

A typical example of a resource is a SAF handle returned by one of the
saXxxInitalize() functions. Compare this with a file handle in
Linux. In Linux, there are two limits for file handles: a per-process
limit that can be configured using the setrlimit() system call, and a
system-global limit that can configured using the /proc file
system. The reason for having a per-process limit is that if the
application process is leaking file handles, we don't want it to
exhaust all available file handles in the entire system. Therefore,
the per-process limit is set to a small value (1024 by default) that
is much lower than the system-global limit.

Size limits
-----------

By size limit I mean typically the maximum size for an object. It
could for example be a maximum string length. Again, if the string is
just allocated locally in the application process, we don't have to be
so concerned about it. But if the string is passed as a parameter to
an OpenSAF service, we may wish to protect the service against
receiving too large strings. Imagine that the application has a memory
corruption bug, so that the variable containing the length of the
string is garbled. The OpenSAF service would receive an insanely large
string, which if not rejected is likely to cause problems to the
service.

Distinguished names, normally stored in the SaNameT type, is an
example for which we have a size limit. Unfortunately, the size limit
is in this particular case specified by the SAF standard, and is
therefore difficult to change. However, there are suggestions for how
we can make an OpenSAF extension that would allow longer distinguished
names.

Time limits
-----------

Time limits, or maybe timeout limits, is yet another category of
limits. There may be a need to configure time limits differently on
different types of systems. OpenSAF can be used on large systems with
many nodes, possibly geographically distributed, and with a large disk
accessed over the network. Or it may be used on a small two-node
embedded system with a fast node-local solid state disk or flash
memory.

IMPLICIT LIMITS
===============

The different types of limits mentioned above are expressed explicitly
in the code; there is a place in the code where we check if we are
above or below the limit, and take different actions depending on
this. I would also like to mention implicit limits; limits that are
not expressed directly in the code, but rather are the results of the
way the code is written: the data types, OS functions or algorithms
that were chosen. The sections below describe different types of
implicit limits:

Limited range of (integer) data type
------------------------------------

A 64-bit integer can for all practical purposes be regarded as being
able to hold an infinite range of numbers. There may be a perfectly
good reason to use a smaller integer type in order to save memory,
network bandwidth, or disk space. But please be careful to ensure that
the data type has sufficient range to hold all possible values also in
the case where the OpenSAF limits have been configured to be larger
than default.

Fixed-size buffers
-------------------------

Prefer to use dynamically allocated buffers of variable size instead
of fixed-size buffers. In C++, this is easy: use std::string or
std::vector. In C, you can use malloc() to dynamically allocate a
buffer. A fixed-size buffer may be sufficient for internal data that
is only used within OpenSAF, for example as a scratch buffer for
formatting a log message. But if the buffer contains application data,
or if it contains something that can be configured, for example a
path, then it is better to use a variable-size buffer. Using
variable-size buffers will in general also be more memory efficient,
since the buffer will only be as large as needed.

Deprecated operating system interfaces
--------------------------------------

Operating system interfaces can also have limits, and in many cases
there is a new variant of the same interface where the limit has been
removed. Prefer to use these newer variants; it is usually not more
difficult than using the old ones, and sometimes easier. Some
examples:

* Use epoll() or poll() instead of select(). Otherwise we are limited
   to a maximum of 1024 file handles. This is especially important when
   writing code that will be used in an agent library, since it
   executes in the same process as an application program.

* Use thread-safe variants (normally ending with the _r suffix) where
   available. E.g. use localtime_r() instead of localtime(). Otherwise
   we are limited to single-threaded programs. This is especially
   important when writing code that will be used in an agent library,
   since it executes in the same process as an application program.

* Use fseeko() and ftello() instead of fseek() and ftell(). Otherwise
   file size is limited to 2 gigabytes on 32-bit systems. For the same
   reason, also make sure that the macro _LARGEFILE_SOURCE is defined.

* When using functions for IP communication, use the newer variants
   that support both IPv4 and IPv6 instead of the old ones that only
   support IPv4. E.g. use inet_pton() instead inet_aton() or
   inet_addr().  Otherwise we are limited to using IPv4 addresses only.

* Prefer the functions sysconf(), pathconf() and getrlimit() over the
   corresponding macros for reading system limits. E.g. use
   sysconf(_SC_HOST_NAME_MAX) instead of HOST_NAME_MAX, and
   pathconf(_PC_PATH_MAX) instead of PATH_MAX. This is mainly a
   portability issue since POSIX does not require these limit to be
   fixed, and the macros are not required to be defined.

Inefficient algorithms
----------------------

Even though it may not cause a theoretical limit, the use of
inefficient algorithms and data structures may in practice have the
effect that the limits cannot be increased since the system would
become too slow. Prefer to use efficient algorithms and design the
code so that it is scalable. For example, use a tree data structure or
a hash table instead of using linear search in a linked list. In C++,
this is easy: just switch to a different container type. std::set and
std::map provide tree data structures, and std::unordered_set and
std::unordered_map provide provide hash tables.

regards,
Anders Widell


------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to