Previous Topic

Next Topic

Book Contents

Book Index

Database

This document describes how to use the Database.

Database Types

There are two types of databases that may be used:

Supported Data Types

With the DB Interface, bundles can store data of the following types:

DB Structure

The data stored in a database is organized in a tree. Every node (including the root) can possess unlimited number of subnodes.

Each node can contain data of the types listed in "Supported Data Types", or can be empty, which indicates that the node has no value and is used only to form the tree hierarchy.

Syntax of Node Names

A node’s full name is a String[] formed recursively from the simple names of all its predecessors and its own simple name. All methods of the DB interface take a full name argument while the list method returns simple names. The String[] used to specify a node’s full name can be null-terminated – it can have arbitrary length and the first null value in the array indicates the end of the name.

To access the root node of a database, use String[] {} as node name.

Writing Data to a DB

The basic method for writing into a database (DB object) is setValue. You can also use the move method to move a subnode to another parent and the delete method to erase some data. Additionally, you can reserve a database by using the lock and unlock methods.

Note that in the main DB only the bundle which initially created a specific node and populated it with data can modify this data.

For illustration of how to write in a DB, refer to Listing 1.1 from the DB example in this document.

Browsing the Content of a DB

The  Core Database bundle provides two ways for reading the content of a DB to bundles:

By Referring Directly to the DB

The methods of the DB interface define support for the following operations:

Node by Node

The Core Database bundle provides representation of DB nodes as DBNode instances. A DBNode can be used to:

It is possible that a DBNode becomes invalid between two successive read operations. To avoid failures, first check the validity of the node by using the isValid method of DBNode. Then, you can lock the parent DB by calling the lock method in order to avoid the situation where the got node might be invalidated by another entity.

DB Restore Points

The Core Database bundle provides the following restore points, that allow you to restore corrupted DBs:

Managing Custom DBs

Each custom database is associated with a root directory and an alias. The root directory specifies the physical location of the database while the alias represents it in an user-friendly manner.

The DB Manager service is published under the com.prosyst.mbs.services.db.DBManager interface name. To create or access a custom database, use the appropriate getCustomDB method.

You can access the main DB as a custom DB under the DBManager.MAIN_DB ("<main>") alias.

You can list the aliases of the created custom DBs using the listCustomDBAliases method.

DB Permission

In case of secured Bosch IoT Gateway Software the access to a custom DB with a specific name can be restricted via com.prosyst.mbs.services.db.DBPermission. The access rights can be assigned for a custom DB, which is defined by its name (prefixes are supported), and by the action allowed for the DB. The DB Permission supports the following actions:

For more information on DBPermission see the Java API, available for the Core module.

There is no DBPermission check for the Main Database.

Saving the Main DB

The DB Manager can be requested to save the main DB by calling its save method. See the Compromising between Speed and Persistence section for more details on the save operation.

Accessing Databases

Bundles with access to the main DB are provided by DB service, published under the com.prosyst.mbs.services.db.DB interface name.

Every bundle that writes into the main DB service is associated with a separate node within the DB root. Such a bundle-specific node is named after the bundle ID. The data in the subnodes is accessible for write operations only by the bundle that created it.

As the DB service stores the data of the main DB in its private area from the framework storage, on updating the DB Bundle this data will be lost as the framework automatically clears the bundle storage area, unless the bundle is updated through the Framework Access service (for example, by using update console command from the fw group with the -k option).

Compromising between Speed and Persistence

As the DB Bundle is widely used for storing data persistently, its performance can have a great influence on the overall operation of the framework. A common case in most embedded devices is a hardware configuration where a flash card with fast read access but unpredictably slow write access is used for persistent storage. The DB Bundle executes a lot of file write operations and in this case writing data directly on the flash file system is not convenient. The DB service can be used to solve the issue as it is capable of buffering bundle data and then transforming the changes back on the flash file system.

Buffering of stored data into RAM is enabled by setting the mbs.db.buffered system property to true prior to DB bundle startup.

To explicitly save the current bundle data from the main DB onto the flash persistent storage, you can call the save method of the DB service. All data that is created is recorded in the DB asynchronously. This means that the data that must be persisted – for example a newly created configuration info is stored in buffers in RAM, and then flushed on the flash.

There are these properties that control the DB data persistence:

Property

Value

Description

mbs.db.buffered

true/false , default is true

Controls if the saves to the DB are buffered.

mbs.db.savetime

[milliseconds] , default is 10000

These properties define the maximum size of the buffered data. If this maximum is reached (before the timeout expires), all changes are stored on the flash. In the case of using buffering and asynchronous persisting of data (default behavior), setting lower values to mbs.db.maxBuffers1 and a lower value for mbs.db.savetime, data will be recorded on the flash more often and in shorter intervals. This is one way to secure against loss of unsaved data. If a change (i.e. configuration) needs to be instantly recorded in the DB - this can be done with mbs.db.maxBuffers2=1 but that is NOT recommended for many reasons. If mbs.db.buffered=false and setting mbs.db.maxBuffers2 will provide a synchronous DB recording.

mbs.db.bufferSize

mbs.db.maxBuffers1

mbs.db.maxBuffers2

The mechanism for saving data using mbs.db.savetime relies on the OS below, the concrete Filesystem used and the storage media itself – HDD, flash or any controllers used, etc.

Some flash file systems are not synchronized and re-mounting with the sync option will force it always; but that is not recommended because it will truly secure against loss of unsaved data but will also dramatically slow down the performance.

There are other system means (not on Java/OSGi level) to flush the buffers to the flash more often - like calling fsync() or sync() in your application, but that shortens the life of the flash.

System Properties

The system properties, that can be set for the operation of the Database, are described in the Setup Guide.

Troubleshooting

Switching on Extensive Debugging

Please, edit your default.prs file (/osgi/bin/vms/<jvm>/default.prs) and add the following:

mbs.db.console=true
mbs.db.debug=true
mbs.db.writeDebug=true

You should then see in the local text console all the debugging information, for example:

(...)
[DB a_metatype] [DB] Storing 2697 bytes in data. eof: 2697
- service using the DB to store some bytes finished for 2697 milliseconds.
(...)