<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/
#include "MultiApp.h"

// Moose
#include "AppFactory.h"
#include "SetupInterface.h"
#include "Executioner.h"
#include "UserObject.h"
#include "FEProblem.h"
#include "Output.h"
#include "AppFactory.h"
#include "MooseUtils.h"

// libMesh
#include "libmesh/mesh_tools.h"

#include <iostream>
#include <iomanip>
#include <iterator>
#include <fstream>
#include <vector>
#include <algorithm>

template<>
InputParameters validParams<MultiApp>()
{
  InputParameters params = validParams<MooseObject>();

  params.addPrivateParam<bool>("use_displaced_mesh", false);

  std::ostringstream app_types_strings;

  registeredMooseAppIterator it = AppFactory::instance()->registeredObjectsBegin();
  while(it != AppFactory::instance()->registeredObjectsEnd())
  {
    app_types_strings << it->first;
    ++it;
    if(it != AppFactory::instance()->registeredObjectsEnd())
      app_types_strings<< ", ";
  }

  MooseEnum app_types_options(app_types_strings.str());

  params.addRequiredParam<MooseEnum>("app_type", app_types_options, "The type of application to build.");
  params.addParam<std::vector<Real> >("positions", "The positions of the App locations.  Each set of 3 values will represent a Point.  Either this must be supplied or 'positions_file'");
  params.addParam<FileName>("positions_file", "A filename that should be looked in for positions. Each set of 3 values in that file will represent a Point.  Either this must be supplied or 'positions'");

  params.addRequiredParam<std::vector<std::string> >("input_files", "The input file for each App.  If this parameter only contains one input file it will be used for all of the Apps.");

  params.addPrivateParam<MPI_Comm>("_mpi_comm");

  MooseEnum execute_options(SetupInterface::getExecuteOptions());
  execute_options = "timestep_begin";  // set the default

  params.addParam<MooseEnum>("execute_on", execute_options, "Set to (residual|jacobian|timestep|timestep_begin|custom) to execute only at that moment");

  params.addPrivateParam<std::string>("built_by_action", "add_multi_app");

  return params;
}

MultiApp::MultiApp(const std::string & name, InputParameters parameters):
    MooseObject(name, parameters),
    _fe_problem(getParam<FEProblem *>("_fe_problem")),
    _app_type(getParam<MooseEnum>("app_type")),
    _input_files(getParam<std::vector<std::string> >("input_files")),
    _orig_comm(getParam<MPI_Comm>("_mpi_comm")),
    _execute_on(getParam<MooseEnum>("execute_on"))
{
  if(isParamValid("positions"))
    _positions_vec = getParam<std::vector<Real> >("positions");
  else if(isParamValid("positions_file"))
  {
    // Read the file on the root processor then broadcast it
    if(libMesh::processor_id() == 0)
    {
      std::string positions_file = getParam<FileName>("positions_file");
      MooseUtils::checkFileReadable(positions_file);

      std::ifstream is(positions_file.c_str());
      std::istream_iterator<Real> begin(is), end;
      _positions_vec.insert(_positions_vec.begin(), begin, end);
    }
    unsigned int num_values = _positions_vec.size();

    Parallel::broadcast(num_values);

    _positions_vec.resize(num_values);

    Parallel::broadcast(_positions_vec);
  }
  else
    mooseError("Must supply either 'positions' or 'positions_file' for MultiApp "<<_name);

  { // Read the positions out of the vector
    unsigned int num_vec_entries = _positions_vec.size();

    mooseAssert(num_vec_entries % LIBMESH_DIM == 0, "Wrong number of entries in 'positions'");

    _positions.reserve(num_vec_entries / LIBMESH_DIM);

    for(unsigned int i=0; i<num_vec_entries; i+=3)
      _positions.push_back(Point(_positions_vec[i], _positions_vec[i+1], _positions_vec[i+2]));
  }

  _total_num_apps = _positions.size();
  mooseAssert(_input_files.size() == 1 || _positions.size() == _input_files.size(), "Number of positions and input files are not the same!");

  /// Set up our Comm and set the number of apps we're going to be working on
  buildComm();

  MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);

  _apps.resize(_my_num_apps);

  for(unsigned int i=0; i<_my_num_apps; i++)
  {
    InputParameters app_params = AppFactory::instance()->getValidParams(_app_type);
    MooseApp * app = AppFactory::instance()->create(_app_type, "multi_app", app_params);

    std::ostringstream output_base;

    // Create an output base by taking the output base of the master problem and appending
    // the name of the multiapp + a number to it
    output_base << _fe_problem->out().fileBase()
                << "_" << _name
                << std::setw(_total_num_apps/10)
                << std::setprecision(0)
                << std::setfill('0')
                << std::right
                << _first_local_app + i;

    _apps[i] = app;

    std::string input_file = "";
    if(_input_files.size() == 1) // If only one input file was provide, use it for all the solves
      input_file = _input_files[0];
    else
      input_file = _input_files[_first_local_app+i];

    app->setInputFileName(input_file);
    app->setOutputFileBase(output_base.str());
    app->setupOptions();
    app->runInputFile();
  }

  // Swap back
  Moose::swapLibMeshComm(swapped);
}

MultiApp::~MultiApp()
{
  for(unsigned int i=0; i<_my_num_apps; i++)
    delete _apps[i];
}

Executioner *
MultiApp::getExecutioner(unsigned int app)
{
  return _apps[globalAppToLocal(app)]->getExecutioner();
}

MeshTools::BoundingBox
MultiApp::getBoundingBox(unsigned int app)
{
  FEProblem * problem = appProblem(app);

  MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);

  MooseMesh & mesh = problem->mesh();
  MeshTools::BoundingBox bbox = MeshTools::bounding_box(mesh);

  Moose::swapLibMeshComm(swapped);

  return bbox;
}

FEProblem *
MultiApp::appProblem(unsigned int app)
{
  unsigned int local_app = globalAppToLocal(app);

  FEProblem * problem = dynamic_cast<FEProblem *>(&_apps[local_app]->getExecutioner()->problem());
  mooseAssert(problem, "Not an FEProblem!");

  return problem;
}

const UserObject &
MultiApp::appUserObjectBase(unsigned int app, const std::string & name)
{
  return appProblem(app)->getUserObjectBase(name);
}

Real
MultiApp::appPostprocessorValue(unsigned int app, const std::string & name)
{
  return appProblem(app)->getPostprocessorValue(name);
}

bool
MultiApp::hasLocalApp(unsigned int global_app)
{
  if(global_app >= _first_local_app && global_app <= _first_local_app + (_my_num_apps-1))
    return true;

  return false;
}

void
MultiApp::buildComm()
{
  MPI_Comm_size(_orig_comm, (int*)&_orig_num_procs);
  MPI_Comm_rank(_orig_comm, (int*)&_orig_rank);

  // If we have more apps than processors then we're just going to divide up the work
  if(_total_num_apps >= _orig_num_procs)
  {
    _my_comm = MPI_COMM_SELF;
    _my_rank = 0;

    _my_num_apps = _total_num_apps/_orig_num_procs;
    _first_local_app = _my_num_apps * _orig_rank;

    // The last processor will pick up any extra apps
    if(_orig_rank == _orig_num_procs - 1)
      _my_num_apps += _total_num_apps % _orig_num_procs;

    return;
  }

  // In this case we need to divide up the processors that are going to work on each app
  int rank;
  MPI_Comm_rank(_orig_comm, &rank);
//  sleep(rank);

  int procs_per_app = _orig_num_procs / _total_num_apps;
  int my_app = rank / procs_per_app;
  int procs_for_my_app = procs_per_app;

  if((unsigned int) my_app >= _total_num_apps-1) // The last app will gain any left-over procs
  {
    my_app = _total_num_apps - 1;
    procs_for_my_app += _orig_num_procs % _total_num_apps;
  }

  // Only one app here
  _first_local_app = my_app;
  _my_num_apps = 1;

  std::vector<int> ranks_in_my_group(procs_for_my_app);

  // Add all the processors in that are in my group
  for(int i=0; i<procs_for_my_app; i++)
    ranks_in_my_group[i] = (my_app * procs_per_app) + i;

  MPI_Group orig_group, new_group;

  // Extract the original group handle
  MPI_Comm_group(_orig_comm, &orig_group);

  // Create a group
  MPI_Group_incl(orig_group, procs_for_my_app, &ranks_in_my_group[0], &new_group);

  // Create new communicator
  MPI_Comm_create(_orig_comm, new_group, &_my_comm);
  MPI_Comm_rank(_my_comm, (int*)&_my_rank);
}

unsigned int
MultiApp::globalAppToLocal(unsigned int global_app)
{
  if(global_app >= _first_local_app && global_app <= _first_local_app + (_my_num_apps-1))
    return global_app-_first_local_app;

  std::cout<<_first_local_app<<" "<<global_app<<std::endl;
  mooseError("Invalid global_app!");
}

<commit_msg>fix zeros for outputting multiapp files ref #1845<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/
#include "MultiApp.h"

// Moose
#include "AppFactory.h"
#include "SetupInterface.h"
#include "Executioner.h"
#include "UserObject.h"
#include "FEProblem.h"
#include "Output.h"
#include "AppFactory.h"
#include "MooseUtils.h"

// libMesh
#include "libmesh/mesh_tools.h"

#include <iostream>
#include <iomanip>
#include <iterator>
#include <fstream>
#include <vector>
#include <algorithm>

