Skip to content

Mapped DboDatabases

Saif edited this page Mar 23, 2015 · 13 revisions

AbstractDboDatabase is a class that maps boost::shared_ptr<...> objects in memory when the server is initialized. It may be accessed by multiple sessions and threads. The purpose of DboDatabase is to share session independent data between sessions without having to duplicate the data or re querying the SQL backend.

AbstractDboDatabase and it's thread safety is managed by DboDatabaseManager which handles the following functions

  • Adding/Removing AbstractDboDatabase in management
  • Loading/Reloading
  • Read/Write locking
  • Managing Wt::Dbo::Session thread safely for each AbstractDboDatabase

Wt::Dbo::ptr are not stored because they are thread unsafe, therefore a separate data structure has to be used to store Dbo data.

Thread Safety

All DboDatabaseManager setter functions, Add/Remove/Load/Reload acquires an exclusive write lock and all read functions grab a shared read lock. A read lock can be acquired by using the RAII ReadLock class. All DboDatabase getter functions should acquire ReadLock. All DboDatabase setter functions are called initially with the write lock acquired therefore getter functions should not be used to avoid deadlock.

Characteristics of a DboDatabase

A DboDatabase have the following characteristics

  • A name for the DboDatabase
  • 1 or more containers to map boost::shared_ptr<...> objects
  • A protected FetchAll() function that reloads data from the backend. This function must have a strong exception safety to make sure that any changes are reverted in the case an exception is thrown.
  • A protected Load() function which maps the Dbo types in Wt::Dbo::Session and to FetchAll()
  • A protected Reload() function to FetchAll()
  • boost::shared_ptr<...> objects must not be modified from within DboDatabase nor from outside of DboDatabase.
  • boost::shared_ptr<...> getter functions must return const protected contained class. boost::shared_ptr<const Class>

Strong exception safety

A common practice to create strong exception safety is the following void DboDatabase::FetchAll() { ContainerType tempContainer; //Create a temporary object of the same type and swap data. We'll swap it back if any exception is caught tempMap.swap(PtrMap) //PtrMap is a member of DboDatabase try { //Fetch from database backend here } catch(...) { TempContainer.swap(tempContainer); } }

Handling reload safely

Data maybe reloaded at anytime, although a mutex would provide thread safety, however, the Application data synchronization may be affected if FetchAll() is called during a procedure such as initialization of an Application. For example if a default language configuration is used in a condition, suddenly after that FetchAll() is called from another thread. Another problem may occur if that language got deleted during that FetchAll(), the application would not find the default language in the database and all strings would printed as ??key??. Such a problem will be referred to as (DboDatabase) data synchronization problem.

Some DboDatabase may be able to solve this problem more easily than others. Some may not even require any further synchronization and some may require restarting all sessions. It depends on how the DboDatabase is being used.

Common options to solve data synchronization problem

Read locking the DboDatabase

This will hold up the DboDatabaseManage::Reload() call until lock is released or goes out of scope. For some cases this may be a complete solution however this should be used together with another solution if the synchronization problem may occur in at any time in a session.

Cached DboDatabase

If the changes in DboDatabase are not expected to be considered by a session immediately, a DboDatabaseCache class can be used to store all boost::shared_ptr<...> for the session, this DboDatabaseCache would not react to changes and will retain the old boost::shared_ptr<...> objects till the end of the session. Old sessions would keep the old data and new session will use the new data.

It is important to grab a read lock in the database by creating a RAII ReadLock class before copying the boost::shared_ptr<...> objects from the active database.

Post changes

If the changes do not affect the program's logic and only affects the user interface, it can simply be posted to all the sessions to update the data.

Restart applications

This is a catch all solution. Applications should be restarted after all events are handled(TODO check for a safe way to restart application).

Disable reloading

If there are no effective solution or reloading is simply not required, reloading may be disabled.

How WebWidgets handle reloading

ModulesDatabase

Reloading is disabled for modules database due to the facts

  • If any new module is added or delete it would require a server restart to load the module library
  • Module names/versions are not included in any part of the application except for control panel

ConfigurationsDatabase

All sessions cache configurations, therefore a reload would only affect future sessions. Control panel would also have a restart applications option in case the change of configuration is very important.

StylesDatabase

Posts the following changes to all sessions

  • Style CssStyleSheet(cleared and repopulated)
  • Template CssStyleSheets(cleared and repopulated)
  • Dbo Templates(new Dbo::ptr<...> replaces the old one)

If the selected style is deleted, non-cached version of ConfigurationsDatabase is used to check the default style and that style is set as the current style.

LanguagesDatabase

Posts the changes to all widgets that uses tr() or trn() in all sessions by replacing the old Dbo::ptr<...> with the new one.

If the selected language is deleted or uninstalled, non-cached version of ConfigurationsDatabase is used to check the default language access path. If the access path does not require change in hostname, the language is simply changed otherwise the language is not changed and the cached version of the deleted language is used. Future calls to tr() or trn() would translate to default language. A notification is given to the user to switch to the default language.

PagesDatabase

Posts the changes to all sessions. If a page loaded in a session is deleted, it is removed from . If the user is currently on that page, forms are disabled and the user is notified of the deletion.

AccessPathsDatabase

To be determined.

This wiki is currently written and managed only for the WebWidgets developer and may or may not be clear to anyone without the knowledge of the structure of WebWidgets.

Clone this wiki locally