--- /dev/null
+..
+.. Copyright (c) 2019 AT&T Intellectual Property.
+.. Copyright (c) 2019 Nokia.
+..
+.. Licensed under the Creative Commons Attribution 4.0 International
+.. Public License (the "License"); you may not use this file except
+.. in compliance with the License. You may obtain a copy of the License at
+..
+.. https://creativecommons.org/licenses/by/4.0/
+..
+.. Unless required by applicable law or agreed to in writing, documentation
+.. distributed under the License is distributed on an "AS IS" BASIS,
+.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+..
+.. See the License for the specific language governing permissions and
+.. limitations under the License.
+..
+
+
+###############
+Developer Guide
+###############
+
+.. raw:: pdf
+
+ PageBreak
+
+.. contents::
+ :depth: 3
+ :local:
+
+.. raw:: pdf
+
+ PageBreak
+
+Introduction
+************
+
+This is the developer guide of O-RAN SC SDL C++ library.
+SDL implementation downloading (execute command in such directory where you want
+to download SDL repository).
+
+Without commit hook::
+
+ git clone "https://gerrit.o-ran-sc.org/r/ric-plt/sdl"
+
+With commit hook::
+
+ git clone "https://gerrit.o-ran-sc.org/r/ric-plt/sdl" && (cd "sdl" && mkdir -p .git/hooks && curl -Lo `git rev-parse --git-dir`/hooks/commit-msg https://gerrit.o-ran-sc.org/r/tools/hooks/commit-msg; chmod +x `git rev-parse --git-dir`/hooks/commit-msg)
+
+
+SDL has only few dependencies to other components and therefore SDL should be
+quite simple to build and install to almost any modern Linux environment by
+following instructions below.
+
+If not otherwise mentioned, commands in this document are executed in the
+directory where the SDL repository has been cloned into.
+
+.. raw:: pdf
+
+ PageBreak
+
+Compilation
+***********
+
+**Dependencies**
+
+C++ compiler supporting C++14 is required for compiling SDL.
+
+Currently, the following library is required while building:
+
+* boost
+* hiredis
+* doxygen (optional)
+
+Commands to install dependent packages in Fedora::
+
+ sudo dnf install boost-devel
+ sudo dnf install hiredis-devel
+ sudo dnf install doxygen
+
+Commands to install dependent packages in Debian/Ubuntu::
+
+ sudo apt install libboost-all-dev
+ sudo apt install libhiredis-dev
+ sudo apt install doxygen
+
+**Compilation in the Source Directory**::
+
+ ./autogen.sh
+ ./configure
+ make all
+ make test
+
+**Compilation in a Separate Build Directory**
+
+Both *configure* and *make* can be executed in a separate directory
+(or directories) for keeping the source directory clean or for testing
+different configuration options in parallel. For example::
+
+ ./autogen.sh
+ mkdir build
+ cd build
+ ../configure
+ make all
+ make test
+
+Note that if you compile SDL this way, all coming *configure* and *make*
+commands are executed in the build directory like above.
+
+.. raw:: pdf
+
+ PageBreak
+
+Installation
+************
+
+By default the shared library is installed to */usr/local/lib* and headers into
+to */usr/local/include*. If this is not desired, then provide different path
+when running *configure*, for example::
+
+ ./configure --prefix=$HOME
+
+Note that *configure* command allows plethora of additional options. For more
+info::
+
+ ./configure --help
+
+After configuration has been done, run::
+
+ make install
+
+.. raw:: pdf
+
+ PageBreak
+
+.. _building_sdl_api_doc:
+
+Building SDL API Document
+*************************
+
+SDL API Documentation is a Doxygen document generated from SDL public header
+files.
+
+One can generate Doxygen documentation locally by running commands::
+
+ ./autogen.sh
+ ./configure
+ make doxygen-doc
+
+in the directory where the SDL repository has been cloned to.
+
+
+By default make doxygen-doc creates HTML, PDF and PS documents (if the needed
+tools are available, check the output of *./configure* command to get the names
+of missing tools). The documents are created to (paths are relative to the
+directory where the SDL repository has been cloned to):
+
+* doxygen-doc/html/index.html
+* doxygen-doc/shareddatalayer.pdf
+* doxygen-doc/shareddatalayer.ps
+
+
+Creation of different document formats can be controlled with various
+--enable-doxygen-* and --disable-doxygen-* configuration options. For example
+if only HTML document is needed, then run::
+
+ ./configure --disable-doxygen-pdf --disable-doxygen-ps
+ make doxygen-doc
+
+.. raw:: pdf
+
+ PageBreak
+
+Running Tests
+*************
+
+Unit Tests
+==========
+
+Unit tests are compiled and executed by simply running::
+
+ make test
+
+By default all unit tests are executed. If *valgrind* is installed, then by
+default unit test execution is analyzed with *valgrind*.
+
+Running specific test cases can be achieved by using *GTEST_FILTER* environment
+variable. For example::
+
+ make test GTEST_FILTER=AsyncStorageTest*
+
+If *valgrind* is not desired (even if installed), then it can be disabled with
+*USE_VALGRIND* environment variable::
+
+ make test USE_VALGRIND=false
+
+Additional *valgrind* arguments can be specified with *VALGRIND_EXTRA_ARGS*
+environment variable. For example::
+
+ make test VALGRIND_EXTRA_ARGS='--track-fds=yes --log-file=mylog.txt'
+
+It is also possible to use the *testrunner* binary directly (after it has been
+compiled). The *testrunner* binary supports all the command line options gtest
+supports, for example::
+
+ make testrunner
+ ./testrunner --help
+ ./testrunner
+ ./testrunner --gtest_filter=AsyncStorageTest*
+
+Functional Tests
+================
+
+Functional tests are not yet available.
+
+.. raw:: pdf
+
+ PageBreak
+
+Debugging SDL Binaries
+**********************
+
+The testrunner and other binaries created by make into the working
+directory are not real binaries but shell scripts (generated by automake)
+used for running the real binaries. The real binaries are in .libs directory.
+Normally this is not important, but when using gdb or other debugger/analyzer
+tools it is important to use the real binary instead of the generated shell
+script.
+
+Examples below demonstrate how one can run testrunner binary (unit tests) in
+gdb debugger::
+
+ LD_LIBRARY_PATH=.libs gdb --args .libs/testrunner
+ LD_LIBRARY_PATH=.libs gdb --args .libs/testrunner --gtest_filter=AsyncStorageTest*
+
+.. raw:: pdf
+
+ PageBreak
+
+Redis
+*****
+
+When Redis type backend data storage is used, SDL requires Redis v4.0 or
+greater. Older versions do not support extension modules.
+
+Redis Modules
+=============
+
+When Redis type backend data storage is used, SDL requires that the following
+Redis extension commands have been installed to runtime environment:
+
+* MSETPUB
+* SETIE
+* SETIEPUB
+* SETNXPUB
+* DELPUB
+* DELIE
+* DELIEPUB
+
+Implementation for these commands is produced by RIC DBaaS. In official RIC
+deployments these commands are installed by DBaaS service to Redis
+container(s). In development environment you may want install commands
+manually to pod/container which is running Redis.
+
+**Manual Redis module installing**
+
+Redis module implementation downloading (execute command in such directory
+where you want to download redis module implementation)::
+
+ git clone "https://gerrit.o-ran-sc.org/r/ric-plt/dbaas"
+
+Installation to default system directory::
+
+ cd redismodule
+ ./autogen.sh
+ ./configure
+ make install
+
+Following line should be added to *redis.conf* file::
+
+ loadmodule <path>/libredismodule.so
+
+<path> should be replaced to match library installation directory path.
+
+*redis-server* must be restarted after configuration file update.
+
+Notice that *redis-server* takes path to configuration file as an argument.
+If not given, *redis-server* will start with default parameter values and above
+made *loadmodule* option is not effective. Refer to::
+
+ redis-server --help
+
+SDL API will check in connection setup phase that all required Redis extension
+commands are available, if not then execution is aborted and error log is
+written to identify which commands are missing.
+
+.. raw:: pdf
+
+ PageBreak
--- /dev/null
+..
+.. Copyright (c) 2019 AT&T Intellectual Property.
+.. Copyright (c) 2019 Nokia.
+..
+.. Licensed under the Creative Commons Attribution 4.0 International
+.. Public License (the "License"); you may not use this file except
+.. in compliance with the License. You may obtain a copy of the License at
+..
+.. https://creativecommons.org/licenses/by/4.0/
+..
+.. Unless required by applicable law or agreed to in writing, documentation
+.. distributed under the License is distributed on an "AS IS" BASIS,
+.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+..
+.. See the License for the specific language governing permissions and
+.. limitations under the License.
+..
+
+
+##########
+User Guide
+##########
+
+.. raw:: pdf
+
+ PageBreak
+
+.. contents::
+ :depth: 3
+ :local:
+
+.. raw:: pdf
+
+ PageBreak
+
+Introduction
+************
+
+This is the user guide of O-RAN SC SDL C++ library.
+Shared Data Layer (SDL) provides a lightweight, high-speed interface (API) for
+accessing shared data storage. SDL can be used for storing and sharing any
+data. Data can be shared at VNF level. One typical use case for SDL is sharing
+the state data of stateful application processes. Thus enabling stateful
+application processes to become stateless, conforming with, e.g., the
+requirements of the fifth generation mobile networks.
+
+Figure below illustrates some main points of SDL:
+
+.. image:: ./_static/sdl_intro.png
+ :align: center
+ :alt: SDL introduction
+
+SDL has been implemented in many languages:
+
+* C++ Linux shared library
+* Golang package
+* Python package
+
+This document focuses on C++ implementation of SDL but general principles are
+the same in all implementations.
+
+.. raw:: pdf
+
+ PageBreak
+
+Key Concepts
+************
+
+**Backend Data Storage**
+
+Backend data storage refers to data storage technology behind SDL API which
+handles the actual data storing. SDL API hides the backend data storage
+implementation from SDL API clients, and therefore backend data storage
+technology can be changed without affecting SDL API clients. Currently, Redis
+database is the most commonly used backend data storage implementation.
+
+Figure below illustrates how SDL API hides backend data storage technology
+from application:
+
+.. image:: ./_static/backend_data_storage.png
+ :align: center
+ :alt: SDL API hides backend data storage technology from application
+
+`SDL Deployment section <#sdl-deployment>`_ provides further information
+about backend data storage deployment options.
+
+**Namespace**
+
+Namespaces provide data isolation within SDL data storage. That is, data in
+certain namespace is isolated from the data in other namespaces. Each SDL
+client uses one or more namespaces.
+
+Namespaces can be used, for example, to isolate data belonging to different
+use cases.
+
+Figure below shows an example of the SDL namespace concept. There are two SDL
+clients, both accessing SDL backend data storage using an SDL API instance
+(C++ object). Client 1 uses both namespaces: A and B, while client 2 uses only
+namespace: B. Therefore, data in the namespace: A is visible only to client 1
+and data in namespace: B is shared between clients 1 and 2:
+
+.. image:: ./_static/sdl_namespaces.png
+ :align: center
+ :alt: SDL namespace concept example
+
+Namespace management is planned to be moved under a managing entity which
+enforces some control over how the namespaces are created. For now, however,
+namespace naming needs to be manually coordinated between clients.
+
+**Keys and Data**
+
+Clients save key-data pairs. Data is passed as byte vectors. SDL stores the
+data as it is. Any structure that this data may have (e.g. a serialized JSON)
+is meaningful only to the client itself. Clients are responsible for managing
+the keys. As namespaces provide data isolation, keys in different namespaces
+always access different data.
+
+.. raw:: pdf
+
+ PageBreak
+
+APIs
+****
+
+SDL provides currently following APIs:
+
+* Asynchronous API for accessing SDL storage *shareddatalayer::AsyncStorage*
+* Synchronous API for accessing SDL storage shareddatalayer::SyncStorage
+
+Same SDL client can use one or more SDL APIs. There should rarely be need to
+create several instances of the same SDL API though. All individual operations
+done using SDL API functions are targeted to one namespace (accessing several
+namespaces requires multiple operations).
+
+SDL API functions are not thread-safe, meaning that same SDL instance must
+not be shared between multiple threads without explicit locking in SDL client.
+
+SDL API functions are atomic unless otherwise indicated. Indication of the
+non-atomic behavior of certain function can be found from one or many of the
+following:
+
+* Function name
+* Function parameters
+* Function doxygen documentation (see below)
+
+Refer to doxygen generated SDL API documentation below for further information
+about SDL APIs and the functions they contain.
+
+Doxygen Generated SDL API Documentation
+=======================================
+
+Pre-built online version of SDL API Doxygen documentation is not yet available.
+
+Doxygen documentation can be generated manually. Follow instructions found from
+:ref:`SDL developer guide <building_sdl_api_doc>`.
+
+.. raw:: pdf
+
+ PageBreak
+
+Building Clients Using SDL
+**************************
+
+SDL API functions can be used by including SDL public headers and by linking
+SDL shared library.
+
+The necessary compilation and linker flags can be acquired with the
+*pkg-config* tool::
+
+ pkg-config --cflags libsdl
+ pkg-config --libs libsdl
+
+SDL internal implementation uses C++14, thus SDL clients need to be build
+using a C++ compiler supporting C++14. However, SDL public API header files
+contain only features which are available in C++11, thus SDL clients do not
+need to be implemented (and compiled) using C++14 (C++11 is enough). The
+compiler just needs to have support for C++14.
+
+.. raw:: pdf
+
+ PageBreak
+
+Using SDL in Application Pod
+****************************
+
+SDL binary artifacts including Debian (.deb) and RPM Package Manager (.rpm)
+packages are available in O-RAN-SC PackageCloud.io repository.
+
+In runtime environment SDL needs also a database backend service, currently
+SDL supports only Redis database. Recommended solution is to use DBaaS
+component of the official RIC platform deployment.
+
+**Deploying SDL database backend with DBaaS service in the RIC**
+
+Download RIC deployment artifacts::
+
+ git clone "https://gerrit.o-ran-sc.org/r/it/dep"
+
+The **ric-platform** directory contains Helm chart and scripts to deploy RIC
+platform components, including also DBaaS component.
+
+RIC DBaaS service must be running before starting application pod which is
+using SDL API. DBaaS defines environment variables which are used to contact
+DBaaS service (offering backend for SDL). Those environment variables are
+exposed inside application container only if DBaaS service is running when
+application container is started. Refer to
+`Database Backend Configuration section <#database-backend-configuration>`_,
+for information about available environment variables.
+You may test SDL connectivity to its backend with the *sdltool* command inside
+your application container::
+
+ sdltool test-connectivity
+
+*sdltool* comes in SDL binary artifacts which are available in O-RAN-SC
+PackageCloud.io repository.
+
+For more information, see also `README <https://gerrit.o-ran-sc.org/r/gitweb?p=ric-plt/dbaas.git;a=blob;f=README.md;h=6391fc45ea762a5b606dcf9f867fac8087b1222f;hb=HEAD>`_
+file of the *dbaas* O-RAN-SC gerrit repository.
+
+.. raw:: pdf
+
+ PageBreak
+
+Configuration
+*************
+
+Certain aspects in SDL functionality can be configured by using environment
+variables.
+
+Database Backend Configuration
+==============================
+
+Database backend configuration can be used to configure, to which database
+backend SDL instance connects. A list of available environment variables to
+configure database backend:
+
+* DBAAS_SERVICE_HOST
+* DBAAS_SERVICE_PORT
+* DBAAS_SERVICE_SENTINEL_PORT
+* DBAAS_MASTER_NAME
+
+After DBaaS service is installed, environment variables are exposed to
+application containers. SDL library will automatically use these environment
+variables. If DBaaS service is not used, above environment variables needs to
+be set manually so that SDL backend can connect to correct database.
+
+**Examples**
+
+An example how environment variables can be set in bash shell, when standalone
+Redis server is running in a Kubernetes Pod with k8s service name of *dbaas* and
+port *6379*::
+
+ export DBAAS_SERVICE_HOST=dbaas
+ export DBAAS_SERVICE_PORT=6379
+
+Besides hostname, IPv4 and IPv6 addresses can be set to *DBAAS_SERVICE_HOST*.
+
+An example how environment variables can be set in bash shell, when Redis
+HA deployment is used. Please note that DBaaS does not support yet HA
+deployment option. Below environment variables are only in the form of an
+example to show how HA deployment would be configured::
+
+ export DBAAS_MASTER_NAME=my-master-sentinel
+ export DBAAS_SERVICE_HOST=dbaas
+ export DBAAS_SERVICE_SENTINEL_PORT=23550
+
+.. raw:: pdf
+
+ PageBreak
+
+Errors
+******
+
+`Doxygen generated SDL API documentation <#doxygen-generated-sdl-api-documentation>`_
+describes which error codes are returned and which exceptions are thrown from
+each SDL API function. Generally, asynchronous SDL APIs return error codes and
+synchronous SDL APIs throw exceptions in error situations.
+
+Handling Error Codes Returned From Asynchronous SDL APIs
+========================================================
+
+Asynchronous SDL APIs return *std::error_code* based error codes in error
+situations. Typically, error code is returned as a parameter in the related
+callback function.
+
+Returned error code contains detailed information about the error which has
+occurred. This information is valuable for SDL developers in case the issue
+needs further investigation, but usually this information is too detailed for
+SDL client error handling logic. For SDL client error handling purposes SDL
+provides *shareddatalayer::error* constants and the returned *std::error_code*
+can be compared against these constants.
+
+Therefore SDL clients are recommended to store the returned *std::error_code*
+somewhere (for example to the log) and implement the error handling logic based
+on *shareddatalayer::error* constants. C++ code example below illustrates this:
+
+.. code-block:: c++
+
+ if (error)
+ {
+ log.error() << "SDL operation failed, error: " << error
+ << " message: " << error.message() << std::endl;
+
+ if (error == shareddatalayer::Error::NOT_CONNECTED)
+ // Error handling logic for shareddatalayer::Error::NOT_CONNECTED
+ else if (error == shareddatalayer::Error::OPERATION_INTERRUPTED)
+ // Error handling logic for shareddatalayer::Error::OPERATION_INTERRUPTED
+ else if (error == shareddatalayer::Error::BACKEND_FAILURE)
+ // Error handling logic for shareddatalayer::Error::BACKEND_FAILURE
+ else if (error == shareddatalayer::Error::REJECTED_BY_BACKEND)
+ // Error handling logic for shareddatalayer::Error::REJECTED_BY_BACKEND
+ }
+
+*error* in the code block above is *std::error_code* type variable which is
+returned from some asynchronous SDL API function. *log* is a logging service
+what an SDL client is using. Note that this is a simple and incomplete example
+for demonstration purposes and not meant to be used as such in real
+environment. Complete error handling implementation depends on SDL client and
+SDL API function which returned the error. For example, in some cases common
+handling for several *shareddatalayer::error* constants might be sufficient.
+
+**Instructions for Error Handling Logic Implementation**
+
+Doxygen documentation contains detailed description for all
+shareddatalayer::Error constants. This information helps to design error
+handling logic for each shareddatalayer::Error constant. For example, following
+information can be found from there:
+
+* What has happened
+* Is data modified in the backend data storage
+* How to recover from error situation
+
+
+Handling Exceptions Thrown by Synchronous SDL APIs
+==================================================
+
+Synchronous SDL APIs throw exceptions in error situations. There are
+corresponding exceptions for all *shareddatalayer::error* constants returned
+by asynchronous APIs (see previous section). All exceptions thrown by SDL are
+derived from *shareddatalayer::Exception*.
+Therefore, a client can catch *shareddatalayer::Exception* in case the client
+wants to implement common handling for some SDL originated exceptions. Note
+that external services, which SDL uses, can throw exceptions which are not
+derived from *shareddatalayer::Exception*.
+
+Below is a C++ code example of a scenario where SDL client does common error
+handling for all exceptions thrown from synchronous SDL API:
+
+.. code-block:: c++
+
+ try
+ {
+ //Code which executes synchronous SDL API function
+ }
+ catch (const shareddatalayer::Exception& e)
+ {
+ log.error() << "SDL operation failed, error: " << e.what() << std::endl;
+ //Common error handling logic for all SDL errors
+ }
+ //Catch also non-SDL exceptions (like std::exception) if needed
+
+Below C++ code example has separate handling for shareddatalayer::BackendError
+exception and common handling for all other exceptions thrown by SDL:
+
+.. code-block:: c++
+
+ try
+ {
+ //Code which executes synchronous SDL API function
+ }
+ catch (const shareddatalayer::BackendError& e)
+ {
+ log.error() << "SDL operation failed, error: " << e.what() << std::endl;
+ //Error handling logic for BackendError
+ }
+ catch (const shareddatalayer::Exception& e)
+ {
+ log.error() << "SDL operation failed, error: " << e.what() << std::endl;
+ //Common error handling logic for all other SDL errors than BackendError
+ }
+ //Catch also non-SDL exceptions (like std::exception) if needed
+
+*log* is a logging service what an SDL client is using. Note that these are
+simple and incomplete examples for demonstration purposes and they are not
+meant to be used as such in real environment.
+
+**Instructions for Error Handling Logic Implementation**
+
+Doxygen documentation contains documentation for all exceptions thrown by SDL.
+This documentation contains information which helps to design error handling
+logic for each exception. For exceptions having corresponding error code,
+exception documentation is usually a reference to corresponding error code
+documentation.
+
+Each SDL API function, which throws exceptions, has a link to the documentation
+of those exceptions. This link can be found from the Doxygen documentation of
+given SDL API function.
+
+.. raw:: pdf
+
+ PageBreak
+
+SDL Properties
+**************
+
+This chapter discusses how certain general data storage related aspects work in
+SDL. Discussed subjects include, for example, concurrency control and data
+persistency.
+
+SDL Deployment
+==============
+
+Production environments are typically deployed so that SDL backend data storage
+and SDL clients are in different nodes (e.g. VM, container).
+
+There are two different supported deployment modes for SDL backend data
+storage:
+
+* Standalone (single DB node without redundancy)
+* Redundant (DB node pair working in master/slave redundancy model)
+
+SDL does not currently have any intelligent logic (e.g. dynamic scaling) on
+which storage node each namespace data is stored. This area might be developed
+further in the future.
+
+SDL does not prevent backend data storage to be deployed in the same node with
+the SDL client. Such deployments are, however, typically used only in
+development/testing type of environments.
+
+Concurrency Control
+===================
+
+SDL does not support transactions doing one or more units of work in ACID
+manner (pessimistic concurrency control).
+
+SDL supports optimistic concurrency control by providing Check and Set (CAS)
+type conditional functions. These conditional functions provide possibility
+to do certain data modification operations only if data value matches the SDL
+client's last known value. Thus a SDL client can check that someone else has
+not changed the data after it was read by the SDL client. If the data would
+have been changed, SDL does not do the modification operation and this is
+indicated to the SDL client. The SDL client can then decide how to handle the
+situation (for example read the latest data and retry modification).
+
+*AsyncStorage::setIfAsync* is an example of a conditional function discussed
+above. Other conditional functions exist as well.
+
+Data Persistency
+================
+
+Currently all data stored to SDL is stored to in-memory backend data storage.
+Meaning that, data is not preserved over DB node restart. DB node restart does
+not necessarily cause data loss for SDL client though. Refer to
+`SDL Deployment section <#sdl-deployment>`_, for information about SDL backend
+data storage redundancy models.
+
+.. raw:: pdf
+
+ PageBreak
+
+Best Practices
+**************
+
+This chapter gives recommendations on how to use SDL.
+
+Building Clients Using SDL
+==========================
+
+* Use *pkg-config* tool to acquire needed compilation and linking flags,
+ instead of hardcoding them. This ensures that flags are always up-to-date.
+ See more information from `here <#building-clients-using-sdl>`_.
+
+Using SDL APIs
+==============
+
+* SDL APIs are not thread-safe. If same SDL API instance is shared between
+ multiple threads, SDL client has to use explicit locking to ensure that only
+ one thread at time executes SDL API functions.
+* Each SDL instance establishes own connection to backend data storage, which
+ requires resources (how heavy this exactly is depends on used backend data
+ storage type). Thus, from performance point of view, only one SDL instance
+ per one SDL API should be used if reasonably possible. One SDL instance can
+ access multiple SDL namespaces when using *AsyncStorage* and *SyncStorage*
+ APIs.
+* Use waitReadyAsync() function before doing first operation via asynchronous
+ APIs to ensure that SDL and backend data storage are ready to handle
+ operations. See waitReadyAsync() function
+ `doxygen documentation <#doxygen-generated-sdl-api-documentation>`_
+ for corresponding asynchronous API for details.
+* Avoid using heavy search functions (for example: *AsyncStorage::findKeys()*).
+ Rather define your keys so that you know which keys should be read.
+
+Using SDL Namespaces
+====================
+
+* As namespace naming is currently on SDL client's responsibility, use enough
+ specific namespace names that same name is surely not used by someone else
+ (unless you want to share given namespace data with that someone else).
+* Data entities related to each other should be placed under the same
+ namespace (unless there is a good reason not to). For example, accessing
+ multiple data entities with one SDL operation is possible only for data
+ entities belonging to same namespace.
+* Identically named keys can be used in different namespaces. Creating own
+ namespaces for different use cases and unrelated data provides more freedom
+ into key name selection.
+
+Data Management
+===============
+
+* Writing or reading one big junk of data at once is more efficient than
+ writing/reading the same amount of data in small steps. For example, create a
+ key list and read it once, rather than reading each key in a loop.
+* If rolling upgrade needs to be supported, consider using Google Protocol
+ Buffers (or something similar) to make it possible to parse data which is
+ written by older or newer application version.
+
+.. raw:: pdf
+
+ PageBreak