template<>
InputParameters validParams<MultiApp>()
{
  InputParameters params = validParams<MooseObject>();

  params.addPrivateParam<bool>("use_displaced_mesh", false);

  std::ostringstream app_types_strings;

  registeredMooseAppIterator it = AppFactory::instance()->registeredObjectsBegin();
  while(it != AppFactory::instance()->registeredObjectsEnd())
  {
    app_types_strings << it->first;
    ++it;
    if(it != AppFactory::instance()->registeredObjectsEnd())
      app_types_strings<< ", ";
  }

  MooseEnum app_types_options(app_types_strings.str());

  params.addRequiredParam<MooseEnum>("app_type", app_types_options, "The type of application to build.");
  params.addParam<std::vector<Real> >("positions", "The positions of the App locations.  Each set of 3 values will represent a Point.  Either this must be supplied or 'positions_file'");
  params.addParam<FileName>("positions_file", "A filename that should be looked in for positions. Each set of 3 values in that file will represent a Point.  Either this must be supplied or 'positions'");

  params.addRequiredParam<std::vector<std::string> >("input_files", "The input file for each App.  If this parameter only contains one input file it will be used for all of the Apps.");

  params.addPrivateParam<MPI_Comm>("_mpi_comm");

  MooseEnum execute_options(SetupInterface::getExecuteOptions());
  execute_options = "timestep_begin";  // set the default

  params.addParam<MooseEnum>("execute_on", execute_options, "Set to (residual|jacobian|timestep|timestep_begin|custom) to execute only at that moment");

  params.addPrivateParam<std::string>("built_by_action", "add_multi_app");

  return params;
}

MultiApp::MultiApp(const std::string & name, InputParameters parameters):
    MooseObject(name, parameters),
    _fe_problem(getParam<FEProblem *>("_fe_problem")),
    _app_type(getParam<MooseEnum>("app_type")),
    _input_files(getParam<std::vector<std::string> >("input_files")),
    _orig_comm(getParam<MPI_Comm>("_mpi_comm")),
    _execute_on(getParam<MooseEnum>("execute_on"))
{
  if(isParamValid("positions"))
    _positions_vec = getParam<std::vector<Real> >("positions");
  else if(isParamValid("positions_file"))
  {
    // Read the file on the root processor then broadcast it
    if(libMesh::processor_id() == 0)
    {
      std::string positions_file = getParam<FileName>("positions_file");
      MooseUtils::checkFileReadable(positions_file);

      std::ifstream is(positions_file.c_str());
      std::istream_iterator<Real> begin(is), end;
      _positions_vec.insert(_positions_vec.begin(), begin, end);
    }
    unsigned int num_values = _positions_vec.size();

    Parallel::broadcast(num_values);

    _positions_vec.resize(num_values);

    Parallel::broadcast(_positions_vec);
  }
  else
    mooseError("Must supply either 'positions' or 'positions_file' for MultiApp "<<_name);

  { // Read the positions out of the vector
    unsigned int num_vec_entries = _positions_vec.size();

    mooseAssert(num_vec_entries % LIBMESH_DIM == 0, "Wrong number of entries in 'positions'");

    _positions.reserve(num_vec_entries / LIBMESH_DIM);

    for(unsigned int i=0; i<num_vec_entries; i+=3)
      _positions.push_back(Point(_positions_vec[i], _positions_vec[i+1], _positions_vec[i+2]));
  }

  _total_num_apps = _positions.size();
  mooseAssert(_input_files.size() == 1 || _positions.size() == _input_files.size(), "Number of positions and input files are not the same!");

  /// Set up our Comm and set the number of apps we're going to be working on
  buildComm();

  MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);

  _apps.resize(_my_num_apps);

  for(unsigned int i=0; i<_my_num_apps; i++)
  {
    InputParameters app_params = AppFactory::instance()->getValidParams(_app_type);
    MooseApp * app = AppFactory::instance()->create(_app_type, "multi_app", app_params);

    std::ostringstream output_base;

    // Create an output base by taking the output base of the master problem and appending
    // the name of the multiapp + a number to it
    output_base << _fe_problem->out().fileBase()
                << "_" << _name
                << std::setw(std::ceil(std::log10(_total_num_apps)))
                << std::setprecision(0)
                << std::setfill('0')
                << std::right
                << _first_local_app + i;

    _apps[i] = app;

    std::string input_file = "";
    if(_input_files.size() == 1) // If only one input file was provide, use it for all the solves
      input_file = _input_files[0];
    else
      input_file = _input_files[_first_local_app+i];

    app->setInputFileName(input_file);
    app->setOutputFileBase(output_base.str());
    app->setupOptions();
    app->runInputFile();
  }

  // Swap back
  Moose::swapLibMeshComm(swapped);
}

MultiApp::~MultiApp()
{
  for(unsigned int i=0; i<_my_num_apps; i++)
    delete _apps[i];
}

Executioner *
MultiApp::getExecutioner(unsigned int app)
{
  return _apps[globalAppToLocal(app)]->getExecutioner();
}

MeshTools::BoundingBox
MultiApp::getBoundingBox(unsigned int app)
{
  FEProblem * problem = appProblem(app);

  MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);

  MooseMesh & mesh = problem->mesh();
  MeshTools::BoundingBox bbox = MeshTools::bounding_box(mesh);

  Moose::swapLibMeshComm(swapped);

  return bbox;
}

FEProblem *
MultiApp::appProblem(unsigned int app)
{
  unsigned int local_app = globalAppToLocal(app);

  FEProblem * problem = dynamic_cast<FEProblem *>(&_apps[local_app]->getExecutioner()->problem());
  mooseAssert(problem, "Not an FEProblem!");

  return problem;
}

const UserObject &
MultiApp::appUserObjectBase(unsigned int app, const std::string & name)
{
  return appProblem(app)->getUserObjectBase(name);
}

Real
MultiApp::appPostprocessorValue(unsigned int app, const std::string & name)
{
  return appProblem(app)->getPostprocessorValue(name);
}

bool
MultiApp::hasLocalApp(unsigned int global_app)
{
  if(global_app >= _first_local_app && global_app <= _first_local_app + (_my_num_apps-1))
    return true;

  return false;
}

void
MultiApp::buildComm()
{
  MPI_Comm_size(_orig_comm, (int*)&_orig_num_procs);
  MPI_Comm_rank(_orig_comm, (int*)&_orig_rank);

  // If we have more apps than processors then we're just going to divide up the work
  if(_total_num_apps >= _orig_num_procs)
  {
    _my_comm = MPI_COMM_SELF;
    _my_rank = 0;

    _my_num_apps = _total_num_apps/_orig_num_procs;
    _first_local_app = _my_num_apps * _orig_rank;

    // The last processor will pick up any extra apps
    if(_orig_rank == _orig_num_procs - 1)
      _my_num_apps += _total_num_apps % _orig_num_procs;

    return;
  }

  // In this case we need to divide up the processors that are going to work on each app
  int rank;
  MPI_Comm_rank(_orig_comm, &rank);
//  sleep(rank);

  int procs_per_app = _orig_num_procs / _total_num_apps;
  int my_app = rank / procs_per_app;
  int procs_for_my_app = procs_per_app;

  if((unsigned int) my_app >= _total_num_apps-1) // The last app will gain any left-over procs
  {
    my_app = _total_num_apps - 1;
    procs_for_my_app += _orig_num_procs % _total_num_apps;
  }

  // Only one app here
  _first_local_app = my_app;
  _my_num_apps = 1;

  std::vector<int> ranks_in_my_group(procs_for_my_app);

  // Add all the processors in that are in my group
  for(int i=0; i<procs_for_my_app; i++)
    ranks_in_my_group[i] = (my_app * procs_per_app) + i;

  MPI_Group orig_group, new_group;

  // Extract the original group handle
  MPI_Comm_group(_orig_comm, &orig_group);

  // Create a group
  MPI_Group_incl(orig_group, procs_for_my_app, &ranks_in_my_group[0], &new_group);

  // Create new communicator
  MPI_Comm_create(_orig_comm, new_group, &_my_comm);
  MPI_Comm_rank(_my_comm, (int*)&_my_rank);
}

unsigned int
MultiApp::globalAppToLocal(unsigned int global_app)
{
  if(global_app >= _first_local_app && global_app <= _first_local_app + (_my_num_apps-1))
    return global_app-_first_local_app;

  std::cout<<_first_local_app<<" "<<global_app<<std::endl;
  mooseError("Invalid global_app!");
}

<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// C POSIX includes
#include <sys/stat.h>

// Moose includes
#include "Checkpoint.h"
#include "FEProblem.h"
#include "MooseApp.h"
#include "MaterialPropertyStorage.h"
#include "RestartableData.h"
#include "MooseMesh.h"

#include "libmesh/checkpoint_io.h"
#include "libmesh/enum_xdr_mode.h"

template <>
InputParameters
validParams<Checkpoint>()
{
  // Get the parameters from the base classes
  InputParameters params = validParams<FileOutput>();

  // Typical checkpoint options
  params.addParam<unsigned int>("num_files", 2, "Number of the restart files to save");
  params.addParam<std::string>(
      "suffix",
      "cp",
      "This will be appended to the file_base to create the directory name for checkpoint files.");

  // Advanced settings
  params.addParam<bool>("binary", true, "Toggle the output of binary files");
  params.addParamNamesToGroup("binary", "Advanced");
  return params;
}

Checkpoint::Checkpoint(const InputParameters & parameters)
  : FileOutput(parameters),
    _num_files(getParam<unsigned int>("num_files")),
    _suffix(getParam<std::string>("suffix")),
    _binary(getParam<bool>("binary")),
    _parallel_mesh(_problem_ptr->mesh().isDistributedMesh()),
    _restartable_data(_app.getRestartableData()),
    _recoverable_data(_app.getRecoverableData()),
    _material_property_storage(_problem_ptr->getMaterialPropertyStorage()),
    _bnd_material_property_storage(_problem_ptr->getBndMaterialPropertyStorage()),
    _restartable_data_io(RestartableDataIO(*_problem_ptr))
{
}

std::string
Checkpoint::filename()
{
  // Get the time step with correct zero padding
  std::ostringstream output;
  output << directory() << "/" << std::setw(_padding) << std::setprecision(0) << std::setfill('0')
         << std::right << timeStep();
  return output.str();
}

std::string
Checkpoint::directory()
{
  return _file_base + "_" + _suffix;
}

