libfoedus-core
FOEDUS Core Library
Thread-Pool and Impersonation

APIs to pool and impersonate worker threads in libfoedus-core. More...

Detailed Description

APIs to pool and impersonate worker threads in libfoedus-core.

Database Engine API and Thread

You might have already noticed that most of our APIs provided by the database engine requires a Thread object as its execution context. On the other hand, client programs aren't allowed to instantiate Thread instances by themselves. So, you have to first obtain the Thread object from the engine. This document describes how user programs do that, and why.

Thread Pool

Most client program needs concurrent accesses running on multiple threads. In order to avoid overheads and complexity of launching and maintaining threads by such client programs, our engine provides a pool of pre-allocated threads. This also makes it easy for the engine to guarantee efficient mapping between thread and NUMA-core. As described in Memory Hierarchy, our engine ties threads to their private memories. If our engine lets the client program to manage its own threads, we can't achieve the static and efficient mapping.

Number of thread/group configurations
Our engine pre-allocates a fixed number of ThreadGroup and Thread at start-up. You can configure the numbers in ThreadOptions, but in many cases the default values (which is the number of hardware NUMA nodes/cores) work fine.

Impersonation

Our API to execute transactions consists of the following three concepts:

In order to start a user transaction or a series of user transactions on some thread, the user first defines the procedure as a function as defined in System and User Procedures. Then, the user calls ThreadPool::impersonate() to impersonate one of the pre-allocated threads for the procedure.

When the thread is impersonated, it starts runninng the procedure asynchronously. The original client thread, which invoked the impersonation, immediately returns with ImpersonateSession object for the acquired session. The original thread can choose to either synchronously wait for the completion of the procedure or do other stuffs, such as launching more sessions (be it the same procedure or not).

This means that a use code doesn't have to do anything to run the procedures on an arbitrary number of threads. Everything is encapsulated in the ThreadPool class and its related classes.

Examples

Below is a trivial example to define a procedure and submit impersonation request.

std::cout << "Ya!" << std::endl;
}
int main(int argc, char **argv) {
foedus::Engine engine(options);
engine.get_proc_manager()->pre_register("my_proc", my_proc);
if (engine.initialize().is_error()) {
return 1;
}
foedus::UninitializeGuard guard(&engine);
foedus::ErrorStack result = engine.get_thread_pool()->impersonate_synchronous("my_proc");
std::cout << "result=" << result << std::endl;
if (engine.uninitialize().is_error()) {
return 1;
}
return 0;
}
Collaboration diagram for Thread-Pool and Impersonation:

Classes

struct  foedus::thread::ImpersonateSession
 A user session running on an impersonated thread. More...
 
class  foedus::thread::ThreadPool
 The pool of pre-allocated threads in the engine to execute transactions. More...
 
class  foedus::thread::ThreadPoolPimpl
 Pimpl object of ThreadPool. More...