libfoedus-core
FOEDUS Core Library
soc_manager_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  */
19 
20 #include <spawn.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <glog/logging.h>
24 #include <sys/prctl.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 
28 #include <chrono>
29 #include <cstdlib>
30 #include <cstring>
31 #include <iostream>
32 #include <string>
33 #include <thread>
34 #include <vector>
35 
36 #include "foedus/engine.hpp"
38 #include "foedus/engine_type.hpp"
39 #include "foedus/epoch.hpp"
44 
45 namespace foedus {
46 namespace soc {
47 // SOC manager is initialized at first even before debug module.
48 // So, we can't use glog yet.
50  if (engine_->is_master()) {
51  return initialize_master();
52  } else {
53  return initialize_child();
54  }
55 }
56 
58  ErrorStackBatch batch;
59  if (engine_->is_master() && memory_repo_.get_global_memory() != nullptr) {
60  CHECK_ERROR(wait_for_child_terminate()); // wait for children to terminate
62  }
64  return SUMMARIZE_ERROR_BATCH(batch);
65 }
66 
68  if (!is_initialized()) {
69  std::cerr << "[FOEDUS] Shared memory not initialized yet. Can't report errors" << std::endl;
70  return;
71  }
72  if (engine_->is_master()) {
74  if (status) {
76  }
77  } else {
79  engine_->get_soc_id())->child_status_memory_;
80  if (status) {
82  }
83  }
84 }
85 
90  engine_->get_options());
91  if (alloc_error.is_error()) {
93  return alloc_error;
94  }
95 
96  // shared memory allocated. now launch child SOCs
99  std::memset(child_upids_, 0, sizeof(child_upids_));
100 
101  // set initial value of initialize/uninitialize status now
102  {
105  status->initialized_modules_ = kInvalid;
107  }
108  uint16_t soc_count = engine_->get_options().thread_.group_count_;
109  for (uint16_t node = 0; node < soc_count; ++node) {
112  status->initialized_modules_ = kInvalid;
114  }
115 
117  if (soc_type == kChildForked) {
119  } else if (soc_type == kChildLocalSpawned || soc_type == kChildRemoteSpawned) {
120  // so far remote spawn does local spawn
122  } else {
124  }
125  return kRetOk;
126 }
127 
129  Upid master_upid = engine_->get_master_upid();
130  Eid master_eid = engine_->get_master_eid();
131  SocId soc_id = engine_->get_soc_id();
132  pid_t pid = ::getpid();
134  master_upid,
135  master_eid,
136  soc_id,
138  if (attach_error.is_error()) {
139  std::cerr << "[FOEDUS-Child] MasterUpid=" << master_upid << ", ChildPid=" << pid
140  << ", Node=" << soc_id << ". Failed to attach shared memory. error=" << attach_error
141  << " This is an unrecoverable error. This process quits shortly" << std::endl;
142  ::_exit(1);
143  }
145 
146  // child engines could just move on, but it's safer to wait for at least the reclamation
147  // of shared memory by master engine.
149  return kRetOk;
150 }
151 
153  // As of this method, glog is not initialized. So, use std::cerr only.
154  // When this method begins, the shared memory is in the most fragile state, not marked for
155  // reclamation but needs to be open for shmget. Be careful in this method!
156  // We avoid even assertions in this method.
157  // As soon as something unusual happens, we conservatively release the shared memory.
158  uint16_t soc_count = engine_->get_options().thread_.group_count_;
159 
160  // robustly wait until all children attached the shared memory.
161  // mark-for-reclaim as soon as possible.
162  const uint32_t kIntervalMillisecond = 20;
163  const uint32_t kTimeoutMillisecond = 10000;
164  uint32_t trials = 0;
165  bool child_as_process = engine_->get_options().soc_.soc_type_ != kChildEmulated;
166  while (true) {
168  std::this_thread::sleep_for(std::chrono::milliseconds(kIntervalMillisecond));
169  bool error_happened = false;
170  bool remaining = false;
171  for (uint16_t node = 0; node < soc_count; ++node) {
173  switch (child_status) {
175  remaining = true;
176  break;
178  break;
179  default:
180  // all other statuses are unexpected
181  error_happened = true;
182  break;
183  }
184  if (child_as_process) {
185  // if we launched the child as a process, let's also check with waitpid()
186  // this doesn't do anything if they are emulated children
187  if (!error_happened && child_upids_[node] != 0) {
188  int status = 0;
189  pid_t wait_ret = ::waitpid(child_upids_[node], &status, WNOHANG | __WALL);
190  if (wait_ret == -1) {
191  std::cerr << "[FOEDUS] FATAL! waitpid() for child-process " << child_upids_[node]
192  << " failed. os error=" << assorted::os_error() << std::endl;
193  error_happened = true;
194  break;
195  } else if (wait_ret != 0) {
196  std::cerr << "[FOEDUS] FATAL! child-process " << child_upids_[node] << " has exit"
197  << " unexpectedly. status=" << status << std::endl;
198  error_happened = true;
199  break;
200  }
201  }
202  }
203  }
204 
205  if (error_happened) {
206  std::cerr << "[FOEDUS] FATAL! Some child failed to attach shared memory." << std::endl;
210  } else if (!remaining) {
211  break; // done!
212  } else if ((++trials) * kIntervalMillisecond > kTimeoutMillisecond) {
213  std::cerr << "[FOEDUS] FATAL! Timeout happend while waiting for child SOCs to start up."
214  " Probably child SOC(s) hanged or did not trap SOC execution (if spawned)." << std::endl;
218  }
219  }
220 
221  // as soon as all children ack-ed, mark the shared memory for release.
222  // no one will newly issue shmget.
224  memory_repo_.mark_for_release(); // now it's safe. closed attaching and marked for reclaim.
225  return kRetOk;
226 }
227 
229  uint16_t soc_count = engine_->get_options().thread_.group_count_;
230  const uint32_t kIntervalMillisecond = 20;
231  const uint32_t kTimeoutMillisecond = 10000;
232  uint32_t trials = 0;
233  bool child_as_process = engine_->get_options().soc_.soc_type_ != kChildEmulated;
234  while (true) {
236  std::this_thread::sleep_for(std::chrono::milliseconds(kIntervalMillisecond));
237  bool remaining = false;
238  for (uint16_t node = 0; node < soc_count; ++node) {
240  if (!child_as_process) {
241  if (child_status == ChildEngineStatus::kTerminated
242  || child_status == ChildEngineStatus::kFatalError) {
243  if (child_emulated_threads_[node].joinable()) {
244  child_emulated_threads_[node].join();
245  }
246  } else {
247  if (child_emulated_threads_[node].joinable()) {
248  remaining = true;
249  }
250  }
251  continue;
252  }
253  if (child_status == ChildEngineStatus::kRunning) {
254  // also check with waitpid(). if the child process terminated, it's fine.
255  if (child_upids_[node] != 0) {
256  int status = 0;
257  pid_t wait_ret = ::waitpid(child_upids_[node], &status, WNOHANG | __WALL);
258  if (wait_ret == -1) {
259  // this is okay, too. the process has already terminated
260  } else if (wait_ret == 0) {
261  remaining = true;
262  } else if (WIFSIGNALED(status)) {
263  std::cerr << "[FOEDUS] ERROR! child-process " << child_upids_[node] << " has been"
264  << " terminated by signal. status=" << status << std::endl;
267  }
268  }
269  }
270  }
271 
272  if (!remaining) {
273  break; // done!
274  } else if ((++trials) * kIntervalMillisecond > kTimeoutMillisecond) {
275  std::cerr << "[FOEDUS] ERROR! Timeout happend while waiting for child SOCs to terminate."
276  " Probably child SOC(s) hanged or did not trap SOC execution (if spawned)." << std::endl;
279  }
280  }
281 
282  return kRetOk;
283 }
284 
285 
288  const uint32_t kIntervalMillisecond = 10;
289 // bool child_as_process = engine_->get_options().soc_.soc_type_ != kChildEmulated;
290  while (true) {
292  std::this_thread::sleep_for(std::chrono::milliseconds(kIntervalMillisecond));
294  if (master_status == target_status) {
295  break; // wait done
296  } else if (master_status == MasterEngineStatus::kFatalError) {
298  } else if (static_cast<int>(master_status) > static_cast<int>(target_status)) {
300  }
301 /*
302  this doesn't work because waitpid is only for child processes.
303  As an alternative to die when parent dies, we use prctl().
304  if (child_as_process) {
305  // Also check parent's process status.
306  Upid master_upid = engine_->get_master_upid();
307  int status = 0;
308  pid_t wait_ret = ::waitpid(master_upid, &status, WNOHANG);
309  if (wait_ret == -1) {
310  std::cerr << "[FOEDUS-Child] FATAL! waitpid() for master-process " << master_upid
311  << " failed. os error:" << assorted::os_error() << std::endl;
312  return ERROR_STACK(kErrorCodeSocMasterDied);
313  } else if (WIFEXITED(status)) {
314  std::cerr << "[FOEDUS-Child] FATAL! master-process " << master_upid << " has exit"
315  << " unexpectedly. status=" << status << std::endl;
316  return ERROR_STACK(kErrorCodeSocMasterDied);
317  } else if (WIFSIGNALED(status)) {
318  std::cerr << "[FOEDUS-Child] FATAL! master-process " << master_upid << " has been"
319  << " terminated by signal. status=" << status << std::endl;
320  return ERROR_STACK(kErrorCodeSocMasterDied);
321  }
322  }
323 */
324  }
325  return kRetOk;
326 }
328  const uint32_t kWarnSleeps = 400;
329  for (uint32_t count = 0;; ++count) {
330  if (count > 0 && count % kWarnSleeps == 0) {
331  LOG(WARNING) << "Suspiciously long wait for master " << (init ? "" : "un") << "initializing"
332  << " module-" << desired << ". count=" << count;
333  }
338  LOG(ERROR) << "Master apparently died while wait_for_master_module";
339  if (init) {
341  } else {
343  }
344  }
347  ModuleType cur;
348  if (init) {
349  cur = status->initialized_modules_;
350  } else {
351  cur = status->uninitialized_modules_;
352  }
353  if (cur == desired) {
354  break;
355  }
356  std::this_thread::sleep_for(std::chrono::milliseconds(5));
357  }
358  return kRetOk;
359 }
361  ASSERT_ND(desired != kSoc); // this method assumes SOC manager is active
362  uint16_t soc_count = engine_->get_options().thread_.group_count_;
363  bool child_as_process = engine_->get_options().soc_.soc_type_ != kChildEmulated;
364 
365  // TASK(Hideaki) should be a function in soc manager
366  // We also check if the child died unexpectedly
367  const uint32_t kWarnSleeps = 400;
368  for (uint32_t count = 0;; ++count) {
369  if (count > 0 && count % kWarnSleeps == 0) {
370  LOG(WARNING) << "Suspiciously long wait for child " << (init ? "" : "un") << "initializing"
371  << " module-" << desired << ". count=" << count;
372  }
374  std::this_thread::sleep_for(std::chrono::milliseconds(5));
376  bool error_happened = false;
377  bool remaining = false;
378  for (uint16_t node = 0; node < soc_count; ++node) {
382  error_happened = true;
383  break;
384  }
385  if (init) {
386  if (status->initialized_modules_ == desired) {
387  continue; // ok
388  } else if (static_cast<int>(status->initialized_modules_)
389  > static_cast<int>(desired)) {
390  LOG(ERROR) << "[FOEDUS] child init went too far??";
391  error_happened = true;
392  break;
393  }
394  } else {
395  if (status->uninitialized_modules_ == desired) {
396  continue; // ok
397  } else if (static_cast<int>(status->uninitialized_modules_)
398  < static_cast<int>(desired)) {
399  LOG(ERROR) << "[FOEDUS] ERROR! child uninit went too far??";
400  error_happened = true;
401  break;
402  }
403  }
404  remaining = true;
405  if (child_as_process) {
406  // TASK(Hideaki) check child process status with waitpid
407  if (child_upids_[node] != 0) {
408  int status = 0;
409  pid_t wait_ret = ::waitpid(child_upids_[node], &status, WNOHANG | __WALL);
410  if (wait_ret == -1) {
411  // this is okay, too. the process has already terminated
412  error_happened = true;
413  LOG(ERROR) << "waitpid() while waiting for child module status failed";
414  break;
415  } else if (wait_ret != 0) {
416  // this is okay
417  error_happened = true;
418  LOG(ERROR) << "child process has already exit while waiting for child module status";
419  break;
420  }
421  }
422  }
423  }
424 
425  if (error_happened) {
426  LOG(ERROR) << "Error encountered in wait_for_children_module";
427  if (init) {
429  } else {
431  }
432  } else if (!remaining) {
433  break;
434  }
435  }
436  return kRetOk;
437 }
438 
439 
441 //
442 // Child SOCs: Emulate
443 //
446  uint16_t soc_count = engine_->get_options().thread_.group_count_;
447  for (uint16_t node = 0; node < soc_count; ++node) {
448  child_emulated_engines_.push_back(nullptr);
449  }
450  // from now on child_emulated_engines_ doesn't grow/shrink
451  for (uint16_t node = 0; node < soc_count; ++node) {
452  child_emulated_threads_.emplace_back(std::thread(
454  this,
455  node));
456  }
457 
459  return kRetOk;
460 }
461 
463  Upid master_upid = engine_->get_master_upid();
464  Eid master_eid = engine_->get_master_eid();
465  // We can reuse procedures pre-registered in master. Good for being a thread.
466  const auto& procedures = engine_->get_proc_manager()->get_pre_registered_procedures();
467  ErrorStack ret = child_main_common(kChildEmulated, master_upid, master_eid, node, procedures);
468  if (ret.is_error()) {
469  std::cerr << "[FOEDUS-Child] Emulated SOC-" << node
470  << " exits with an error: " << ret << std::endl;
471  }
472 }
473 
475 //
476 // Child SOCs: fork
477 //
480  uint16_t soc_count = engine_->get_options().thread_.group_count_;
481  for (uint16_t node = 0; node < soc_count; ++node) {
482  pid_t pid = ::fork();
483  if (pid == -1) {
484  // failed to fork! immediately release shared memory and return.
487  std::cerr << "[FOEDUS] Failed to fork child SOC. error=" << assorted::os_error() << std::endl;
488  // the already forked children will shortly notice that the parent failed and exits.
490  } else if (pid == 0) {
491  // child
492  int child_ret = forked_child_main(node);
493  ::_exit(child_ret);
494  } else {
495  // parent. move on.
496  child_upids_[node] = pid;
497  }
498  }
500  return kRetOk;
501 }
502 
504  Upid master_upid = engine_->get_master_upid();
505  Eid master_eid = engine_->get_master_eid();
506  // These are pre-registered before fork(), so still we can reuse.
507  const auto& procedures = engine_->get_proc_manager()->get_pre_registered_procedures();
508  ErrorStack ret = child_main_common(kChildForked, master_upid, master_eid, node, procedures);
509  if (ret.is_error()) {
510  std::cerr << "[FOEDUS-Child] Forked SOC-" << node
511  << " exits with an error: " << ret << std::endl;
512  return EXIT_FAILURE;
513  } else {
514  return EXIT_SUCCESS;
515  }
516 }
517 
519 //
520 // Child SOCs: spawn
521 //
524  Upid master_upid = engine_->get_master_upid();
525  Eid master_eid = engine_->get_master_eid();
526  uint16_t soc_count = engine_->get_options().thread_.group_count_;
527  for (uint16_t node = 0; node < soc_count; ++node) {
528  posix_spawn_file_actions_t file_actions;
529  posix_spawnattr_t attr;
530  ::posix_spawn_file_actions_init(&file_actions);
531  ::posix_spawnattr_init(&attr);
532  std::string executable = engine_->get_options().soc_.convert_spawn_executable_pattern(node);
533  std::string ld_path = engine_->get_options().soc_.convert_spawn_ld_library_path_pattern(node);
534  std::string ld_env("LD_LIBRARY_PATH=");
535  ld_env += ld_path;
536  std::string pid_env("FOEDUS_MASTER_UPID=");
537  pid_env += std::to_string(master_upid);
538  std::string eid_env("FOEDUS_MASTER_EID=");
539  eid_env += std::to_string(master_eid);
540  std::string soc_id_env("FOEDUS_SOC_ID=");
541  soc_id_env += std::to_string(node);
542 
543  char* const argv[] = { const_cast<char*>(executable.c_str()), nullptr};
544  char* const envp[] = {
545  const_cast<char*>(ld_env.c_str()),
546  const_cast<char*>(pid_env.c_str()),
547  const_cast<char*>(eid_env.c_str()),
548  const_cast<char*>(soc_id_env.c_str()),
549  nullptr};
550 
551  pid_t child_pid;
552  int ret = ::posix_spawn(&child_pid, executable.c_str(), &file_actions, &attr, argv, envp);
553  if (ret == -1) {
554  // failed to spawn! immediately release shared memory and return.
557  std::cerr << "[FOEDUS] Failed to spawn child SOC. error="
558  << assorted::os_error() << std::endl;
559  // the already spawned children will shortly notice that the parent failed and exits.
561  }
562  child_upids_[node] = child_pid;
563  }
565  return kRetOk;
566 }
567 
568 void SocManagerPimpl::spawned_child_main(const std::vector< proc::ProcAndName >& procedures) {
569  const char* master_upid_str = std::getenv("FOEDUS_MASTER_UPID");
570  const char* master_eid_str = std::getenv("FOEDUS_MASTER_EID");
571  const char* soc_id_str = std::getenv("FOEDUS_SOC_ID");
572  if (master_upid_str == nullptr || master_eid_str == nullptr || soc_id_str == nullptr) {
573  return; // not launched as an SOC engine. exit
574  }
575 
576  Upid master_upid = std::atoll(master_upid_str);
577  Eid master_eid = std::atoll(master_eid_str);
578  SocId node = std::atol(master_upid_str);
579  ErrorStack ret = child_main_common(kChildLocalSpawned, master_upid, master_eid, node, procedures);
580  if (ret.is_error()) {
581  std::cerr << "[FOEDUS-Child] Spawned SOC-" << node
582  << " exits with an error: " << ret << std::endl;
583  ::_exit(EXIT_FAILURE);
584  } else {
585  ::_exit(EXIT_SUCCESS);
586  }
587 }
588 
590 //
591 // Child SOCs: common
592 //
595  EngineType engine_type,
596  Upid master_upid,
597  Eid master_eid,
598  SocId node,
599  const std::vector< proc::ProcAndName >& procedures) {
600  thread::NumaThreadScope scope(node);
601 
602  // In order to make sure child processes die as soon as the parent dies,
603  // we use prctl.
604  if (engine_type != kChildEmulated) {
605  ::prctl(PR_SET_PDEATHSIG, SIGHUP);
606  }
607 
608  Engine soc_engine(engine_type, master_upid, master_eid, node);
609  ErrorStack init_error = soc_engine.initialize();
610  if (init_error.is_error()) {
611  std::cerr << "[FOEDUS-Child] Failed to initialize child SOC-" << node
612  << ". error=" << init_error
613  << " This is an unrecoverable error. This process quits shortly" << std::endl;
614  CHECK_ERROR(soc_engine.uninitialize());
615  return init_error;
616  }
617 
618  SocManagerPimpl* soc_this = soc_engine.get_soc_manager()->pimpl_;
619  SharedMemoryRepo& soc_memory = soc_this->memory_repo_;
620 
621  // after initialize(), we can safely use glog.
622  LOG(INFO) << "The SOC engine-" << node << " was initialized.";
623 
624  // Add the given procedures.
625  proc::ProcManager* procm = soc_engine.get_proc_manager();
626  for (const proc::ProcAndName& proc_and_name : procedures) {
627  COERCE_ERROR(procm->local_register(proc_and_name));
628  }
629 
630  LOG(INFO) << "Added user procedures: " << procm->describe_registered_procs()
631  << ". Waiting for master engine's initialization...";
634  LOG(INFO) << "The SOC engine-" << node << " detected that master engine has started"
635  << " running.";
638 
639  LOG(INFO) << "Stopping the SOC engine-" << node;
641  ErrorStack uninit_error = soc_engine.uninitialize();
642  if (uninit_error.is_error()) {
643  LOG(ERROR) << "Error while uninitializing SOC engine-" << node << ": " << uninit_error;
644  return uninit_error;
645  }
646 
647  return kRetOk;
648 }
649 
650 } // namespace soc
651 } // namespace foedus
ErrorStack uninitialize_once() override
Upid child_upids_[kMaxSocs]
Process IDs of child SOCs.
ErrorStack allocate_shared_memories(uint64_t upid, Eid eid, const EngineOptions &options)
Master process creates shared memories by calling this method.
0x0C04 : "SOC : Failed to spawn child SOCs." .
Definition: error_code.hpp:223
void emulated_child_main(SocId node)
Main routine of emulated SOCs.
0x0C02 : "SOC : Failed to attach a shared memory." .
Definition: error_code.hpp:221
ErrorStack initialize() override
Starts up the database engine.
Definition: engine.cpp:64
The master engine has normally terminated.
ModuleType initialized_modules_
The module that has been most recently initialized in this node.
static ErrorStack child_main_common(EngineType engine_type, Upid master_upid, Eid master_eid, SocId node, const std::vector< proc::ProcAndName > &procedures)
void change_master_status(MasterEngineStatus::StatusCode new_status)
#define ERROR_STACK(e)
Instantiates ErrorStack with the given foedus::error_code, creating an error stack with the current f...
ErrorStack launch_forked_children()
Launch children via fork.
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()
StatusCode
These statuses represent each step described in SocManager comment.
Eid get_master_eid() const
Returns Engine ID of the master engine.
Definition: engine.cpp:76
std::vector< std::thread > child_emulated_threads_
Threads that emulate child SOCs.
void deallocate_shared_memories()
Detaches and releases the shared memories.
void change_status_atomic(StatusCode new_status)
Update the value of status_code_ with fence.
void change_status_atomic(StatusCode new_status)
Update the value of status_code_ with fence.
static void spawned_child_main(const std::vector< proc::ProcAndName > &procedures)
Main routine of spawned SOCs.
Whenever child observes this, they will call _exit() asap.
Brings error stacktrace information as return value of functions.
Definition: error_stack.hpp:81
EngineType soc_type_
How to launch SOC engine instances.
Definition: soc_options.hpp:54
0x0C0A : "SOC : Failed to normally terminate some SOC(s).." .
Definition: error_code.hpp:229
FileStatus status(const Path &p)
Returns the status of the file.
Definition: filesystem.cpp:45
void mark_for_release()
Marks shared memories as being removed so that it will be reclaimed when all processes detach it...
A child SOC instance launched in other machines.
Definition: engine_type.hpp:87
NodeMemoryAnchors * get_node_memory_anchors(SocId node)
Pin the current thread to the given NUMA node in this object's scope.
Procedure manager, which maintains the list of system/user procedures.
0x0C0B : "SOC : Child SOC failed to initialize a module." .
Definition: error_code.hpp:230
const EngineOptions & get_options() const
Definition: engine.cpp:39
0x0C03 : "SOC : Failed to fork child SOCs." .
Definition: error_code.hpp:222
ModuleType initialized_modules_
The module that has been most recently initialized in master.
ErrorStack initialize_master()
Called as part of initialize_once() if this is a master engine.
#define COERCE_ERROR(x)
This macro calls x and aborts if encounters an error.
bool is_master() const
Returns if this engine object is a master instance.
Definition: engine.cpp:68
Child engine successfully attached shared memory and waiting for master's kWaitingForChildInitializat...
ModuleType
Enumerates modules in FOEDUS engine.
Definition: module_type.hpp:26
The child engine has normally terminated.
Batches zero or more ErrorStack objects to represent in one ErrorStack.
ErrorStack wait_for_child_attach()
Wait for child SOCs to start up and at least finish attaching shared memory.
std::string convert_spawn_executable_pattern(int node) const
converts spawn_executable_pattern_ into a string with the given node ID.
Definition: soc_options.cpp:36
soc::Upid get_master_upid() const
Returns Universal (or Unique) ID of the master process.
Definition: engine.cpp:75
ErrorStack wait_for_children_module(bool init, ModuleType module)
0x0C09 : "SOC : Timeout happend while waiting for child SOCs to terminate. Probably child SOC(s) h...
Definition: error_code.hpp:228
std::string describe_registered_procs() const
For debug uses only.
ErrorStack launch_emulated_children()
Launch emulated children as threads.
Current status of master engine.
ErrorStack attach_shared_memories(uint64_t master_upid, Eid master_eid, SocId my_soc_id, EngineOptions *options)
Child processes (emulated or not) set a reference to shared memory and receive the EngnieOption value...
int forked_child_main(SocId node)
Main routine of forked SOCs.
ErrorStack wait_for_master_module(bool init, ModuleType module)
A child SOC instance launched via spawn().
Definition: engine_type.hpp:78
Database engine object that holds all resources and provides APIs.
Definition: engine.hpp:109
Done all initialization and running transactions.
std::vector< Engine * > child_emulated_engines_
And their engines.
ErrorStack initialize_once() override
std::pair< ProcName, Proc > ProcAndName
Just a std::pair.
Definition: proc_id.hpp:119
Child engine has successfully initialized all modules and is now waiting for master's kRunning status...
EngineType
Type of an engine instance of how to launch it.
Definition: engine_type.hpp:35
ErrorStack launch_spawned_children()
Launch children via spawn.
ErrorStack wait_for_master_status(MasterEngineStatus::StatusCode target_status)
Wait for master engine to finish upto the specified status.
Current status of a child SOC engine.
const std::vector< ProcAndName > & get_pre_registered_procedures() const
Returns procedures given to pre_register()
0x0C07 : "SOC : Master engine died unexpectedly. This child engine will follow." .
Definition: error_code.hpp:226
uint64_t Upid
Universal (or Unique) ID of a process.
Definition: soc_id.hpp:48
A child SOC instance launched via fork().
Definition: engine_type.hpp:65
proc::ProcManager * get_proc_manager() const
See System and User Procedures.
Definition: engine.cpp:51
uint16_t group_count_
Number of ThreadGroup in the engine.
0x0C06 : "SOC : Timeout happend while waiting for child SOCs to start up. Probably child SOC(s) ha...
Definition: error_code.hpp:225
EngineOptions * get_nonconst_options()
Returns an updatable reference to options.
Definition: engine.cpp:40
void spinlock_yield()
Invoke _mm_pause(), x86 PAUSE instruction, or something equivalent in the env.
Repository of all shared memory in one FOEDUS instance.
#define SUMMARIZE_ERROR_BATCH(x)
This macro calls ErrorStackBatch::summarize() with automatically provided parameters.
ErrorStack wait_for_child_terminate()
Wait for child SOCs to terminate.
uint16_t SocId
Represents an ID of an SOC, or NUMA node.
Definition: soc_id.hpp:41
std::string os_error()
Thread-safe strerror(errno).
thread::ThreadOptions thread_
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
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...
soc::SocManager * get_soc_manager() const
See SOC and IPC.
Definition: engine.cpp:59
Pimpl object of SocManager.
ErrorStack local_register(const ProcAndName &proc_and_name)
Register a function pointer as a user procedure in the current SOC.
ChildEngineStatus * child_status_memory_
This tiny piece of memory contains the current status of the child engine on this node...
0x0C08 : "SOC : The status of master engine is unexpected." .
Definition: error_code.hpp:227
soc::SocId get_soc_id() const
If this is a child instance, returns its SOC ID (NUMA node).
Definition: engine.cpp:73
uint64_t Eid
An Engine ID to differentiate two Engine objects instantiated in the same process.
Definition: engine_type.hpp:29
Done all initialization and running transactions.
void change_child_status(SocId node, ChildEngineStatus::StatusCode new_status)
0x0C0C : "SOC : Child SOC failed to uninitialize a module." .
Definition: error_code.hpp:231
#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
ModuleType uninitialized_modules_
The module that has been most recently closed in master.
ModuleType uninitialized_modules_
The module that has been most recently closed in this node.
ErrorStack initialize_child()
Called as part of initialize_once() if this is a child SOC engine.
bool is_initialized() const override final
Returns whether the object has been already initialized or not.
ChildEngineStatus::StatusCode get_child_status(SocId node) const
Master engine successfully allocated shared memory and waiting for child's attach.
std::string convert_spawn_ld_library_path_pattern(int node) const
converts spawn_ld_library_path_pattern_ into a string with the given node ID.
Definition: soc_options.cpp:44
Master engine successfully confirmed child's attach and reserved the reclamation of the shared memori...
StatusCode
These statuses represent each step described in SocManager comment.
bool is_error() const
Returns if this return code is not kErrorCodeOk.
The child engine observed some unrecoverable error and has exit.
MasterEngineStatus::StatusCode get_master_status() const
void memory_fence_acq_rel()
Equivalent to std::atomic_thread_fence(std::memory_order_acq_rel).
A child SOC instance launched just as a thread in the same process as master.
Definition: engine_type.hpp:51
ErrorStack uninitialize() override
Terminates the database engine.
Definition: engine.cpp:65