void
Checkpoint::output(const ExecFlagType & /*type*/)
{
  // Start the performance log
  Moose::perf_log.push("Checkpoint::output()", "Output");

  // Create the output directory
  std::string cp_dir = directory();
  mkdir(cp_dir.c_str(), S_IRWXU | S_IRGRP);

  // Create the output filename
  std::string current_file = filename();

  // Create the libMesh Checkpoint_IO object
  MeshBase & mesh = _es_ptr->get_mesh();
  CheckpointIO io(mesh, _binary);

  // Set libHilbert renumbering flag to false.  We don't support
  // N-to-M restarts regardless, and if we're *never* going to do
  // N-to-M restarts then libHilbert is just unnecessary computation
  // and communication.
  const bool renumber = false;

  // Create checkpoint file structure
  CheckpointFileNames current_file_struct;
  if (_binary)
  {
    current_file_struct.checkpoint = current_file + "_mesh.cpr";
    current_file_struct.system = current_file + ".xdr";
  }
  else
  {
    current_file_struct.checkpoint = current_file + "_mesh.cpa";
    current_file_struct.system = current_file + ".xda";
  }
  current_file_struct.restart = current_file + ".rd";

  // Write the checkpoint file
  io.write(current_file_struct.checkpoint);

  // Write the system data, using ENCODE vs WRITE based on xdr vs xda
  _es_ptr->write(current_file_struct.system,
                 EquationSystems::WRITE_DATA | EquationSystems::WRITE_ADDITIONAL_DATA |
                     EquationSystems::WRITE_PARALLEL_FILES,
                 renumber);

  // Write the restartable data
  _restartable_data_io.writeRestartableData(
      current_file_struct.restart, _restartable_data, _recoverable_data);

  // Remove old checkpoint files
  updateCheckpointFiles(current_file_struct);

  // Stop the logging
  Moose::perf_log.pop("Checkpoint::output()", "Output");
}

void
Checkpoint::updateCheckpointFiles(CheckpointFileNames file_struct)
{
  // Update the list of stored files
  _file_names.push_back(file_struct);

  // Remove un-wanted files
  if (_file_names.size() > _num_files)
  {
    // Extract the filenames to be removed
    CheckpointFileNames delete_files = _file_names.front();

    // Remove these filenames from the list
    _file_names.pop_front();

    // Get thread and proc information
    processor_id_type proc_id = processor_id();

    // Delete checkpoint files (_mesh.cpr)
    if (proc_id == 0)
    {
      std::ostringstream oss;
      oss << delete_files.checkpoint;
      std::string file_name = oss.str();
      CheckpointIO::cleanup(file_name, comm().size());
    }

    // Delete the system files (xdr and xdr.0000, ...)
    if (proc_id == 0)
    {
      std::ostringstream oss;
      oss << delete_files.system;
      std::string file_name = oss.str();
      int ret = remove(file_name.c_str());
      if (ret != 0)
        mooseWarning("Error during the deletion of file '", file_name, "': ", std::strerror(ret));
    }

    {
      std::ostringstream oss;
      oss << delete_files.system << "." << std::setw(4) << std::setprecision(0) << std::setfill('0')
          << proc_id;
      std::string file_name = oss.str();
      int ret = remove(file_name.c_str());
      if (ret != 0)
        mooseWarning("Error during the deletion of file '", file_name, "': ", std::strerror(ret));
    }

    unsigned int n_threads = libMesh::n_threads();

    // Remove the restart files (rd)
    {
      for (THREAD_ID tid = 0; tid < n_threads; tid++)
      {
        std::ostringstream oss;
        oss << delete_files.restart << "-" << proc_id;
        if (n_threads > 1)
          oss << "-" << tid;
        std::string file_name = oss.str();
        int ret = remove(file_name.c_str());
        if (ret != 0)
          mooseWarning("Error during the deletion of file '", file_name, "': ", std::strerror(ret));
      }
    }
  }
}
<commit_msg>Cleanup the right mesh files<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// C POSIX includes
#include <sys/stat.h>

// Moose includes
#include "Checkpoint.h"
#include "FEProblem.h"
#include "MooseApp.h"
#include "MaterialPropertyStorage.h"
#include "RestartableData.h"
#include "MooseMesh.h"

#include "libmesh/checkpoint_io.h"
#include "libmesh/enum_xdr_mode.h"

template <>
InputParameters
validParams<Checkpoint>()
{
  // Get the parameters from the base classes
  InputParameters params = validParams<FileOutput>();

  // Typical checkpoint options
  params.addParam<unsigned int>("num_files", 2, "Number of the restart files to save");
  params.addParam<std::string>(
      "suffix",
      "cp",
      "This will be appended to the file_base to create the directory name for checkpoint files.");

  // Advanced settings
  params.addParam<bool>("binary", true, "Toggle the output of binary files");
  params.addParamNamesToGroup("binary", "Advanced");
  return params;
}

Checkpoint::Checkpoint(const InputParameters & parameters)
  : FileOutput(parameters),
    _num_files(getParam<unsigned int>("num_files")),
    _suffix(getParam<std::string>("suffix")),
    _binary(getParam<bool>("binary")),
    _parallel_mesh(_problem_ptr->mesh().isDistributedMesh()),
    _restartable_data(_app.getRestartableData()),
    _recoverable_data(_app.getRecoverableData()),
    _material_property_storage(_problem_ptr->getMaterialPropertyStorage()),
    _bnd_material_property_storage(_problem_ptr->getBndMaterialPropertyStorage()),
    _restartable_data_io(RestartableDataIO(*_problem_ptr))
{
}

std::string
Checkpoint::filename()
{
  // Get the time step with correct zero padding
  std::ostringstream output;
  output << directory() << "/" << std::setw(_padding) << std::setprecision(0) << std::setfill('0')
         << std::right << timeStep();
  return output.str();
}

std::string
Checkpoint::directory()
{
  return _file_base + "_" + _suffix;
}

void
Checkpoint::output(const ExecFlagType & /*type*/)
{
  // Start the performance log
  Moose::perf_log.push("Checkpoint::output()", "Output");

  // Create the output directory
  std::string cp_dir = directory();
  mkdir(cp_dir.c_str(), S_IRWXU | S_IRGRP);

  // Create the output filename
  std::string current_file = filename();

  // Create the libMesh Checkpoint_IO object
  MeshBase & mesh = _es_ptr->get_mesh();
  CheckpointIO io(mesh, _binary);

  // Set libHilbert renumbering flag to false.  We don't support
  // N-to-M restarts regardless, and if we're *never* going to do
  // N-to-M restarts then libHilbert is just unnecessary computation
  // and communication.
  const bool renumber = false;

  // Create checkpoint file structure
  CheckpointFileNames current_file_struct;
  if (_binary)
  {
    current_file_struct.checkpoint = current_file + "_mesh.cpr";
    current_file_struct.system = current_file + ".xdr";
  }
  else
  {
    current_file_struct.checkpoint = current_file + "_mesh.cpa";
    current_file_struct.system = current_file + ".xda";
  }
  current_file_struct.restart = current_file + ".rd";

  // Write the checkpoint file
  io.write(current_file_struct.checkpoint);

  // Write the system data, using ENCODE vs WRITE based on xdr vs xda
  _es_ptr->write(current_file_struct.system,
                 EquationSystems::WRITE_DATA | EquationSystems::WRITE_ADDITIONAL_DATA |
                     EquationSystems::WRITE_PARALLEL_FILES,
                 renumber);

  // Write the restartable data
  _restartable_data_io.writeRestartableData(
      current_file_struct.restart, _restartable_data, _recoverable_data);

  // Remove old checkpoint files
  updateCheckpointFiles(current_file_struct);

  // Stop the logging
  Moose::perf_log.pop("Checkpoint::output()", "Output");
}

void
Checkpoint::updateCheckpointFiles(CheckpointFileNames file_struct)
{
  // Update the list of stored files
  _file_names.push_back(file_struct);

  // Remove un-wanted files
  if (_file_names.size() > _num_files)
  {
    // Extract the filenames to be removed
    CheckpointFileNames delete_files = _file_names.front();

    // Remove these filenames from the list
    _file_names.pop_front();

    // Get thread and proc information
    processor_id_type proc_id = processor_id();

    // Delete checkpoint files (_mesh.cpr)
    if (proc_id == 0)
    {
      std::ostringstream oss;
      oss << delete_files.checkpoint;
      std::string file_name = oss.str();
      CheckpointIO::cleanup(file_name, _parallel_mesh ? comm().size() : 1);
    }

    // Delete the system files (xdr and xdr.0000, ...)
    if (proc_id == 0)
    {
      std::ostringstream oss;
      oss << delete_files.system;
      std::string file_name = oss.str();
      int ret = remove(file_name.c_str());
      if (ret != 0)
        mooseWarning("Error during the deletion of file '", file_name, "': ", std::strerror(ret));
    }

    {
      std::ostringstream oss;
      oss << delete_files.system << "." << std::setw(4) << std::setprecision(0) << std::setfill('0')
          << proc_id;
      std::string file_name = oss.str();
      int ret = remove(file_name.c_str());
      if (ret != 0)
        mooseWarning("Error during the deletion of file '", file_name, "': ", std::strerror(ret));
    }

    unsigned int n_threads = libMesh::n_threads();

    // Remove the restart files (rd)
    {
      for (THREAD_ID tid = 0; tid < n_threads; tid++)
      {
        std::ostringstream oss;
        oss << delete_files.restart << "-" << proc_id;
        if (n_threads > 1)
          oss << "-" << tid;
        std::string file_name = oss.str();
        int ret = remove(file_name.c_str());
        if (ret != 0)
          mooseWarning("Error during the deletion of file '", file_name, "': ", std::strerror(ret));
      }
    }
  }
}
<|endoftext|>


<commit_before>#include <cstdio>

#include <io/FilePointer.hpp>
#include <io/Inet4Address.hpp>
#include <io/Resolv.hpp>
#include <io/ServerSocket.hpp>
#include <io/Socket.hpp>
#include <io/StringWriter.hpp>
#include <io/binary/StreamGetter.hpp>

#include <json/Json.hpp>
#include <json/JsonMercuryTempl.hpp>

#include <log/LogManager.hpp>
#include <log/LogServer.hpp>

#include <mercury/Mercury.hpp>

#include <os/Condition.hpp>

#include <sys/wait.h>

#include <errno.h>
#include <signal.h>
#include <unistd.h>

using namespace logger ;
using namespace std ;
using namespace io ;
using namespace os ;
using namespace json ;

byte mercury_magic_cookie[32] = {
    0xe2, 0x1a, 0x14, 0xc8, 0xa2, 0x35, 0x0a, 0x92,
    0xaf, 0x1a, 0xff, 0xd6, 0x35, 0x2b, 0xa4, 0xf3,
    0x97, 0x79, 0xaf, 0xb5, 0xc1, 0x23, 0x43, 0xf0,
    0xf7, 0x14, 0x17, 0x62, 0x53, 0x4a, 0xa9, 0x7e,
};

