680 lines
17 KiB
Text
680 lines
17 KiB
Text
Lumiera: The Inner Core
|
|
=======================
|
|
|
|
|
|
[abstract]
|
|
******************************************************************************
|
|
The Lumiera Developers have a distinct vision about the core of a modern NLE.
|
|
This document outlines some of the basic technical concepts and highlights
|
|
the fundamental design decisions. New Developers may find this Document useful
|
|
to get an idea about how the different components work together.
|
|
******************************************************************************
|
|
|
|
|
|
Overview
|
|
--------
|
|
|
|
Lumiera constitutes of a broad range of subsystems. These are roughly grouped
|
|
into three layers plus some extra components. This structure is mostly kept in
|
|
the source directory structures.
|
|
|
|
This three Layers are:
|
|
|
|
The User Interface::
|
|
User interfaces are implemented as plug-ins, most commonly one will see
|
|
the default GUI. But also scripting interfaces or specialized GUI's are
|
|
possible.
|
|
|
|
The Processing layer::
|
|
Keeps the Session, generates the rendering graphs for sequences.
|
|
|
|
The IO and System interface Backend::
|
|
Manages thread-queues, schedules jobs, does the memory management for the
|
|
heavy multimedia data.
|
|
|
|
The extra components are:
|
|
|
|
Lumiera::
|
|
The main program itself, basically acts only as loader to pull the rest up.
|
|
|
|
Common::
|
|
Vital components and common services which must be available for pulling up
|
|
any part of the system.
|
|
|
|
Library::
|
|
A lot of (largely) stateless helper functionality used throughout the code.
|
|
|
|
|
|
Coding Style
|
|
~~~~~~~~~~~~
|
|
|
|
The Lumiera team agreed on using GNU coding style with some exceptions (no
|
|
tabs, line wrap must not always be enforced). Otherwise we are a bit pedantic
|
|
to be consistent to make the codebase uniform. Function naming conventions
|
|
and other details are described in several RFCs.
|
|
|
|
Documentation
|
|
~~~~~~~~~~~~~
|
|
|
|
Every public function should be documented with doxygen comments. The overall
|
|
design is outlined in this text and documented in the various detail pages and
|
|
accompanying RFCs. Bootstrapping the Lumiera design used several other places,
|
|
in several TiddlyWikis, an UML model and cehteh's private wiki, most of this
|
|
information is asciidoced meanwhile and in progress to be integrated in the
|
|
central documentation hierarchy.
|
|
|
|
|
|
Test Driven Development
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
We strive to use _Test-Driven-Development:_ tests are to be written first,
|
|
defining the specification of the entity being tested. Then things get
|
|
implemented until they pass their tests. While increasing the initial
|
|
development effort significantly, this approach is known to lead to
|
|
clearly defined components and overall increases code quality.
|
|
In practice, this approach might not be suitable at times,
|
|
nevertheless we try to sick to it as far as possible
|
|
and maintain fairly complete test coverage.
|
|
|
|
|
|
Lumiera Application
|
|
-------------------
|
|
Generally speaking, the Application is comprised of several self contained
|
|
_subsystems_, which may depend on each other. Dependencies between components
|
|
are to be abstracted through interfaces. Based on the current configuration,
|
|
the application framework brings up the necessary subsystems and finally
|
|
conducts a clean shutdown. Beyond that, the application framework remains
|
|
passive, yet provides vital services commonly used.
|
|
|
|
While the core components are linked into a coherent application and may
|
|
utilise each other's services directly based on C/C++ language facilities,
|
|
several important parts of the applications are loaded as plug-ins, starting
|
|
with the GUI.
|
|
|
|
|
|
User Interfaces
|
|
---------------
|
|
|
|
The purpose of the user interface(s) is to act on the _high-level data model_
|
|
contained within the Session, which belongs to the _processing layer_ below.
|
|
User interfaces are implemented as plug-ins and are pulled up on demand,
|
|
they won't contain any relevant persistent state beyond presentation.
|
|
|
|
|
|
|
|
Processing Layer
|
|
----------------
|
|
|
|
High Level Model
|
|
~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Assets
|
|
^^^^^^
|
|
_tbw_
|
|
|
|
Placement
|
|
^^^^^^^^^
|
|
_tbw_
|
|
|
|
Scoping
|
|
^^^^^^^
|
|
_tbw_
|
|
|
|
MObject References
|
|
^^^^^^^^^^^^^^^^^^
|
|
_tbw_
|
|
|
|
QueryFocus
|
|
^^^^^^^^^^
|
|
_tbw_
|
|
|
|
Output Management
|
|
~~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Stream Type System
|
|
~~~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Command Frontend
|
|
~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Defaults Manager
|
|
~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Rules System
|
|
~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Builder
|
|
~~~~~~~
|
|
_tbw_
|
|
|
|
Low Level Model
|
|
~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Play/Render processes
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
|
|
|
|
|
|
Backend
|
|
-------
|
|
|
|
I/O Subsystem
|
|
~~~~~~~~~~~~~
|
|
|
|
.OS Filehandles
|
|
as mru cache, round robin reused
|
|
|
|
.Files
|
|
Lumiera has its own abstract file handles which store the state and name of a
|
|
file. The associated filehandle doesn't need to be kept open and will be
|
|
reopened on demand. Hardlinked files are recognized and opened only once.
|
|
|
|
.Memory Mapping
|
|
All file access is done by memory mapping to reduce data copies between
|
|
userland and kernel. Moreover the kernel becomes responsible to schedule
|
|
paging (which will be augmented by lumiera) to make the best use of available
|
|
resources. Memory is mapped in biggier possibly overlapping windows of
|
|
resonable sized chunks. Requests asking for a contingous set of data from the
|
|
file in memory.
|
|
|
|
|
|
.Indexing
|
|
|
|
.Frameprovider
|
|
|
|
|
|
Threadpools
|
|
~~~~~~~~~~~
|
|
|
|
Manages serveral classes of threads in pools. The threadpool is reasonable
|
|
dumb. Higher level management will be done by the Schedulers and Jobs.
|
|
|
|
|
|
Schedulers
|
|
~~~~~~~~~~
|
|
|
|
Scheduling Queues for different purposes:
|
|
|
|
.Deadline
|
|
Higher priority jobs ordered by a deadline time plus some (negative) hystersis. Jobs are
|
|
started when they approach their deadline. Jobs who miss their deadline are
|
|
never scheduled here.
|
|
|
|
.Background
|
|
Background jobs scheduled by priority and timeout.
|
|
|
|
|
|
.Realtime
|
|
Timer driven queue which starts jobs at defined absolute times. Timer might be
|
|
also an external synchronization entity.
|
|
|
|
|
|
Job
|
|
^^^
|
|
a job can be part of multiple queues, the queue which picks them first runs
|
|
them. When other queues hit a running job they either just drop it or promote
|
|
its priority (to be decided).
|
|
|
|
|
|
Resource Management
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
Running Lumiera requires a lot different resources, such as CPU-Time, Threads,
|
|
IO Bandwidth, Memory, Address space and so on. Many of this resources are rather
|
|
hard limited and the system will return errors when this limits are hit, but
|
|
often one does not even reach this hard limits because performance will
|
|
degrade way before coming into the realm of this limits. The goal for Lumiera
|
|
is to find a sweet spot for operating with optimal performance. Thus we have
|
|
some facilities to monitor and adjust resource usage depending and adapting to
|
|
the system and current circumstances.
|
|
|
|
|
|
Profiler
|
|
^^^^^^^^
|
|
|
|
Collects statistic about resource load, helps to decide if job constraints can
|
|
be fulfilled.
|
|
|
|
Things to watch:
|
|
* cpu utilization
|
|
* memory usage (swapping, paging)
|
|
* I/O load, latency
|
|
|
|
|
|
Budget Manager
|
|
^^^^^^^^^^^^^^
|
|
|
|
resources need to be distributed among a lot subsystems and jobs. Each of this
|
|
component can become part of a budgeting system which accounts resource usage
|
|
and helps to distribute it. Resource usage is only voluntary managed.
|
|
|
|
|
|
Resource collector
|
|
^^^^^^^^^^^^^^^^^^
|
|
|
|
Handles system errors related to resource shortage. There are several classes
|
|
of resources defined. Other subsystems can hook in functions to free
|
|
resources. Has multiple policies about how aggressive resources should be freed.
|
|
|
|
If no one cares it does a final abort(). So all systems should hook better
|
|
recovery here in!
|
|
|
|
|
|
|
|
|
|
|
|
Common Services
|
|
---------------
|
|
|
|
Subsystem runner
|
|
~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Lifecycle events
|
|
~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Interface system
|
|
~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Plugin loader
|
|
~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Rules system
|
|
~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Serialiser
|
|
~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Config loader
|
|
~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Lua Scripting
|
|
~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
|
|
Library
|
|
-------
|
|
|
|
The Lumiera support library contains lots of helper functionality
|
|
factored out from the internals and re-used. It is extended as we go.
|
|
|
|
|
|
Locking
|
|
~~~~~~~
|
|
Based on object monitors. Performance critical code
|
|
uses mutexes, condition vars and rwlocks direcly.
|
|
Intentionally no semaphores.
|
|
|
|
- C++ locks are managed by scoped automatic variables
|
|
- C code uses macros to wrap critical sections
|
|
|
|
|
|
|
|
Time
|
|
~~~~
|
|
Time values are represented by an opaque date type `lumiera::Time`
|
|
with overloaded operators. The implementation is based on `gavl_time_t`,
|
|
an integral (µsec) time tick value. Any Time handling and conversions
|
|
is centralised in library routines.
|
|
|
|
We distinguish between time values and a _quantisation_ into a frame
|
|
or sample grid. In any case, quantisation has to be done once, explicitly
|
|
and as late as possible. See the link:{rfc}/TimeHandling.html[Time handling RfC].
|
|
|
|
|
|
Errors
|
|
~~~~~~
|
|
|
|
* As a Rule, Exceptions + RAII are to be preferred over error
|
|
codes and manual cleanup. At external interfaces we rely on
|
|
error states though.
|
|
* Exceptions can happen everywhere and any time
|
|
* Exceptions and Errors shall only be dealt with at locations where it's actually
|
|
possible to _handle_ them (the so called ``fail not repair'' rule)
|
|
* API functions are categorised by _error safety guarantee_
|
|
- *EX_FREE* functions won't raise an exception or set an error state,
|
|
unless the runtime system is corrupted.
|
|
- *EX_STRONG* functions are known to have no tangible effect in
|
|
case of raising an exception / error state (transactional behaviour).
|
|
- *EX_SANE* functions might leave a partial change, but care to leave
|
|
any involved objects in a sane state.
|
|
* Raising an Exception creates an _error state_ -- error states can also
|
|
be set directly per thread.
|
|
* Error states are identified by pointers to static strings.
|
|
* Error states are thread local and sticky (a new state can't be set
|
|
unless a pending state got cleared).
|
|
|
|
|
|
Exception hierarchy
|
|
^^^^^^^^^^^^^^^^^^^
|
|
Typically, when an error situation is detected, the error will be categorised
|
|
by throwing the appropriate exception. Exceptions provide a mechanism to attach
|
|
the root cause. The classification happens according to the _relevance for the
|
|
application_ as a whole -- _not_ according to the cause.
|
|
|
|
`lumiera::Error`:: root of error hierarchy. extends `std::exception`
|
|
`error::Logic`:: contradiction to internal logic assumptions detected
|
|
`error::Fatal`:: (⤷ `Logic`) unable to cope with, internal logic floundered
|
|
`error::Config`:: execution aborted due to misconfiguration
|
|
`error::State`:: unforeseen internal state (usually causes component restart)
|
|
`error::Flag`:: (⤷ `State`) non-cleared error state from C code
|
|
`error::Invalid`:: invalid input or parameters encountered
|
|
`error::External`:: failure in external service the application relies on
|
|
`error::Assertion`:: assertion failure
|
|
|
|
Please be sure to clear the error state whenever catching and handling an exception.
|
|
|
|
|
|
Error states
|
|
^^^^^^^^^^^^
|
|
Errors states get declared in headers with the `LUMIERA_ERROR_DECLARE(err)` macro.
|
|
A matching definition needs to reside in some translation unit, using the
|
|
`LUMIERA_ERROR_DEFINE(err, msg)` macro. There is no central registry, any component
|
|
can introduce its own errorcodes but must ensure that the error identifier is
|
|
unique.
|
|
|
|
.Error handling in C
|
|
There are two helper macro forms for setting up error conditions, one is
|
|
`LUMIERA_ERROR_SET..(flag, err, extra)` and the other one is
|
|
`LUMIERA_ERROR_GOTO..(flag, err, extra)`. Each for different logging levels.
|
|
The `SET` form just logs an error and sets it, the `GOTO` form also jumps to
|
|
an error handler. Both take a NoBug flag used for logging and a optional
|
|
`extra` c-string.
|
|
|
|
|
|
[source,C]
|
|
--------------------------------------------------------------------------------
|
|
const char*
|
|
mayfail()
|
|
{
|
|
const char* ret = foo();
|
|
if (!ret)
|
|
LUMIERA_ERROR_GOTO (flag, FOO_FAILED, 0);
|
|
|
|
if (!bar(ret))
|
|
LUMIERA_ERROR_GOTO (flag, BAR_FAILED, 1,
|
|
lumiera_tmpbuf_snprintf (256, "foo was %s", ret));
|
|
|
|
return "everything ok";
|
|
|
|
/* cleanup in reverse setup order */
|
|
BAR_FAILED1:
|
|
lumiera_free (ret);
|
|
FOO_FAILED0:
|
|
return NULL;
|
|
}
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Singletons
|
|
~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Extensible Factory
|
|
~~~~~~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Visiting Tool
|
|
~~~~~~~~~~~~~
|
|
_tbw_
|
|
|
|
Iterators
|
|
~~~~~~~~~
|
|
Lumiera Forward Iterator
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
_tbw_
|
|
|
|
Iterator Adapters
|
|
^^^^^^^^^^^^^^^^^
|
|
_tbw_
|
|
|
|
Itertools
|
|
^^^^^^^^^
|
|
_tbw_
|
|
|
|
|
|
Wrappers and Opaque Holders
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
- smart handle
|
|
- unified value/ptr/reference holder
|
|
- ownership managing collection
|
|
- opaque holder to ``piggypack'' an object inline,
|
|
without the need for heap allocated storage
|
|
- vector of references
|
|
|
|
Unique Identifiers
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
LUID
|
|
^^^^
|
|
Generating 128 bit non cryptographic strong unique identifiers.
|
|
|
|
- having an alternative representation to store a pointer
|
|
- may be extended for a strong (slow) and a fast (weak) variant in future
|
|
|
|
EntryID
|
|
^^^^^^^
|
|
Combines an user readable ID, a (compile time) type tag and a hash-ID.
|
|
The latter is based on the symbolic ID and the type tag, which is discarded
|
|
at runtime (type erasure)
|
|
|
|
Typed Lookup
|
|
^^^^^^^^^^^^
|
|
_planned_ a system of per-type lookup tables, based on `EntryID`, together
|
|
with an type specific access functor. Together, this allows to translate
|
|
transparently and typesafe from symbolic ID to object instance, which
|
|
is an prerequisite for integrating a rules based system. Besides, these
|
|
tables allow unique IDs per type
|
|
|
|
|
|
Allocators
|
|
~~~~~~~~~~
|
|
_tbw_
|
|
|
|
|
|
Memory Pools
|
|
~~~~~~~~~~~~
|
|
|
|
Fast memory pools for moderately small static sized allocations in highly
|
|
dynamic situations.
|
|
|
|
* optimized for cache locality
|
|
* supporting a destructor callback to free all objects
|
|
|
|
|
|
Temporary Buffers
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
Provides a small number of round robin buffers which need not to be freed.
|
|
Must only be used locally when no deep recursion may use tmpbufs. Using these
|
|
wrong (recursively) will result in corrupted data.
|
|
|
|
Very fast and efficient from smallest too hugest allocations. No need to care
|
|
for 'free()'
|
|
|
|
|
|
Template Metaprogramming
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Typelists
|
|
^^^^^^^^^
|
|
_tbw_
|
|
|
|
Tuples
|
|
^^^^^^
|
|
_tbw_
|
|
|
|
Functor Utils
|
|
^^^^^^^^^^^^^
|
|
_tbw_
|
|
|
|
|
|
Preprocessor Metaprogramming
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
ppmpl.h
|
|
|
|
|
|
CLib wrappers
|
|
~~~~~~~~~~~~~
|
|
|
|
Some wrapers for the C memory management functions malloc, calloc, realloc and
|
|
free which never fail. In case of an error the resourcecollector in the
|
|
backend is invoked to free resources or doing an emergency shutdown.
|
|
|
|
Safe wrapers for some string functions from the C-library which also never
|
|
fail. NULL strings are propagated to "" empty strings.
|
|
|
|
|
|
Polymorphic Programming in C
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Just a macro for simplyfying vtable function calls
|
|
VCALL(Handle, function, arguments...)
|
|
translates to
|
|
Handle->vtable->function (Handle, arguments...)
|
|
|
|
The user is responsible for setting up a `vtable` member in his datastructures
|
|
this macro does some NoBug checks that self and function are initialized.
|
|
|
|
|
|
Algorithms & Datastructures
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Probabilistic Splay Tree
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Self optimizing splay tree
|
|
|
|
Advantage:
|
|
* can be iterated
|
|
* very fast in situations where few common elements are queried most often
|
|
|
|
Disadvantages
|
|
* provides no own locking, needs to be locked from outside
|
|
* (almost) every access is a mutation and needs an exclusive lock, bad for concurrency
|
|
|
|
|
|
BTree
|
|
^^^^^
|
|
|
|
Generic B+/B* Tree implementation. Details are provided by a vtable at an
|
|
actual implementation.
|
|
|
|
* Fine grained (block level) locking with different modes
|
|
* supports cursors to iterate over the data, in both directions
|
|
* exact and inexact searched (what's close before/after something)
|
|
|
|
|
|
Cuckoo Hashing
|
|
^^^^^^^^^^^^^^
|
|
_Currently defunct, to be revived someday_
|
|
|
|
|
|
Hash functions
|
|
^^^^^^^^^^^^^^
|
|
_planned_
|
|
|
|
|
|
Linked Lists
|
|
^^^^^^^^^^^^
|
|
|
|
.llist
|
|
|
|
Cyclic double linked intrusive list.
|
|
|
|
.slist
|
|
|
|
Single linked variant.
|
|
|
|
|
|
Most Recent used Cachelists
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
A list where old entries are recycled from the tail, used things are removed
|
|
from the list (ownership acquired) and released back to the head.
|
|
|
|
Items not used propagate towards the tail where they will be reused.
|
|
|
|
|
|
//Undocumented
|
|
//access-casted.hpp
|
|
//advice.hpp symbol-impl.cpp
|
|
//allocationcluster.cpp symbol.hpp
|
|
//bool-checkable.hpp
|
|
//cmdline.cpp
|
|
//cmdline.hpp
|
|
//del-stash.hpp
|
|
//diagnostic-context.hpp
|
|
//element-tracker.hpp
|
|
//external
|
|
//factory.hpp
|
|
//format.hpp
|
|
//frameid.hpp
|
|
//functor-util.hpp
|
|
//handle.hpp
|
|
//hash-indexed.hpp
|
|
//iter-adapter-stl.hpp
|
|
//iter-adapter.hpp
|
|
//iter-source.hpp
|
|
//itertools.hpp
|
|
//lifecycle.cpp
|
|
//lifecycleregistry.hpp
|
|
//lumitime-fmt.hpp
|
|
//lumitime.cpp
|
|
//multifact-arg.hpp
|
|
//multifact.hpp
|
|
//nobug-init.cpp <<why here and not in common?
|
|
//nobug-init.hpp
|
|
//null-value.hpp
|
|
//observable-list.hpp
|
|
//opaque-holder.hpp
|
|
//p.hpp
|
|
//query.cpp
|
|
//query.hpp
|
|
//ref-array-impl.hpp
|
|
//ref-array.hpp
|
|
//result.hpp
|
|
//scoped-holder.hpp
|
|
//scoped-ptrvect.hpp
|
|
//scopedholdertransfer.hpp
|
|
//singleton-ref.hpp
|
|
//singleton-subclass.hpp
|
|
//singleton.hpp
|
|
//singletonfactory.hpp
|
|
//singletonpolicies.hpp
|
|
//singletonpreconfigure.hpp
|
|
//streamtype.cpp
|
|
//test
|
|
//thread-local.hpp
|
|
//tree.hpp
|
|
//typed-allocation-manager.hpp
|
|
//typed-counter.hpp
|
|
//util-foreach.hpp
|
|
//util.cpp
|
|
//util.hpp
|
|
//variant.hpp
|
|
//visitor-dispatcher.hpp
|
|
//visitor-policies.hpp
|
|
//visitor.hpp
|
|
//wrapper.hpp
|
|
//wrapperptr.hpp
|
|
|
|
|