libfoedus-core
FOEDUS Core Library
engine_pimpl.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015, Hewlett-Packard Development Company, LP.
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details. You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14  *
15  * HP designates this particular file as subject to the "Classpath" exception
16  * as provided by HP in the LICENSE.txt file that accompanied this code.
17  */
18 #include "foedus/engine_pimpl.hpp"
19 
20 #include <unistd.h>
21 #include <valgrind.h>
22 #include <glog/logging.h>
23 
24 #include <algorithm>
25 #include <chrono>
26 #include <fstream>
27 #include <iostream>
28 #include <sstream>
29 #include <string>
30 #include <thread>
31 
37 
38 namespace foedus {
39 
40 EnginePimpl::EnginePimpl(Engine* engine, const EngineOptions &options) :
41  options_(options),
42  engine_(engine),
43  type_(kMaster),
44  master_upid_(::getpid()),
45  // simply the pointer value of Engine object as identifier.
46  master_eid_(reinterpret_cast<uintptr_t>(reinterpret_cast<void*>(engine))),
47  soc_id_(0),
48  // although we give a pointer to engine, these objects must not access it yet.
49  // even the Engine object has not set the pimpl pointer.
50  soc_manager_(engine),
51  debug_(engine),
52  proc_manager_(engine),
53  memory_manager_(engine),
54  savepoint_manager_(engine),
55  thread_pool_(engine),
56  log_manager_(engine),
57  snapshot_manager_(engine),
58  cache_manager_(engine),
59  storage_manager_(engine),
60  xct_manager_(engine),
61  restart_manager_(engine) {
62 }
64  Engine* engine,
65  EngineType type,
66  soc::Upid master_upid,
67  Eid master_eid,
68  soc::SocId soc_id) :
69  engine_(engine),
70  type_(type),
71  master_upid_(master_upid),
72  master_eid_(master_eid),
73  soc_id_(soc_id),
74  soc_manager_(engine),
75  debug_(engine),
76  proc_manager_(engine),
77  memory_manager_(engine),
78  savepoint_manager_(engine),
79  thread_pool_(engine),
80  log_manager_(engine),
81  snapshot_manager_(engine),
82  cache_manager_(engine),
83  storage_manager_(engine),
84  xct_manager_(engine),
85  restart_manager_(engine) {
86 }
87 
88 std::string EnginePimpl::describe_short() const {
89  if (type_ == kMaster) {
90  return "MASTER";
91  }
92  std::string ret("CHILD-");
93  return ret + std::to_string(soc_id_);
94 }
95 
97  if (is_master()) {
99  }
100  // SOC manager is special. We must initialize it first.
103  ErrorStack module_initialize_error = initialize_modules();
104  if (module_initialize_error.is_error()) {
105  LOG(ERROR) << "*******************************************************************************";
106  LOG(ERROR) << "*** ERROR while module initailization in " << describe_short() << ". "
107  << module_initialize_error << "";
108  LOG(ERROR) << "*******************************************************************************";
110  CHECK_ERROR(module_initialize_error);
111  }
112 
113  // The following can assume SOC manager is already initialized
114  if (is_master()) {
117  // wait for children's kRunning status
118  // TASK(Hideaki) should be a function in soc manager
119  uint16_t soc_count = engine_->get_options().thread_.group_count_;
120  while (true) {
121  std::this_thread::sleep_for(std::chrono::milliseconds(5));
123  bool error_happened = false;
124  bool remaining = false;
125  for (uint16_t node = 0; node < soc_count; ++node) {
128  error_happened = true;
129  break;
130  }
132  continue; // ok
133  }
134  remaining = true;
135  }
136 
137  if (error_happened) {
138  LOG(ERROR) << "[FOEDUS] ERROR! error while waiting child kRunning";
141  } else if (!remaining) {
142  break;
143  }
144  }
145  }
146  LOG(INFO) << "================================================================================";
147  LOG(INFO) << "================== FOEDUS ENGINE ("
148  << describe_short() << ") INITIALIZATION DONE ===========";
149  LOG(INFO) << "================================================================================";
150 
151  // In a few places, we check if we are running under valgrind and, if so, turn off
152  // optimizations valgrind can't handle (eg hugepages).
153  bool running_on_valgrind = RUNNING_ON_VALGRIND;
154  if (running_on_valgrind) {
155  LOG(INFO) << "=============== ATTENTION: VALGRIND MODE! ==================";
156  LOG(INFO) << "This Engine is running under valgrind, which disables several optimizations";
157  LOG(INFO) << "If you see this message while usual execution, something is wrong.";
158  LOG(INFO) << "=============== ATTENTION: VALGRIND MODE! ==================";
159  }
160  return kRetOk;
161 }
164  for (ModulePtr& module : get_modules()) {
165  // During initialization, SOCs wait for master's initialization before their init.
166  if (!is_master()) {
167  CHECK_ERROR(soc_manager_.wait_for_master_module(true, module.type_));
168  }
169  CHECK_ERROR(module.ptr_->initialize());
170  on_module_initialized(module.type_);
171  // Then master waits for SOCs before moving on to next module.
172  if (is_master()) {
174  }
175  }
176  return kRetOk;
177 }
179  LOG(INFO) << "================================================================================";
180  LOG(INFO) << "=================== FOEDUS ENGINE ("
181  << describe_short() << ") EXITTING...... ================";
182  LOG(INFO) << "================================================================================";
186  }
187  ErrorStackBatch batch;
188  // uninit in reverse order of initialization
189  auto modules = get_modules();
190  std::reverse(modules.begin(), modules.end());
191  for (ModulePtr& module : modules) {
192  if (!module.ptr_->is_initialized()) {
193  continue;
194  }
195  // During uninitialization, master waits for SOCs' uninitialization before its uninit.
196  if (is_master()) {
197  batch.emprace_back(soc_manager_.wait_for_children_module(false, module.type_));
198  }
199  batch.emprace_back(module.ptr_->uninitialize());
200  on_module_uninitialized(module.type_);
201  // Then SOCs wait for master before moving on to next module.
202  if (!is_master()) {
203  batch.emprace_back(soc_manager_.wait_for_master_module(false, module.type_));
204  }
205  }
206 
207  // SOC manager is special. We must uninitialize it at last.
209  // after that, we can't even set status. shared memory has been detached.
210  return SUMMARIZE_ERROR_BATCH(batch);
211 }
212 
214  CHECK_ERROR(options_.prescreen(&std::cerr));
215  CHECK_ERROR(check_minimal_pool_size());
216  CHECK_ERROR(check_transparent_hugepage_setting());
217  return kRetOk;
218 }
219 
220 ErrorStack EnginePimpl::check_minimal_pool_size() const {
221  // Can we at least start up?
224  uint64_t total_threads = t.group_count_ * t.thread_count_per_group_;
225  uint64_t minimal_page_pool
227  if ((static_cast<uint64_t>(m.page_pool_size_mb_per_node_)
228  * t.group_count_ << 20) < minimal_page_pool) {
230  }
231  return kRetOk;
232 }
233 
234 ErrorStack EnginePimpl::check_transparent_hugepage_setting() {
235  /* we don't warn about THP anymore. We anyway use pre-allocated hugepages
236  std::ifstream conf("/sys/kernel/mm/transparent_hugepage/enabled");
237  if (conf.is_open()) {
238  std::string line;
239  std::getline(conf, line);
240  conf.close();
241  if (line == "[always] madvise never") {
242  std::cout << "Great, THP is in always mode" << std::endl;
243  } else {
244  // Now that we use non-transparent hugepages rather than THP, we don't output this as
245  // warning. Maybe we completely get rid of this message.
246  std::cerr << "THP is not in always mode ('" << line << "')."
247  << " Not enabling THP reduces our performance up to 30%. Run the following to enable it:"
248  << std::endl << " sudo sh -c 'echo always > /sys/kernel/mm/transparent_hugepage/enabled'"
249  << std::endl;
250  }
251  return kRetOk;
252  }
253 
254  std::cerr << "Could not read /sys/kernel/mm/transparent_hugepage/enabled to check"
255  << " if THP is enabled. This implies that THP is not available in this system."
256  << " Using an old linux without THP reduces our performance up to 30%" << std::endl;
257  */
258  return kRetOk;
259 }
260 
263  if (is_master()) {
265  } else {
267  }
268 }
269 
272  if (is_master()) {
274  } else {
276  }
277 }
278 
280  return pimpl_->savepoint_manager_.get_earliest_epoch();
281 }
283  return pimpl_->xct_manager_.get_current_global_epoch();
284 }
286  return pimpl_->xct_manager_.get_current_grace_epoch();
287 }
289  return pimpl_->log_manager_.get_durable_global_epoch();
290 }
291 
292 } // namespace foedus
Set of options about threads and thread-groups.
ErrorStack initialize() override
Acquires resources in this object, usually called right after constructor.
Definition: soc_manager.cpp:34
ErrorStack wait_for_children_module(bool init, ModuleType module)
Wait for other engines to finish init/uninit the module.
Definition: soc_manager.cpp:57
EngineOptions options_
Options given at boot time.
0x0303 : "MEMORY : Page Pool size is too small." .
Definition: error_code.hpp:144
void emprace_back(ErrorStack &&error_stack)
If the given ErrorStack is an error, this method adds it to the end of this batch.
void change_master_status(MasterEngineStatus::StatusCode new_status)
void on_module_initialized(ModuleType module)
Called whenever each module has completed its initialization.
#define ERROR_STACK(e)
Instantiates ErrorStack with the given foedus::error_code, creating an error stack with the current f...
void on_module_uninitialized(ModuleType module)
Called whenever each module has completed its uninitialization.
ErrorStack check_valid_options()
uint32_t private_page_pool_initial_grab_
How many pages each NumaCoreMemory initially grabs when it is initialized.
Epoch get_current_global_epoch() const
Returns the current global epoch, the epoch a newly started transaction will be in.
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
The master is waiting for child engines to terminate.
GlobalMemoryAnchors * get_global_memory_anchors()
Epoch get_current_grace_epoch() const
Returns the current grace-period epoch (global epoch - 1), the epoch some transaction might be still ...
bool is_master() const
ErrorStack uninitialize() override
An idempotent method to release all resources of this object, if any.
Definition: soc_manager.cpp:36
ErrorStack initialize_once() override
void report_engine_fatal_error()
Announce fatal error state of this (either master or child) engine if possible.
Definition: soc_manager.cpp:64
Brings error stacktrace information as return value of functions.
Definition: error_stack.hpp:81
Represents a time epoch.
Definition: epoch.hpp:61
FileStatus status(const Path &p)
Returns the status of the file.
Definition: filesystem.cpp:45
ErrorStack wait_for_master_module(bool init, ModuleType module)
Wait for master engine to finish init/uninit the module.
Definition: soc_manager.cpp:61
NodeMemoryAnchors * get_node_memory_anchors(SocId node)
soc::SocManager soc_manager_
SOC manager.
0x0C0B : "SOC : Child SOC failed to initialize a module." .
Definition: error_code.hpp:230
const EngineOptions & get_options() const
Definition: engine.cpp:39
ThreadLocalOrdinal thread_count_per_group_
Number of Thread in each ThreadGroup.
std::vector< ModulePtr > get_modules()
Returns in initialization order.
Epoch get_durable_global_epoch() const
Returns the durable epoch of the entire engine.
ErrorStack prescreen(std::ostream *details_out) const
Checks the machine environment and raises as many errors as possible before the engine starts up...
std::string describe_short() const
ModuleType
Enumerates modules in FOEDUS engine.
Definition: module_type.hpp:26
savepoint::SavepointManager savepoint_manager_
Batches zero or more ErrorStack objects to represent in one ErrorStack.
memory::MemoryOptions memory_
void change_uninit_atomic(ModuleType value)
Epoch get_current_global_epoch() const
Returns the current global epoch, the epoch a newly started transaction will be in.
const EngineType type_
Database engine object that holds all resources and provides APIs.
Definition: engine.hpp:109
Done all initialization and running transactions.
xct::XctManager xct_manager_
Set of options for memory manager.
Set of option values given to the engine at start-up.
EngineType
Type of an engine instance of how to launch it.
Definition: engine_type.hpp:35
bool is_initialized() const override
Returns whether the object has been already initialized or not.
Definition: soc_manager.cpp:35
const soc::SocId soc_id_
Engine *const engine_
Pointer to the enclosing object.
Current status of a child SOC engine.
uint64_t Upid
Universal (or Unique) ID of a process.
Definition: soc_id.hpp:48
uint16_t group_count_
Number of ThreadGroup in the engine.
The central instance that launches child engines on each NUMA node (SOC).
Definition: engine_type.hpp:41
pair of module pointer and its type.
Repository of all shared memory in one FOEDUS instance.
#define SUMMARIZE_ERROR_BATCH(x)
This macro calls ErrorStackBatch::summarize() with automatically provided parameters.
log::LogManager log_manager_
uint16_t SocId
Represents an ID of an SOC, or NUMA node.
Definition: soc_id.hpp:41
Epoch get_durable_global_epoch() const
Returns the durable epoch of the entire engine.
Definition: log_manager.cpp:36
void change_init_atomic(ModuleType value)
thread::ThreadOptions thread_
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
void change_init_atomic(ModuleType value)
uint32_t page_pool_size_mb_per_node_
Size of the page pool in MB per each NUMA node.
const ErrorStack kRetOk
Normal return value for no-error case.
MasterEngineStatus * master_status_memory_
This tiny piece of memory contains the current status of the master engine and its synchronization me...
ErrorStack initialize_modules()
void change_uninit_atomic(ModuleType value)
ChildEngineStatus * child_status_memory_
This tiny piece of memory contains the current status of the child engine on this node...
Epoch get_current_grace_epoch() const
Returns the current grace-period epoch (global epoch - 1), the epoch some transaction might be still ...
uint64_t Eid
An Engine ID to differentiate two Engine objects instantiated in the same process.
Definition: engine_type.hpp:29
ErrorStack uninitialize_once() override
Done all initialization and running transactions.
#define ASSERT_ND(x)
A warning-free wrapper macro of assert() that has no performance effect in release mode even when 'x'...
Definition: assert_nd.hpp:72
Epoch get_earliest_epoch() const
Returns the Earliest-Epoch, the minimum epoch that is valid within this engine.
const uint16_t kPageSize
A constant defining the page size (in bytes) of both snapshot pages and volatile pages.
Definition: storage_id.hpp:45
bool is_error() const
Returns if this return code is not kErrorCodeOk.
The child engine observed some unrecoverable error and has exit.
SharedMemoryRepo * get_shared_memory_repo()
Returns the shared memories maintained across SOCs.
Definition: soc_manager.cpp:38
void memory_fence_acq_rel()
Equivalent to std::atomic_thread_fence(std::memory_order_acq_rel).