Mutex* g_mutex;
Condition* g_cond;

class MercuryConfig {
public:
    MercuryConfig():
        logEverything(false),
        controller_url("http://127.0.0.1:5000/"),
        bind_ip(new Inet4Address("127.0.0.1", 8639)),
        log_out(NULL),
        colors(true),
        default_level(NULL),
        log_server(NULL)
        {}

    bool logEverything;
    std::string controller_url;
    SocketAddress* bind_ip;
    BaseIO* log_out;
    bool colors;
    LogLevel* default_level;

    SocketAddress* log_server;
};

template<>
struct JsonBasicConvert<MercuryConfig> {
    static MercuryConfig convert(const json::Json& jsn) {
        MercuryConfig ret;
        ret.logEverything = jsn.hasAttribute("logEverything") && jsn["logEverything"] != 0;
        SocketAddress* old;

        if(jsn.hasAttribute("controller_url")) {
            ret.controller_url = jsn["controller_url"].stringValue();
        }
        if(jsn.hasAttribute("bind_ip")) {
            old = ret.bind_ip;
            ret.bind_ip = jsn["bind_ip"].convert<SocketAddress*>();
            delete old;
        }

        if(jsn.hasAttribute("logFile")) {
            FILE* f = fopen(jsn["logFile"].stringValue().c_str(), "w");
            if(f) {
                io::FilePointer* fp = new io::FilePointer(f);
                ret.log_out = fp;
            } else {
                fprintf(stderr, "Unable to open log file. Logging to stdout\n");
            }
        }

        if(jsn.hasAttribute("defaultLogLevel")) {
            ret.default_level = LogLevel::getLogLevelByName(jsn["defaultLogLevel"].stringValue().c_str());
        }

        if(jsn.hasAttribute("logColors")) {
            ret.colors = jsn["logColors"] != 0;
        }

        if(jsn.hasAttribute("logServerBindAddress")) {
            ret.log_server = jsn["logServerBindAddress"].convert<SocketAddress*>();
            if(ret.log_server->linkProtocol() == AF_UNIX) {
                dynamic_cast<UnixAddress*>(ret.log_server)->unlink();
            }
        }

        return ret;
    }
};

void sigchld_hdlr(int sig) {
    ScopedLock __sl(*g_mutex);
    g_cond->signal();
}

void start_logging_service(int fd) {
    /* start a logging service which will read on
     * fd and wait for input */
    pid_t child;
    printf("Forking child\n");
    if(!(child = fork())) {
        LogContext::unlock();

        LogContext& log = LogManager::instance().getLogContext("Child", "StdErr");
        log.printfln(DEBUG, "Error logger started");
        FILE* f = fdopen(fd, "r");
        char read[1024];
        read[1023] = 0;
        while(true) {
            fgets(read, sizeof(read)-1, f);
            log.printfln(ERROR, read);
        }
    }

    if(child < 0) {
        perror("fork() failed");
    }
}

int startMercury(LogContext& m_log, MercuryConfig& config) {
    StreamServerSocket sock;
    SocketAddress* bind_addr = config.bind_ip;

    int error_pipe[2];
    if(pipe(error_pipe)) {
        perror("Error on pipe()\n");
        return 1;
    }
    dup2(error_pipe[1], STDERR_FILENO);

    /* Start the service that is only resposible for
     * logging the stderr of the this process and
     * its other children */
    start_logging_service(error_pipe[0]);

    m_log.printfln(INFO, "Binding to address: %s", bind_addr->toString().c_str());
    sock.bind(*bind_addr);
    sock.listen(1);

    while(true) {
        StreamSocket* client = sock.accept();
        m_log.printfln(INFO, "Connection accepted");

        /* simply get 64 bytes from the client and
         * then close the connection */
        byte recieve[64];
        client->read(recieve, sizeof(recieve));
        delete client;

        /* make sure the cookie is equal to what we expect */
        if(std::equal(recieve, recieve + 32, mercury_magic_cookie)) {
            /* the cookie is equal to what we expect
             * so continue with the fork() */
            m_log.printfln(INFO, "Magic cookie accepted, forking new process");
            pid_t child;

            if(!(child = fork())) {
                LogContext::unlock();

                /* report all stderr to the error pipe */
                fprintf(stderr, "Test stderr\n");
                fflush(stderr);
                /* Child process. Setup the config and boot
                 * the merucry state machine */
                mercury::Config conf;
                std::copy(recieve + 32, recieve + 64, conf.mercury_id);
                conf.controller_url = config.controller_url;
                mercury::Proxy& process = mercury::ProxyHolder::instance();

                /* start mercury */
                process.start(conf, NULL);
                process.waitForExit();

                exit(0);
            } else {

                /* parent */
                m_log.printfln(INFO, "Child started pid=%d", child);
                int res = 0;
                pid_t pid;

                /* Wait for the child to exit. this
                 * condition will be signaled by the
                 * sigchld handler */
                if(!g_cond->timedwait(*g_mutex, 300 SECS)) {
                    /* The child is taking too long to return
                     * kill it */
                    m_log.printfln(WARN, "Child timeout, sending SIGTERM");
                    kill(child, SIGTERM);
                    if(!g_cond->timedwait(*g_mutex, 10 SECS)) {
                        /* The child still isn't dead */
                        m_log.printfln(WARN, "Child hard timeout, sending SIGKILL");
                        kill(child, SIGKILL);
                    }
                }

                if((pid = waitpid(child, &res, WNOHANG))) {
                    if(pid == -1) {
                        m_log.printfln(ERROR, "Error in waitpid %s", strerror(errno));
                    } else {
                        m_log.printfln(INFO, "Reap child (%d)\n", (int)pid);
                    }
                }

                if(WIFSIGNALED(res)) {
                    m_log.printfln(WARN, "Child was signaled with %d", WTERMSIG(res));
                }

                if(WEXITSTATUS(res)) {
                    m_log.printfln(WARN, "Child returned abnormal status: %d", WEXITSTATUS(res));
                }

                if(WIFSTOPPED(res)) {
                    m_log.printfln(WARN, "Child timed out and was killed by parent");
                }
            }
        } else {
            m_log.printfln(ERROR, "Bad magic cookie received. Timeout for 5 seconds");
            sleep(5);
            m_log.printfln(INFO, "Timeout complete");
        }
    }

    return 0;
}

int main( int argc, char** argv ) {
    (void) argc ; (void) argv ;

    g_mutex = new Mutex();
    g_cond = new Condition();

    ScopedLock __sl(*g_mutex);

    MercuryConfig conf;
    SocketAddress* old = conf.bind_ip;
    signal(SIGCHLD, sigchld_hdlr);

    try {
        Json* jsn = Json::fromFile("config.json");
        conf = jsn->convert<MercuryConfig>();
        delete old;
    } catch(Exception& exp) {
        fprintf(stderr, "Unable to load config file: %s\n", exp.getMessage());
    };

    if(conf.log_out) {
        LogManager::instance().addLogOutput(conf.log_out, conf.colors);
    }

    if(conf.logEverything) {
        LogManager::instance().logEverything();
    }

    if(conf.default_level) {
        LogManager::instance().setDefaultLevel(*conf.default_level);
    }

    try {
        if(conf.log_server) {
            LogServer* log_server = new LogServer(*conf.log_server);
            Thread* __th = new Thread(*log_server);
            __th->start();
        }

        LogContext& m_log = LogManager::instance().getLogContext("Main", "Main");
        m_log.printfln(INFO, "Mercury started");
        return startMercury(m_log, conf);
    } catch(Exception& exp) {
        LogContext& m_log = LogManager::instance().getLogContext("Main", "Main");
        m_log.printfln(FATAL, "Uncaught exception: %s", exp.getMessage());
        return 127;
    }
}
<commit_msg>removed printf<commit_after>#include <cstdio>

#include <io/FilePointer.hpp>
#include <io/Inet4Address.hpp>
#include <io/Resolv.hpp>
#include <io/ServerSocket.hpp>
#include <io/Socket.hpp>
#include <io/StringWriter.hpp>
#include <io/binary/StreamGetter.hpp>

#include <json/Json.hpp>
#include <json/JsonMercuryTempl.hpp>

#include <log/LogManager.hpp>
#include <log/LogServer.hpp>

#include <mercury/Mercury.hpp>

#include <os/Condition.hpp>

#include <sys/wait.h>

#include <errno.h>
#include <signal.h>
#include <unistd.h>

using namespace logger ;
using namespace std ;
using namespace io ;
using namespace os ;
using namespace json ;

byte mercury_magic_cookie[32] = {
    0xe2, 0x1a, 0x14, 0xc8, 0xa2, 0x35, 0x0a, 0x92,
    0xaf, 0x1a, 0xff, 0xd6, 0x35, 0x2b, 0xa4, 0xf3,
    0x97, 0x79, 0xaf, 0xb5, 0xc1, 0x23, 0x43, 0xf0,
    0xf7, 0x14, 0x17, 0x62, 0x53, 0x4a, 0xa9, 0x7e,
};

Mutex* g_mutex;
Condition* g_cond;

class MercuryConfig {
public:
    MercuryConfig():
        logEverything(false),
        controller_url("http://127.0.0.1:5000/"),
        bind_ip(new Inet4Address("127.0.0.1", 8639)),
        log_out(NULL),
        colors(true),
        default_level(NULL),
        log_server(NULL)
        {}

    bool logEverything;
    std::string controller_url;
    SocketAddress* bind_ip;
    BaseIO* log_out;
    bool colors;
    LogLevel* default_level;

    SocketAddress* log_server;
};

template<>
struct JsonBasicConvert<MercuryConfig> {
    static MercuryConfig convert(const json::Json& jsn) {
        MercuryConfig ret;
        ret.logEverything = jsn.hasAttribute("logEverything") && jsn["logEverything"] != 0;
        SocketAddress* old;

        if(jsn.hasAttribute("controller_url")) {
            ret.controller_url = jsn["controller_url"].stringValue();
        }
        if(jsn.hasAttribute("bind_ip")) {
            old = ret.bind_ip;
            ret.bind_ip = jsn["bind_ip"].convert<SocketAddress*>();
            delete old;
        }

        if(jsn.hasAttribute("logFile")) {
            FILE* f = fopen(jsn["logFile"].stringValue().c_str(), "w");
            if(f) {
                io::FilePointer* fp = new io::FilePointer(f);
                ret.log_out = fp;
            } else {
                fprintf(stderr, "Unable to open log file. Logging to stdout\n");
            }
        }

        if(jsn.hasAttribute("defaultLogLevel")) {
            ret.default_level = LogLevel::getLogLevelByName(jsn["defaultLogLevel"].stringValue().c_str());
        }

        if(jsn.hasAttribute("logColors")) {
            ret.colors = jsn["logColors"] != 0;
        }

        if(jsn.hasAttribute("logServerBindAddress")) {
            ret.log_server = jsn["logServerBindAddress"].convert<SocketAddress*>();
            if(ret.log_server->linkProtocol() == AF_UNIX) {
                dynamic_cast<UnixAddress*>(ret.log_server)->unlink();
            }
        }

        return ret;
    }
};

void sigchld_hdlr(int sig) {
    ScopedLock __sl(*g_mutex);
    g_cond->signal();
}

void start_logging_service(int fd) {
    /* start a logging service which will read on
     * fd and wait for input */
    pid_t child;
    if(!(child = fork())) {
        LogContext::unlock();

        LogContext& log = LogManager::instance().getLogContext("Child", "StdErr");
        log.printfln(DEBUG, "Error logger started");
        FILE* f = fdopen(fd, "r");
        char read[1024];
        read[1023] = 0;
        while(true) {
            fgets(read, sizeof(read)-1, f);
            log.printfln(ERROR, read);
        }
    }

    if(child < 0) {
        perror("fork() failed");
    }
}

int startMercury(LogContext& m_log, MercuryConfig& config) {
    StreamServerSocket sock;
    SocketAddress* bind_addr = config.bind_ip;

    int error_pipe[2];
    if(pipe(error_pipe)) {
        perror("Error on pipe()\n");
        return 1;
    }

    /* Redirect stderr to the error_pipe. This will make it
     * so we can still see stderr messages in the log */
    dup2(error_pipe[1], STDERR_FILENO);

    /* Start the service that is only resposible for
     * logging the stderr of the this process and
     * its other children */
    start_logging_service(error_pipe[0]);

    m_log.printfln(INFO, "Binding to address: %s", bind_addr->toString().c_str());
    sock.bind(*bind_addr);
    sock.listen(1);

    while(true) {
        StreamSocket* client = sock.accept();
        m_log.printfln(INFO, "Connection accepted");

        /* simply get 64 bytes from the client and
         * then close the connection */
        byte recieve[64];
        client->read(recieve, sizeof(recieve));
        delete client;

        /* make sure the cookie is equal to what we expect */
        if(std::equal(recieve, recieve + 32, mercury_magic_cookie)) {
            /* the cookie is equal to what we expect
             * so continue with the fork() */
            m_log.printfln(INFO, "Magic cookie accepted, forking new process");
            pid_t child;

            if(!(child = fork())) {
                LogContext::unlock();

                /* report all stderr to the error pipe */
                fprintf(stderr, "Test stderr\n");
                fflush(stderr);
                /* Child process. Setup the config and boot
                 * the merucry state machine */
                mercury::Config conf;
                std::copy(recieve + 32, recieve + 64, conf.mercury_id);
                conf.controller_url = config.controller_url;
                mercury::Proxy& process = mercury::ProxyHolder::instance();

                /* start mercury */
                process.start(conf, NULL);
                process.waitForExit();

                exit(0);
            } else {

                /* parent */
                m_log.printfln(INFO, "Child started pid=%d", child);
                int res = 0;
                pid_t pid;

                /* Wait for the child to exit. this
                 * condition will be signaled by the
                 * sigchld handler */
                if(!g_cond->timedwait(*g_mutex, 300 SECS)) {
                    /* The child is taking too long to return
                     * kill it */
                    m_log.printfln(WARN, "Child timeout, sending SIGTERM");
                    kill(child, SIGTERM);
                    if(!g_cond->timedwait(*g_mutex, 10 SECS)) {
                        /* The child still isn't dead */
                        m_log.printfln(WARN, "Child hard timeout, sending SIGKILL");
                        kill(child, SIGKILL);
                    }
                }

                if((pid = waitpid(child, &res, WNOHANG))) {
                    if(pid == -1) {
                        m_log.printfln(ERROR, "Error in waitpid %s", strerror(errno));
                    } else {
                        m_log.printfln(INFO, "Reap child (%d)\n", (int)pid);
                    }
                }

                if(WIFSIGNALED(res)) {
                    m_log.printfln(WARN, "Child was signaled with %d", WTERMSIG(res));
                }

                if(WEXITSTATUS(res)) {
                    m_log.printfln(WARN, "Child returned abnormal status: %d", WEXITSTATUS(res));
                }

                if(WIFSTOPPED(res)) {
                    m_log.printfln(WARN, "Child timed out and was killed by parent");
                }
            }
        } else {
            m_log.printfln(ERROR, "Bad magic cookie received. Timeout for 5 seconds");
            sleep(5);
            m_log.printfln(INFO, "Timeout complete");
        }
    }

    return 0;
}

int main( int argc, char** argv ) {
    (void) argc ; (void) argv ;

    g_mutex = new Mutex();
    g_cond = new Condition();

    ScopedLock __sl(*g_mutex);

    MercuryConfig conf;
    SocketAddress* old = conf.bind_ip;
    signal(SIGCHLD, sigchld_hdlr);

    try {
        Json* jsn = Json::fromFile("config.json");
        conf = jsn->convert<MercuryConfig>();
        delete old;
    } catch(Exception& exp) {
        fprintf(stderr, "Unable to load config file: %s\n", exp.getMessage());
    };

    if(conf.log_out) {
        LogManager::instance().addLogOutput(conf.log_out, conf.colors);
    }

    if(conf.logEverything) {
        LogManager::instance().logEverything();
    }

    if(conf.default_level) {
        LogManager::instance().setDefaultLevel(*conf.default_level);
    }

    try {
        if(conf.log_server) {
            LogServer* log_server = new LogServer(*conf.log_server);
            Thread* __th = new Thread(*log_server);
            __th->start();
        }

        LogContext& m_log = LogManager::instance().getLogContext("Main", "Main");
        m_log.printfln(INFO, "Mercury started");
        return startMercury(m_log, conf);
    } catch(Exception& exp) {
        LogContext& m_log = LogManager::instance().getLogContext("Main", "Main");
        m_log.printfln(FATAL, "Uncaught exception: %s", exp.getMessage());
        return 127;
    }
}
<|endoftext|>


<commit_before>#ifndef HACK_HPP
#define HACK_HPP

#include <cstdint>
#include <string>
#include <unordered_map>

namespace Hasm {
namespace Hack {

using WORD = uint16_t;

const WORD INIT_RAM_ADDRESS{16};

const std::unordered_map<std::string, WORD> PREDEFINED_SYMBOLS{
    {"SP", 0x00},
    {"LCL", 0x01},
    {"ARG", 0x02},
    {"THIS", 0x03},
    {"THAT", 0x04},
    {"R0", 0x00},
    {"R1", 0x01},
    {"R2", 0x02},
    {"R3", 0x03},
    {"R4", 0x04},
    {"R5", 0x05},
    {"R6", 0x06},
    {"R7", 0x07},
    {"R8", 0x08},
    {"R9", 0x09},
    {"R10", 0x10},
    {"R11", 0x11},
    {"R12", 0x12},
    {"R13", 0x13},
    {"R14", 0x14},
    {"R15", 0x15},
    {"SCREEN", 0x4000},
    {"KBD", 0x6000}
};

} // namespace Hack
} // namespace Hasm

#endif<commit_msg>Fix symbol values<commit_after>#ifndef HASM_HACK_HPP
#define HASM_HACK_HPP

#include <cstdint>
#include <string>
#include <unordered_map>

namespace Hasm {
namespace Hack {

using WORD = uint16_t;

const WORD INIT_RAM_ADDRESS{16};

const std::unordered_map<std::string, WORD> PREDEFINED_SYMBOLS{
    {"SP", 0x0},
    {"LCL", 0x1},
    {"ARG", 0x2},
    {"THIS", 0x3},
    {"THAT", 0x4},
    {"R0", 0x0},
    {"R1", 0x1},
    {"R2", 0x2},
    {"R3", 0x3},
    {"R4", 0x4},
    {"R5", 0x5},
    {"R6", 0x6},
    {"R7", 0x7},
    {"R8", 0x8},
    {"R9", 0x9},
    {"R10", 0xA},
    {"R11", 0xB},
    {"R12", 0xC},
    {"R13", 0xD},
    {"R14", 0xE},
    {"R15", 0xF},
    {"SCREEN", 0x4000},
    {"KBD", 0x6000}
};

} // namespace Hack
} // namespace Hasm

#endif<|endoftext|>


<commit_before>#ifndef UTIL_HPP
#define UTIL_HPP

#include <vector>
#include <iterator>
#include <cstddef>
#include <boost/dynamic_bitset.hpp>
#include <iostream>

namespace rmatch {
    /*!
        given two bit vectors \a lowBits and \a topBits it finds the
        bits for which we have ones only in either one of them
        It returns the positions of those bits.
    */
    template <typename output_container>
    void retrieveRangeIndices(
            const boost::dynamic_bitset<> & lowbits,
            const boost::dynamic_bitset<> & topbits,
            output_container& positions)
    {
        /*
            we have the bitsets for the lower and the upper bound
            obviously the lower bound is a subset of the upper bound
            namely if we have 1 for some index in the lower bound, the we have it in the upper bound
            we have to set those bits to 0
            we just have to do an XOR
        */
        const boost::dynamic_bitset<> XOR = lowbits ^ topbits;

        /*
            we have the bits now 1 where the suffix is in the given bound
            we have to search for them.
            XOR.count() gives the count of the bits where we have 1
        */
        positions.reserve(XOR.count());

        size_t i = XOR.find_first();

        /*
            find the next bit's position and store the index
            note that if one decides to stop using the bitset and use multiple memory blocks to work with
            the best way to find the next bit set is to use the expression
            (val & -val) which is equivalen to (val & (~val + 1)) due to 2-complement of how integers are stored in memory
        */
        while (i != XOR.npos)
        {
            positions.push_back(i);
            i = XOR.find_next(i);
        }
    }

    inline std::vector<size_t> retrieveRangeIndices(
            const boost::dynamic_bitset<> & lowbits,
            const boost::dynamic_bitset<> & topbits)
    {
        std::vector<size_t> positions;
        retrieveRangeIndices(lowbits,topbits,positions);
        return std::move(positions);
    }
}

#endif // UTIL_HPP
<commit_msg>Fix u < l in util<commit_after>#ifndef UTIL_HPP
#define UTIL_HPP

#include <vector>
#include <iterator>
#include <cstddef>
#include <boost/dynamic_bitset.hpp>
#include <iostream>

namespace rmatch {
    /*!
        given two bit vectors \a lowBits and \a topBits it finds the
        bits for which we have ones only in either one of them
        It returns the positions of those bits.
    */
    template <typename output_container>
    void retrieveRangeIndices(
            const boost::dynamic_bitset<> & lowbits,
            const boost::dynamic_bitset<> & topbits,
            output_container& positions)
    {
        /*
            we have the bitsets for the lower and the upper bound
            obviously the lower bound is a subset of the upper bound
            namely if we have 1 for some index in the lower bound, the we have it in the upper bound
            we have to set those bits to 0
            we just have to do an XOR
        */
        const boost::dynamic_bitset<> XOR = topbits - lowbits;

        /*
            we have the bits now 1 where the suffix is in the given bound
            we have to search for them.
            XOR.count() gives the count of the bits where we have 1
        */
        positions.reserve(XOR.count());

        size_t i = XOR.find_first();

        /*
            find the next bit's position and store the index
            note that if one decides to stop using the bitset and use multiple memory blocks to work with
            the best way to find the next bit set is to use the expression
            (val & -val) which is equivalen to (val & (~val + 1)) due to 2-complement of how integers are stored in memory
        */
        while (i != XOR.npos)
        {
            positions.push_back(i);
            i = XOR.find_next(i);
        }
    }

    inline std::vector<size_t> retrieveRangeIndices(
            const boost::dynamic_bitset<> & lowbits,
            const boost::dynamic_bitset<> & topbits)
    {
        std::vector<size_t> positions;
        retrieveRangeIndices(lowbits,topbits,positions);
        return std::move(positions);
    }
}

#endif // UTIL_HPP
<|endoftext|>


<commit_before>// XXX This compiles, but is completely untested

#pragma once

#include "bitset.hh"
#include "cpu.hh"
#include "spinlock.hh"
#include "percpu.hh"

#include <atomic>
#include <cstdint>
#include <utility>
#include <vector>

// OpLog is a technique for scaling objects that are frequently
// written and rarely read.  It works by logging modification
// operations to per-CPU logs and only applying these modification
// operations when a read needs to observe the object's state.
namespace oplog {
  enum {
    CACHE_SLOTS = 4096
  };

  // A base class for objects whose modification operations are logged
  // and synchronized to the object's state only when the state needs
  // to be observed.
  //
  // Classes wishing to apply OpLog should implement a "logger class"
  // and subclass @c logged_object.  Methods that modify the object's
  // state should call @c get_logger to get an instance of the logger
  // class and should call a method of the logger class to log the
  // operation.  Methods that read the object's state should call @c
  // synchronize to apply all outstanding logged operations before
  // they observe the object's state.
  //
  // @c logged_object takes care of making this memory-efficient:
  // rather than simply keeping per-CPU logs for every object, it
  // maintains a fixed size cache of logs per CPU so that only
  // recently modified objects are likely to have logs.
  //
  // @tparam Logger A class that logs operations to be applied to the
  // object later.  This is the type returned by get_logger.  There
  // may be many Logger instances created per logged_object.  Logger
  // must have a default constructor, but there are no other
  // requirements.
  template<typename Logger>
  class logged_object
  {
  public:
    constexpr logged_object() : sync_lock_("logged_object") { }

    // A Logger instance protected by a lock.  Users of this class
    // should not attempt to hold a reference to the protected logger
    // longer than the locked_logger object remains live.
    class locked_logger
    {
      lock_guard<spinlock> lock_;
      Logger *logger_;

      locked_logger(lock_guard<spinlock> &&lock, Logger *logger)
        : lock_(std::move(lock)), logger_(logger) { }

    public:
      locked_logger(locked_logger &&o)
        : lock_(std::move(o.lock_)), logger_(o.logger_)
      {
        o.logger_ = nullptr;
      }

      locked_logger &operator=(locked_logger &&o)
      {
        lock_ = std::move(o.lock_);
        logger_ = o.logger_;
        o.logger_ = nullptr;
      }

      // Return the protected Logger instance.  Note that there is no
      // operator*, since that would encourage decoupling the life
      // time of the locked_logger from the lifetime of the Logger*.
      Logger *operator->() const
      {
        return logger_;
      }
    };

  protected:
    // Return a locked operation logger for this object.  In general,
    // this logger will be CPU-local, meaning that operations from
    // different cores can be performed in parallel and without
    // communication.
    locked_logger get_logger()
    {
      auto id = myid();
      auto my_way = cache_[id].hash_way(this);
    back_out:
      auto guard = my_way->lock_.guard();
      auto cur_obj = my_way->obj_.load(std::memory_order_relaxed);

      if (cur_obj != this) {
        if (cur_obj) {
          // Evict this logger.  In the unlikely event of a race
          // between this and synchronize, we may deadlock here if we
          // simply acquire cur_obj's sync lock.  Hence, we perform
          // deadlock avoidance.
          auto sync_guard = cur_obj->sync_lock_.try_guard();
          if (!sync_guard)
            // We would deadlock with synchronize.  Back out
            goto back_out;
          // XXX Since we don't do a full synchronize here, we lose
          // some of the potential memory overhead benefits of the
          // logger cache for ordered loggers like tsc_logged_object.
          // These have to keep around all operations anyway until
          // someone calls synchronize.  We could keep track of this
          // object in the locked_logger and call synchronize when it
          // gets released.
          cur_obj->flush_logger(&my_way->logger_);
          cur_obj->cpus_.atomic_reset(id);
        }
        // Put this object in this way's tag
        my_way->obj_.store(this, std::memory_order_relaxed);
        cpus_.atomic_set(id);
      }

      return locked_logger(std::move(guard), &my_way->logger_);
    }

    // Acquire a per-object lock, apply all logged operations to this
    // object, and return the per-object lock.  The caller may keep
    // this lock live for as long as it needs to prevent modifications
    // to the object's synchronized value.
    lock_guard<spinlock> synchronize()
    {
      auto guard = sync_lock_.guard();

      // Repeatedly gather loggers until we see that the CPU set is
      // empty.  We can't check the whole CPU set atomically, but
      // that's okay.  Since we hold the sync lock, only we can clear
      // bits in the CPU set, so while operations may happen between
      // when we observe that CPU 0 is not in the set and when we
      // observe that CPU n is not in the set, *if* we observe that
      // all of the bits are zero, *then* we had a consistent snapshot
      // as of when we observed that CPU 0's bit was zero.
      while (1) {
        bool any = false;
        // Gather loggers
        for (auto cpu : cpus_) {
          // XXX Is the optimizer smart enough to lift the hash
          // computation?
          auto way = cache_[cpu].hash_way(this);
          auto way_guard = way->lock_.guard();
          auto cur_obj = way->obj_.load(std::memory_order_relaxed);
          assert(cur_obj == this);
          flush_logger(way->logger_);
          cpus_.atomic_reset(cpu);
          any = true;
        }
        if (!any)
          break;
        // Make sure we see concurrent updates to cpus_.
        barrier();
      }

      // Tell the logged object that it has a consistent set of
      // loggers and should do any final flushing.
      flush_finish();

      return std::move(guard);
    }

    // Flush one logger, resetting it to its initial state.  This may
    // update the object's state, but is not required to (for some
    // loggers, this may be impossible when there are other loggers
    // still cached).  This is called with a locks that prevent
    // concurrent flush_* calls and that prevent l from being returned
    // by get_logger.
    virtual void flush_logger(Logger *l) = 0;

    // Perform final synchronization of the object's state.  This is
    // called by synchronize after it has flushed a consistent
    // snapshot of loggers for this object.  This is called with locks
    // that prevents concurrent flush_* calls.
    virtual void flush_finish() = 0;

  private:
    struct way
    {
      std::atomic<logged_object*> obj_;
      spinlock lock_;
      Logger logger_;
    };

    struct cache
    {
      way ways_[CACHE_SLOTS];

      way *hash_way(logged_object *obj) const
      {
        // Hash based on Java's HashMap re-hashing function.
        uint64_t wayno = (uintptr_t)obj;
        wayno ^= (wayno >> 32) ^ (wayno >> 20) ^ (wayno >> 12);
        wayno ^= (wayno >> 7) ^ (wayno >> 4);
        wayno %= CACHE_SLOTS;
        return &ways_[wayno];
      }
    };

    // Per-type, per-CPU, per-object logger.  The per-CPU part of this
    // is unprotected because we lock internally.
    static percpu<cache, NO_CRITICAL> cache_;

    // Bitmask of CPUs that have logged operations for this object.
    // Bits can be set without any lock, but can only be cleared when
    // holding sync_lock_.
    bitset<NCPU> cpus_;

    // This lock serializes log flushes and protects clearing cpus_.
    spinlock sync_lock_;
  };

  // The logger class used by tsc_logged_object.
  class tsc_logger
  {
    class op
    {
    public:
      const uint64_t tsc;
      op(uint64_t tsc) : tsc(tsc) { }
      virtual void run() = 0;
    };

    template<class CB>
    class op_inst : public op
    {
      CB cb_;
    public:
      op_inst(uint64_t tsc, CB &&cb) : op(tsc), cb_(cb) { }
      void run() override
      {
        cb_();
      }
    };

    // Logged operations in TSC order
    std::vector<op*> ops_;

    static uint64_t rdtscp()
    {
      uint64_t a, d, c;
      __asm __volatile("rdtscp" : "=a" (a), "=d" (d), "=c" (c));
      return a | (d << 32);
    }

    void reset()
    {
      ops_.clear();
    }

    friend class tsc_logged_object;

  public:
    // Log the operation cb, which must be a callable.  cb will be
    // called with no arguments when the logs need to be
    // synchronized.
    template<typename CB>
    void push(CB &&cb)
    {
      // We use rdtscp because all instructions before it must
      // retire before it reads the time stamp, which means we must
      // get a time stamp after the lock acquisition in get_logger.
      // rdtscp does not prevent later instructions from issuing
      // before it, but that's okay up to the lock release.  The
      // lock release will not move before the TSC read because we
      // have to write the value of the TSC to memory, which
      // introduces a data dependency from the rdtscp to this write,
      // and the lock release also writes to memory, which
      // introduces a TSO dependency from the TSC memory write to
      // the lock release.
      ops_.push_back(new op_inst<CB>(rdtscp(), std::forward<CB>(cb)));
    }
  };

  // A logger that applies operations in global timestamp order using
  // synchronized TSCs.
  class tsc_logged_object : public logged_object<tsc_logger>
  {
    std::vector<tsc_logger> pending_;

    void flush_logger(tsc_logger *l) override
    {
      pending_.emplace_back(std::move(*l));
      l->reset();
    }

    // XXX Not implemented.  This should heap-merge all of the loggers
    // in pending_ and apply their operations in order.
    void flush_finish() override;
  };

  // Problems with paper API:
  // * Synchronize calls apply on each Queue object.  Where do ordered
  //   queues actually get merged?
  // * Supposedly it flushes long queues, but there's nowhere in the
  //   supposed API where that can happen.  Object::queue doesn't know
  //   the length of the queue and Queue::push can't do the right
  //   locking.
  // * Baking "Op" into the API is awkward for type-specific oplogs.
  // * Evicting a queue on hash collision is actually really
  //   complicated.  The paper says you synchronize the whole object,
  //   but the requires locking the other queues for that object,
  //   which is either racy or deadlock-prone.  For many queue types,
  //   it's perfectly reasonable to flush a single queue.  Even for
  //   queue types that require a global synchronization (e.g., to
  //   merge ordered queues), you can always flush the queue back to a
  //   per-object queue, and only apply that on sync.
  // * Queue types have no convenient way to record per-object state
  //   (e.g., evicted but unapplied operations).
  // * Type-specific Queue types don't automatically have access to
  //   the type's private fields, which is probably what they need to
  //   modify.
  // * (Not really a problem, per se) The paper frames OpLog as the
  //   TSC-ordered approach that can then be optimized for specific
  //   types.  I think this makes the API awkward, since the API is
  //   aimed at the TSC-ordered queue, rather than type-specific
  //   queues.  Another way to look at it is that OpLog handles the
  //   mechanics of per-core queues, queue caching, and
  //   synchronization and that the user can plug in any queue type by
  //   implementing a simple interface.  The TSC-ordered queue is then
  //   simply a very general queue type that the user may choose to
  //   plug in.
};
<commit_msg>oplog: Give logged_object a virtual destructor<commit_after>// XXX This compiles, but is completely untested

#pragma once

#include "bitset.hh"
#include "cpu.hh"
#include "spinlock.hh"
#include "percpu.hh"

#include <atomic>
#include <cstdint>
#include <utility>
#include <vector>

// OpLog is a technique for scaling objects that are frequently
// written and rarely read.  It works by logging modification
// operations to per-CPU logs and only applying these modification
// operations when a read needs to observe the object's state.
namespace oplog {
  enum {
    CACHE_SLOTS = 4096
  };

  // A base class for objects whose modification operations are logged
  // and synchronized to the object's state only when the state needs
  // to be observed.
  //
  // Classes wishing to apply OpLog should implement a "logger class"
  // and subclass @c logged_object.  Methods that modify the object's
  // state should call @c get_logger to get an instance of the logger
  // class and should call a method of the logger class to log the
  // operation.  Methods that read the object's state should call @c
  // synchronize to apply all outstanding logged operations before
  // they observe the object's state.
  //
  // @c logged_object takes care of making this memory-efficient:
  // rather than simply keeping per-CPU logs for every object, it
  // maintains a fixed size cache of logs per CPU so that only
  // recently modified objects are likely to have logs.
  //
  // @tparam Logger A class that logs operations to be applied to the
  // object later.  This is the type returned by get_logger.  There
  // may be many Logger instances created per logged_object.  Logger
  // must have a default constructor, but there are no other
  // requirements.
  template<typename Logger>
  class logged_object
  {
  public:
    constexpr logged_object() : sync_lock_("logged_object") { }

    // logged_object is meant to be subclassed, so it needs a virtual
    // destructor.
    virtual ~logged_object() { }

    // A Logger instance protected by a lock.  Users of this class
    // should not attempt to hold a reference to the protected logger
    // longer than the locked_logger object remains live.
    class locked_logger
    {
      lock_guard<spinlock> lock_;
      Logger *logger_;

      locked_logger(lock_guard<spinlock> &&lock, Logger *logger)
        : lock_(std::move(lock)), logger_(logger) { }

    public:
      locked_logger(locked_logger &&o)
        : lock_(std::move(o.lock_)), logger_(o.logger_)
      {
        o.logger_ = nullptr;
      }

      locked_logger &operator=(locked_logger &&o)
      {
        lock_ = std::move(o.lock_);
        logger_ = o.logger_;
        o.logger_ = nullptr;
      }

      // Return the protected Logger instance.  Note that there is no
      // operator*, since that would encourage decoupling the life
      // time of the locked_logger from the lifetime of the Logger*.
      Logger *operator->() const
      {
        return logger_;
      }
    };

  protected:
    // Return a locked operation logger for this object.  In general,
    // this logger will be CPU-local, meaning that operations from
    // different cores can be performed in parallel and without
    // communication.
    locked_logger get_logger()
    {
      auto id = myid();
      auto my_way = cache_[id].hash_way(this);
    back_out:
      auto guard = my_way->lock_.guard();
      auto cur_obj = my_way->obj_.load(std::memory_order_relaxed);

      if (cur_obj != this) {
        if (cur_obj) {
          // Evict this logger.  In the unlikely event of a race
          // between this and synchronize, we may deadlock here if we
          // simply acquire cur_obj's sync lock.  Hence, we perform
          // deadlock avoidance.
          auto sync_guard = cur_obj->sync_lock_.try_guard();
          if (!sync_guard)
            // We would deadlock with synchronize.  Back out
            goto back_out;
          // XXX Since we don't do a full synchronize here, we lose
          // some of the potential memory overhead benefits of the
          // logger cache for ordered loggers like tsc_logged_object.
          // These have to keep around all operations anyway until
          // someone calls synchronize.  We could keep track of this
          // object in the locked_logger and call synchronize when it
          // gets released.
          cur_obj->flush_logger(&my_way->logger_);
          cur_obj->cpus_.atomic_reset(id);
        }
        // Put this object in this way's tag
        my_way->obj_.store(this, std::memory_order_relaxed);
        cpus_.atomic_set(id);
      }

      return locked_logger(std::move(guard), &my_way->logger_);
    }

    // Acquire a per-object lock, apply all logged operations to this
    // object, and return the per-object lock.  The caller may keep
    // this lock live for as long as it needs to prevent modifications
    // to the object's synchronized value.
    lock_guard<spinlock> synchronize()
    {
      auto guard = sync_lock_.guard();

      // Repeatedly gather loggers until we see that the CPU set is
      // empty.  We can't check the whole CPU set atomically, but
      // that's okay.  Since we hold the sync lock, only we can clear
      // bits in the CPU set, so while operations may happen between
      // when we observe that CPU 0 is not in the set and when we
      // observe that CPU n is not in the set, *if* we observe that
      // all of the bits are zero, *then* we had a consistent snapshot
      // as of when we observed that CPU 0's bit was zero.
      while (1) {
        bool any = false;
        // Gather loggers
        for (auto cpu : cpus_) {
          // XXX Is the optimizer smart enough to lift the hash
          // computation?
          auto way = cache_[cpu].hash_way(this);
          auto way_guard = way->lock_.guard();
          auto cur_obj = way->obj_.load(std::memory_order_relaxed);
          assert(cur_obj == this);
          flush_logger(way->logger_);
          cpus_.atomic_reset(cpu);
          any = true;
        }
        if (!any)
          break;
        // Make sure we see concurrent updates to cpus_.
        barrier();
      }

      // Tell the logged object that it has a consistent set of
      // loggers and should do any final flushing.
      flush_finish();

      return std::move(guard);
    }

    // Flush one logger, resetting it to its initial state.  This may
    // update the object's state, but is not required to (for some
    // loggers, this may be impossible when there are other loggers
    // still cached).  This is called with a locks that prevent
    // concurrent flush_* calls and that prevent l from being returned
    // by get_logger.
    virtual void flush_logger(Logger *l) = 0;

    // Perform final synchronization of the object's state.  This is
    // called by synchronize after it has flushed a consistent
    // snapshot of loggers for this object.  This is called with locks
    // that prevents concurrent flush_* calls.
    virtual void flush_finish() = 0;

  private:
    struct way
    {
      std::atomic<logged_object*> obj_;
      spinlock lock_;
      Logger logger_;
    };

    struct cache
    {
      way ways_[CACHE_SLOTS];

      way *hash_way(logged_object *obj) const
      {
        // Hash based on Java's HashMap re-hashing function.
        uint64_t wayno = (uintptr_t)obj;
        wayno ^= (wayno >> 32) ^ (wayno >> 20) ^ (wayno >> 12);
        wayno ^= (wayno >> 7) ^ (wayno >> 4);
        wayno %= CACHE_SLOTS;
        return &ways_[wayno];
      }
    };

    // Per-type, per-CPU, per-object logger.  The per-CPU part of this
    // is unprotected because we lock internally.
    static percpu<cache, NO_CRITICAL> cache_;

    // Bitmask of CPUs that have logged operations for this object.
    // Bits can be set without any lock, but can only be cleared when
    // holding sync_lock_.
    bitset<NCPU> cpus_;

    // This lock serializes log flushes and protects clearing cpus_.
    spinlock sync_lock_;
  };

  // The logger class used by tsc_logged_object.
  class tsc_logger
  {
    class op
    {
    public:
      const uint64_t tsc;
      op(uint64_t tsc) : tsc(tsc) { }
      virtual void run() = 0;
    };

    template<class CB>
    class op_inst : public op
    {
      CB cb_;
    public:
      op_inst(uint64_t tsc, CB &&cb) : op(tsc), cb_(cb) { }
      void run() override
      {
        cb_();
      }
    };

    // Logged operations in TSC order
    std::vector<op*> ops_;

    static uint64_t rdtscp()
    {
      uint64_t a, d, c;
      __asm __volatile("rdtscp" : "=a" (a), "=d" (d), "=c" (c));
      return a | (d << 32);
    }

    void reset()
    {
      ops_.clear();
    }

    friend class tsc_logged_object;

  public:
    // Log the operation cb, which must be a callable.  cb will be
    // called with no arguments when the logs need to be
    // synchronized.
    template<typename CB>
    void push(CB &&cb)
    {
      // We use rdtscp because all instructions before it must
      // retire before it reads the time stamp, which means we must
      // get a time stamp after the lock acquisition in get_logger.
      // rdtscp does not prevent later instructions from issuing
      // before it, but that's okay up to the lock release.  The
      // lock release will not move before the TSC read because we
      // have to write the value of the TSC to memory, which
      // introduces a data dependency from the rdtscp to this write,
      // and the lock release also writes to memory, which
      // introduces a TSO dependency from the TSC memory write to
      // the lock release.
      ops_.push_back(new op_inst<CB>(rdtscp(), std::forward<CB>(cb)));
    }
  };

  // A logger that applies operations in global timestamp order using
  // synchronized TSCs.
  class tsc_logged_object : public logged_object<tsc_logger>
  {
    std::vector<tsc_logger> pending_;

    void flush_logger(tsc_logger *l) override
    {
      pending_.emplace_back(std::move(*l));
      l->reset();
    }

    // XXX Not implemented.  This should heap-merge all of the loggers
    // in pending_ and apply their operations in order.
    void flush_finish() override;
  };

  // Problems with paper API:
  // * Synchronize calls apply on each Queue object.  Where do ordered
  //   queues actually get merged?
  // * Supposedly it flushes long queues, but there's nowhere in the
  //   supposed API where that can happen.  Object::queue doesn't know
  //   the length of the queue and Queue::push can't do the right
  //   locking.
  // * Baking "Op" into the API is awkward for type-specific oplogs.
  // * Evicting a queue on hash collision is actually really
  //   complicated.  The paper says you synchronize the whole object,
  //   but the requires locking the other queues for that object,
  //   which is either racy or deadlock-prone.  For many queue types,
  //   it's perfectly reasonable to flush a single queue.  Even for
  //   queue types that require a global synchronization (e.g., to
  //   merge ordered queues), you can always flush the queue back to a
  //   per-object queue, and only apply that on sync.
  // * Queue types have no convenient way to record per-object state
  //   (e.g., evicted but unapplied operations).
  // * Type-specific Queue types don't automatically have access to
  //   the type's private fields, which is probably what they need to
  //   modify.
  // * (Not really a problem, per se) The paper frames OpLog as the
  //   TSC-ordered approach that can then be optimized for specific
  //   types.  I think this makes the API awkward, since the API is
  //   aimed at the TSC-ordered queue, rather than type-specific
  //   queues.  Another way to look at it is that OpLog handles the
  //   mechanics of per-core queues, queue caching, and
  //   synchronization and that the user can plug in any queue type by
  //   implementing a simple interface.  The TSC-ordered queue is then
  //   simply a very general queue type that the user may choose to
  //   plug in.
};
<|endoftext|>


<commit_before><commit_msg>Create pablo9696.cpp<commit_after><|endoftext|>


<commit_before><commit_msg>MainGame.cpp 누락된 것 추가<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_MACAB_PREPAREDSTATEMENT_HXX_
#define _CONNECTIVITY_MACAB_PREPAREDSTATEMENT_HXX_

#include "MacabStatement.hxx"
#include "MacabResultSetMetaData.hxx"
#include <connectivity/FValue.hxx>
#include <com/sun/star/sdbc/XParameters.hpp>
#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
#include <cppuhelper/implbase4.hxx>

namespace connectivity
{
    namespace macab
    {

        class OBoundParam;
        typedef ::cppu::ImplInheritanceHelper4< MacabCommonStatement,
                                                ::com::sun::star::sdbc::XPreparedStatement,
                                                ::com::sun::star::sdbc::XParameters,
                                                ::com::sun::star::sdbc::XResultSetMetaDataSupplier,
                                                ::com::sun::star::lang::XServiceInfo> MacabPreparedStatement_BASE;

        class MacabPreparedStatement : public  MacabPreparedStatement_BASE
        {
        protected:
            ::rtl::OUString                 m_sSqlStatement;
            ::rtl::Reference< MacabResultSetMetaData >
                                            m_xMetaData;
            sal_Bool                        m_bPrepared;
            mutable sal_Int32                   m_nParameterIndex;
            OValueRow                       m_aParameterRow;

            void checkAndResizeParameters(sal_Int32 nParams) throw(::com::sun::star::sdbc::SQLException);
            void setMacabFields() const throw(::com::sun::star::sdbc::SQLException);

        protected:
            virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
                    sal_Int32 nHandle,
                    const ::com::sun::star::uno::Any& rValue) throw (::com::sun::star::uno::Exception);

            virtual void resetParameters() const throw(::com::sun::star::sdbc::SQLException);
            virtual void getNextParameter(::rtl::OUString &rParameter) const throw(::com::sun::star::sdbc::SQLException);
            virtual ~MacabPreparedStatement();

        public:
            DECLARE_SERVICE_INFO();
            MacabPreparedStatement(MacabConnection* _pConnection, const ::rtl::OUString& sql);

            // OComponentHelper
            virtual void SAL_CALL disposing();

            // XPreparedStatement
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet > SAL_CALL executeQuery(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual sal_Int32 SAL_CALL executeUpdate(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual sal_Bool SAL_CALL execute(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL getConnection(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            // XParameters
            virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const ::rtl::OUString& typeName ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setString( sal_Int32 parameterIndex, const ::rtl::OUString& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const ::com::sun::star::uno::Sequence< sal_Int8 >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const ::com::sun::star::util::Date& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const ::com::sun::star::util::Time& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const ::com::sun::star::util::DateTime& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const ::com::sun::star::uno::Any& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const ::com::sun::star::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRef >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XBlob >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XClob >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XArray >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL clearParameters(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            // XCloseable
            virtual void SAL_CALL close(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            // XResultSetMetaDataSupplier
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSetMetaData > SAL_CALL getMetaData(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
        };
    }
}

#endif // _CONNECTIVITY_MACAB_PREPAREDSTATEMENT_HXX_

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>WaE: make the overloaded-virtual mess here just a warning even with -Werror<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_MACAB_PREPAREDSTATEMENT_HXX_
#define _CONNECTIVITY_MACAB_PREPAREDSTATEMENT_HXX_

#include "MacabStatement.hxx"
#include "MacabResultSetMetaData.hxx"
#include <connectivity/FValue.hxx>
#include <com/sun/star/sdbc/XParameters.hpp>
#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
#include <cppuhelper/implbase4.hxx>

#ifdef __clang__
#pragma clang diagnostic warning "-Woverloaded-virtual"
#endif

namespace connectivity
{
    namespace macab
    {

        class OBoundParam;
        typedef ::cppu::ImplInheritanceHelper4< MacabCommonStatement,
                                                ::com::sun::star::sdbc::XPreparedStatement,
                                                ::com::sun::star::sdbc::XParameters,
                                                ::com::sun::star::sdbc::XResultSetMetaDataSupplier,
                                                ::com::sun::star::lang::XServiceInfo> MacabPreparedStatement_BASE;

        class MacabPreparedStatement : public  MacabPreparedStatement_BASE
        {
        protected:
            ::rtl::OUString                 m_sSqlStatement;
            ::rtl::Reference< MacabResultSetMetaData >
                                            m_xMetaData;
            sal_Bool                        m_bPrepared;
            mutable sal_Int32                   m_nParameterIndex;
            OValueRow                       m_aParameterRow;

            void checkAndResizeParameters(sal_Int32 nParams) throw(::com::sun::star::sdbc::SQLException);
            void setMacabFields() const throw(::com::sun::star::sdbc::SQLException);

        protected:
            virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
                    sal_Int32 nHandle,
                    const ::com::sun::star::uno::Any& rValue) throw (::com::sun::star::uno::Exception);

            virtual void resetParameters() const throw(::com::sun::star::sdbc::SQLException);
            virtual void getNextParameter(::rtl::OUString &rParameter) const throw(::com::sun::star::sdbc::SQLException);
            virtual ~MacabPreparedStatement();

        public:
            DECLARE_SERVICE_INFO();
            MacabPreparedStatement(MacabConnection* _pConnection, const ::rtl::OUString& sql);

            // OComponentHelper
            virtual void SAL_CALL disposing();

            // XPreparedStatement
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet > SAL_CALL executeQuery(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual sal_Int32 SAL_CALL executeUpdate(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual sal_Bool SAL_CALL execute(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection > SAL_CALL getConnection(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            // XParameters
            virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const ::rtl::OUString& typeName ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setString( sal_Int32 parameterIndex, const ::rtl::OUString& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const ::com::sun::star::uno::Sequence< sal_Int8 >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const ::com::sun::star::util::Date& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const ::com::sun::star::util::Time& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const ::com::sun::star::util::DateTime& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const ::com::sun::star::uno::Any& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const ::com::sun::star::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRef >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XBlob >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XClob >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XArray >& x ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL clearParameters(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            // XCloseable
            virtual void SAL_CALL close(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            // XResultSetMetaDataSupplier
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSetMetaData > SAL_CALL getMetaData(  ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
        };
    }
}

#endif // _CONNECTIVITY_MACAB_PREPAREDSTATEMENT_HXX_

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>