<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library 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 for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef JUBATUS_CORE_COMMON_EXCEPTION_HPP_
#define JUBATUS_CORE_COMMON_EXCEPTION_HPP_

#include <exception>
#include <stdexcept>
#include <ios>
#include <sstream>
#include <string>
#include <vector>

#include <pficommon/lang/shared_ptr.h>
#include <pficommon/lang/demangle.h>
#include "exception_info.hpp"

namespace jubatus {
namespace core {
namespace common {
namespace exception {

typedef error_info<struct error_at_file_, std::string> error_at_file;
typedef error_info<struct error_at_func_, std::string> error_at_func;
typedef error_info<struct error_at_line_, int> error_at_line;
typedef error_info<struct error_errno_, int> error_errno;
inline std::string to_string(const error_errno& info) {
  char buf[256];
  std::string msg(strerror_r(info.value(), buf, 256));
  msg += " (" + pfi::lang::lexical_cast<std::string>(info.value()) + ")";
  return msg;
}

typedef error_info<struct error_file_name_, std::string> error_file_name;
typedef error_info<struct error_api_func_, std::string> error_api_func;
typedef error_info<struct error_message_, std::string> error_message;

typedef error_info<struct error_splitter_, void> error_splitter;

struct exception_thrower_binder_type {
};
// for exception_thrower

#if defined(__GNUC__)
#define JUBATUS_ERROR_FUNC \
  jubatus::core::common::exception::error_at_func(__PRETTY_FUNCTION__)
#else
#define JUBATUS_ERROR_FUNC \
  jubatus::core::common::exception::error_at_func(__func__)
#endif

#define JUBATUS_CURRENT_ERROR_INFO() \
  jubatus::core::common::exception::error_at_file(__FILE__) \
    << jubatus::core::common::exception::error_at_line(__LINE__) \
    << JUBATUS_ERROR_FUNC << jubatus::core::common::exception::error_splitter()
#define JUBATUS_EXCEPTION(e) e << \
  jubatus::core::common::exception::exception_thrower_binder_type() \
    << JUBATUS_CURRENT_ERROR_INFO()

class exception_thrower_base;
typedef pfi::lang::shared_ptr<exception_thrower_base> exception_thrower_ptr;

typedef std::vector<pfi::lang::shared_ptr<error_info_base> > error_info_list_t;

class jubatus_exception : public std::exception {
 public:
  jubatus_exception() throw () {
  }
  virtual ~jubatus_exception() throw () {
  }

  virtual exception_thrower_ptr thrower() const = 0;

  template<class Exception>
  friend const Exception& add_info(
      const Exception& e,
      pfi::lang::shared_ptr<error_info_base> info);

  std::string name() const throw () {
    // does not assume multithreading
    if (exception_class_name_.empty()) {
      exception_class_name_ = pfi::lang::demangle(typeid(*this).name());
    }

    return exception_class_name_;
  }

  virtual const char* what() const throw () {
    name();
    return exception_class_name_.c_str();
  }

  error_info_list_t error_info() const;
  std::string diagnostic_information(bool display_what = false) const;

 private:
  mutable std::string exception_class_name_;
  mutable error_info_list_t info_list_;
};

template<class Exception>
inline const Exception& add_info(
    const Exception& e,
    pfi::lang::shared_ptr<error_info_base> info) {
  e.info_list_.push_back(info);
  return e;
}

template<class Exception, class Tag, class V>
inline const Exception& operator <<(
    const Exception& e,
    const error_info<Tag, V>& info) {
  return add_info(
      e, pfi::lang::shared_ptr<error_info_base>(new error_info<Tag, V>(info)));
}

template<class Exception>
inline const Exception& operator <<(
    const Exception& e,
    pfi::lang::shared_ptr<error_info_base> info) {
  return add_info(e, info);
}

class exception_thrower_base {
 public:
  exception_thrower_base() {
  }
  virtual ~exception_thrower_base() {
  }

  virtual void throw_exception() const = 0;
};

template<class Exception>
class exception_thrower_impl : public exception_thrower_base {
 public:
  explicit exception_thrower_impl(const Exception& e)
      : exception_(e) {
  }

 private:
  // noncopyable
  exception_thrower_impl(const exception_thrower_impl&);
  exception_thrower_impl& operator=(const exception_thrower_impl&);

 public:
  void throw_exception() const {
    throw exception_;
  }

 private:
  Exception exception_;
};

template<class Exception>
class jubaexception : public jubatus_exception {
 public:
  jubaexception() {
  }
  virtual ~jubaexception() throw () {
  }

  exception_thrower_ptr thrower() const {
    if (thrower_) {
      return thrower_;
    } else {
      return exception_thrower_ptr(
          new exception_thrower_impl<Exception>(
              *(static_cast<const Exception*>(this))));
    }
  }

  // This is desireble in private
  void bind_thrower(exception_thrower_ptr thrower) const {
    thrower_ = thrower;
  }

 private:
  mutable exception_thrower_ptr thrower_;
};

template<class Exception>
inline const Exception& operator <<(
    const Exception& e,
    const exception_thrower_binder_type&) {
  e.bind_thrower(
      exception_thrower_ptr(new exception_thrower_impl<Exception>(e)));
  return e;
}

class unknown_exception : public jubaexception<unknown_exception> {
 public:
  explicit unknown_exception() {
    // TODO(kashihara): push unknown_exception
  }

  const char* what() const throw () {
    return "unknown exception";
  }
};

class runtime_error : public jubaexception<runtime_error> {
 public:
  explicit runtime_error(const std::string& what)
      : what_(what) {
  }

  ~runtime_error() throw () {
  }

  const char* what() const throw () {
    return what_.c_str();
  }
 private:
  std::string what_;
};

namespace detail {
template<class Exception>
exception_thrower_ptr current_std_exception(const Exception& e) {
  return exception_thrower_ptr(new exception_thrower_impl<Exception>(e));
}

}  // namespace detail

// Don't call without catch blocks
inline exception_thrower_ptr get_current_exception() {
  exception_thrower_ptr ptr;

  try {
    throw;
  } catch (const std::bad_alloc& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::bad_cast& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::bad_exception& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::bad_typeid& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::domain_error& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::invalid_argument& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::length_error& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::out_of_range& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::logic_error& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::range_error& e) {  // runtime_error
    ptr = detail::current_std_exception(e);
  } catch (const std::overflow_error& e) {  // runtime_error
    ptr = detail::current_std_exception(e);
  } catch (const std::underflow_error& e) {  // runtime_error
    ptr = detail::current_std_exception(e);
  } catch (const std::runtime_error& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::ios_base::failure& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const jubatus_exception& e) {
    ptr = e.thrower();
  } catch (const std::exception& e) {
    ptr = detail::current_std_exception(e);
  } catch (...) {
    ptr = unknown_exception().thrower();
  }

  return ptr;
}

}  // namespace exception

class config_exception : public exception::jubaexception<config_exception> {
};

class storage_not_set : public exception::jubaexception<storage_not_set> {
};

class config_not_set : public exception::jubaexception<config_not_set> {
  const char* what() const throw () {
    return "config_not_set";
  }
};

class unsupported_method : public exception::runtime_error {
 public:
  explicit unsupported_method(const std::string& n)
      : jubatus::core::common::exception::runtime_error(
          std::string("unsupported method (") + n + ")") {
  }
};

class bad_storage_type : public exception::runtime_error {
 public:
  explicit bad_storage_type(const std::string& n)
      : jubatus::core::common::exception::runtime_error(n) {
  }
};

class membership_error : public exception::runtime_error {
 public:
  explicit membership_error(const std::string& n)
      : jubatus::core::common::exception::runtime_error(n) {
  }
};

class not_found : public membership_error {
 public:
  explicit not_found(const std::string& n)
      : membership_error(n) {
  }
};

class argv_error : public exception::runtime_error {
 public:
  explicit argv_error(const std::string& n)
      : jubatus::core::common::exception::runtime_error(n) {
  }
};

}  // namespace common
}  // namespace core
}  // namespace jubatus

#endif  // JUBATUS_CORE_COMMON_EXCEPTION_HPP_
<commit_msg>#495 change buffer size from 256 to 1024<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library 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 for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef JUBATUS_CORE_COMMON_EXCEPTION_HPP_
#define JUBATUS_CORE_COMMON_EXCEPTION_HPP_

#include <exception>
#include <stdexcept>
#include <ios>
#include <sstream>
#include <string>
#include <vector>

#include <pficommon/lang/shared_ptr.h>
#include <pficommon/lang/demangle.h>
#include "exception_info.hpp"

namespace jubatus {
namespace core {
namespace common {
namespace exception {

typedef error_info<struct error_at_file_, std::string> error_at_file;
typedef error_info<struct error_at_func_, std::string> error_at_func;
typedef error_info<struct error_at_line_, int> error_at_line;
typedef error_info<struct error_errno_, int> error_errno;
inline std::string to_string(const error_errno& info) {
  char buf[1024];
  std::string msg(strerror_r(info.value(), buf, 1024));
  msg += " (" + pfi::lang::lexical_cast<std::string>(info.value()) + ")";
  return msg;
}

typedef error_info<struct error_file_name_, std::string> error_file_name;
typedef error_info<struct error_api_func_, std::string> error_api_func;
typedef error_info<struct error_message_, std::string> error_message;

typedef error_info<struct error_splitter_, void> error_splitter;

struct exception_thrower_binder_type {
};
// for exception_thrower

#if defined(__GNUC__)
#define JUBATUS_ERROR_FUNC \
  jubatus::core::common::exception::error_at_func(__PRETTY_FUNCTION__)
#else
#define JUBATUS_ERROR_FUNC \
  jubatus::core::common::exception::error_at_func(__func__)
#endif

#define JUBATUS_CURRENT_ERROR_INFO() \
  jubatus::core::common::exception::error_at_file(__FILE__) \
    << jubatus::core::common::exception::error_at_line(__LINE__) \
    << JUBATUS_ERROR_FUNC << jubatus::core::common::exception::error_splitter()
#define JUBATUS_EXCEPTION(e) e << \
  jubatus::core::common::exception::exception_thrower_binder_type() \
    << JUBATUS_CURRENT_ERROR_INFO()

class exception_thrower_base;
typedef pfi::lang::shared_ptr<exception_thrower_base> exception_thrower_ptr;

typedef std::vector<pfi::lang::shared_ptr<error_info_base> > error_info_list_t;

class jubatus_exception : public std::exception {
 public:
  jubatus_exception() throw () {
  }
  virtual ~jubatus_exception() throw () {
  }

  virtual exception_thrower_ptr thrower() const = 0;

  template<class Exception>
  friend const Exception& add_info(
      const Exception& e,
      pfi::lang::shared_ptr<error_info_base> info);

  std::string name() const throw () {
    // does not assume multithreading
    if (exception_class_name_.empty()) {
      exception_class_name_ = pfi::lang::demangle(typeid(*this).name());
    }

    return exception_class_name_;
  }

  virtual const char* what() const throw () {
    name();
    return exception_class_name_.c_str();
  }

  error_info_list_t error_info() const;
  std::string diagnostic_information(bool display_what = false) const;

 private:
  mutable std::string exception_class_name_;
  mutable error_info_list_t info_list_;
};

template<class Exception>
inline const Exception& add_info(
    const Exception& e,
    pfi::lang::shared_ptr<error_info_base> info) {
  e.info_list_.push_back(info);
  return e;
}

template<class Exception, class Tag, class V>
inline const Exception& operator <<(
    const Exception& e,
    const error_info<Tag, V>& info) {
  return add_info(
      e, pfi::lang::shared_ptr<error_info_base>(new error_info<Tag, V>(info)));
}

template<class Exception>
inline const Exception& operator <<(
    const Exception& e,
    pfi::lang::shared_ptr<error_info_base> info) {
  return add_info(e, info);
}

class exception_thrower_base {
 public:
  exception_thrower_base() {
  }
  virtual ~exception_thrower_base() {
  }

  virtual void throw_exception() const = 0;
};

template<class Exception>
class exception_thrower_impl : public exception_thrower_base {
 public:
  explicit exception_thrower_impl(const Exception& e)
      : exception_(e) {
  }

 private:
  // noncopyable
  exception_thrower_impl(const exception_thrower_impl&);
  exception_thrower_impl& operator=(const exception_thrower_impl&);

 public:
  void throw_exception() const {
    throw exception_;
  }

 private:
  Exception exception_;
};

template<class Exception>
class jubaexception : public jubatus_exception {
 public:
  jubaexception() {
  }
  virtual ~jubaexception() throw () {
  }

  exception_thrower_ptr thrower() const {
    if (thrower_) {
      return thrower_;
    } else {
      return exception_thrower_ptr(
          new exception_thrower_impl<Exception>(
              *(static_cast<const Exception*>(this))));
    }
  }

  // This is desireble in private
  void bind_thrower(exception_thrower_ptr thrower) const {
    thrower_ = thrower;
  }

 private:
  mutable exception_thrower_ptr thrower_;
};

template<class Exception>
inline const Exception& operator <<(
    const Exception& e,
    const exception_thrower_binder_type&) {
  e.bind_thrower(
      exception_thrower_ptr(new exception_thrower_impl<Exception>(e)));
  return e;
}

class unknown_exception : public jubaexception<unknown_exception> {
 public:
  explicit unknown_exception() {
    // TODO(kashihara): push unknown_exception
  }

  const char* what() const throw () {
    return "unknown exception";
  }
};

class runtime_error : public jubaexception<runtime_error> {
 public:
  explicit runtime_error(const std::string& what)
      : what_(what) {
  }

  ~runtime_error() throw () {
  }

  const char* what() const throw () {
    return what_.c_str();
  }
 private:
  std::string what_;
};

namespace detail {
template<class Exception>
exception_thrower_ptr current_std_exception(const Exception& e) {
  return exception_thrower_ptr(new exception_thrower_impl<Exception>(e));
}

}  // namespace detail

// Don't call without catch blocks
inline exception_thrower_ptr get_current_exception() {
  exception_thrower_ptr ptr;

  try {
    throw;
  } catch (const std::bad_alloc& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::bad_cast& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::bad_exception& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::bad_typeid& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::domain_error& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::invalid_argument& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::length_error& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::out_of_range& e) {  // logic_error
    ptr = detail::current_std_exception(e);
  } catch (const std::logic_error& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::range_error& e) {  // runtime_error
    ptr = detail::current_std_exception(e);
  } catch (const std::overflow_error& e) {  // runtime_error
    ptr = detail::current_std_exception(e);
  } catch (const std::underflow_error& e) {  // runtime_error
    ptr = detail::current_std_exception(e);
  } catch (const std::runtime_error& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const std::ios_base::failure& e) {  // exception
    ptr = detail::current_std_exception(e);
  } catch (const jubatus_exception& e) {
    ptr = e.thrower();
  } catch (const std::exception& e) {
    ptr = detail::current_std_exception(e);
  } catch (...) {
    ptr = unknown_exception().thrower();
  }

  return ptr;
}

}  // namespace exception

class config_exception : public exception::jubaexception<config_exception> {
};

class storage_not_set : public exception::jubaexception<storage_not_set> {
};

class config_not_set : public exception::jubaexception<config_not_set> {
  const char* what() const throw () {
    return "config_not_set";
  }
};

class unsupported_method : public exception::runtime_error {
 public:
  explicit unsupported_method(const std::string& n)
      : jubatus::core::common::exception::runtime_error(
          std::string("unsupported method (") + n + ")") {
  }
};

class bad_storage_type : public exception::runtime_error {
 public:
  explicit bad_storage_type(const std::string& n)
      : jubatus::core::common::exception::runtime_error(n) {
  }
};

class membership_error : public exception::runtime_error {
 public:
  explicit membership_error(const std::string& n)
      : jubatus::core::common::exception::runtime_error(n) {
  }
};

class not_found : public membership_error {
 public:
  explicit not_found(const std::string& n)
      : membership_error(n) {
  }
};

class argv_error : public exception::runtime_error {
 public:
  explicit argv_error(const std::string& n)
      : jubatus::core::common::exception::runtime_error(n) {
  }
};

}  // namespace common
}  // namespace core
}  // namespace jubatus

#endif  // JUBATUS_CORE_COMMON_EXCEPTION_HPP_
<|endoftext|>


<commit_before>#include <set>
#include <string>
#include <memory>
#include <cassert>
#include <iostream>
#include <stdexcept>

#include "config.h"
#include "parsers/cli.h"
#include "solvers/dpll.h"
#include "solvers/tseitin.h"
#include "structures/difference_atom.h"
#include "structures/extended_formula.h"
#include "solvers/difference_assistant.h"
#include "extended_formula.y.hpp"

#define EF satsolver::ExtendedFormula
#define SPEF std::shared_ptr<EF>
#define DA theorysolver::DifferenceAtom
#define SPDA std::shared_ptr<DA>

extern FILE *yyin;
extern int yyparse();

bool VERBOSE = false;
bool WITH_WL = false;
bool DISPLAY_SAT;
bool DISPLAY_ATOMS;
bool DISPLAY_FORMULA;
satsolver::Heuristic HEURISTIC = satsolver::DUMB ;

void parser_result(SPEF ext_formula, std::vector<SPDA> &literal_to_DA) {
    /*********************
     * Reduce
     ********************/
    theorysolver::DifferenceAssistant *assistant;
    satsolver::Affectation *sat_solution;
    std::vector<unsigned int> affected_literals;
    std::shared_ptr<std::map<std::string, int>> name_to_variable;
    std::map<int, std::string> variable_to_name;
    std::shared_ptr<std::unordered_set<std::string>> literals = ext_formula->get_literals();
    std::shared_ptr<satsolver::Formula> formula;

    if (VERBOSE || DISPLAY_FORMULA)
        std::cout << "Interpreted formula as: " << ext_formula->to_string() << std::endl;
    if (VERBOSE || DISPLAY_ATOMS) {
        std::cout << "Atoms:" << std::endl;
        for (unsigned int i=0; i<literal_to_DA.size(); i++)
            std::cout << "\t#" << i+1 << ": " << literal_to_DA[i]->to_string() << std::endl;
    }
    ext_formula = theorysolver::DifferenceAssistant::canonize_formula(ext_formula, literal_to_DA);
    if (VERBOSE || DISPLAY_FORMULA)
        std::cout << "Canonized formula as: " << ext_formula->to_string() << std::endl;
    if (VERBOSE || DISPLAY_ATOMS) {
        std::cout << "Atoms:" << std::endl;
        for (unsigned int i=0; i<literal_to_DA.size(); i++)
            std::cout << "\t#" << i+1 << ": " << literal_to_DA[i]->to_string() << std::endl;
    }
    if (!tseitin_reduction(DISPLAY_SAT, ext_formula, name_to_variable, formula, &affected_literals)) {
        // The formula is always false
        if (DISPLAY_SAT)
            std::cout << "c The formula is so obviously wrong it is not even needed to convert it to conjonctive form." << std::endl;
        std::cout << "s UNSATISFIABLE" << std::endl;
        return;
    }
    if (!name_to_variable) {
        switch (ext_formula->get_type()) {
            case EF::TRUE:
                std::cout << "s SATISFIABLE (tautology)" << std::endl;
                return;
            case EF::FALSE:
                std::cout << "s UNSATISFIABLE" << std::endl;
                return;
            default:
                assert(false);
        }
    }
    assistant = new theorysolver::DifferenceAssistant(literal_to_DA, name_to_variable, formula);
    for (auto it : affected_literals) {
        if (!assistant->on_flip(it)) {
            std::cout << "s UNSATISFIABLE" << std::endl;
            return;
        }
    }

    /*********************
     * Solve
     ********************/
    try {
        sat_solution = satsolver::solve(formula, assistant);
    }
    catch (satsolver::Conflict) {
        std::cout << "s UNSATISFIABLE" << std::endl;
        return;
    }
    /*********************
     * Display solution
     ********************/
    assert(assistant->is_state_consistent());
    if (VERBOSE) {
        std::cout << "Solution to SAT problem: " << sat_solution->to_string() << std::endl;
        std::cout << assistant->get_graph().to_string() << std::endl;
    }
    for (auto literal : *literals) {
        try {
            std::cout << literal << " = " << (sat_solution->is_true(name_to_variable->at(literal)) ? "true" : "false") << std::endl;
        }
        catch (std::out_of_range) {
            SPEF f = literal_to_DA[atoi(literal.c_str()+1)-1]->canonical;
            std::cout << literal << " (inferred from " << f->to_string() << ")" << " = ";
            try {
                std::cout << (f->is_true(formula->get_aff(), name_to_variable) ? "true" : "false") << std::endl;
            }
            catch (std::out_of_range) {
                std::cout << "can be true or false" << std::endl ;
            }
        }
    }
    delete assistant;
}

int main (int argc, char *argv[]) {
    /*********************
     * Get input
     ********************/
    CommandLineParser cli_parser(argc, argv, std::unordered_set<std::string>({"-print-interpretation", "-print-sat", "-print-atoms"}), "[-print-interpretation] [-print-sat] [-print-atoms] [<filename>]");
    if (cli_parser.get_nb_parsed_args() == -1)
        return 1;
    int nb_remaining_args = argc - cli_parser.get_nb_parsed_args();
    if (nb_remaining_args == 0) {
        // No other option
    }
    else if (nb_remaining_args == 1) {
        // One option left; hopefully the file name
        yyin = fopen(argv[argc-nb_remaining_args], "r");
    }
    else {
        // Too many unknown options
        cli_parser.print_syntax_error(argv[0]);
        return 1;
    }
    DISPLAY_SAT = cli_parser.get_arg("-print-sat");
    DISPLAY_ATOMS = cli_parser.get_arg("-print-atoms");
    DISPLAY_FORMULA = cli_parser.get_arg("-print-interpretation");
    return yyparse();
}

<commit_msg>Correct a little mistake.<commit_after>#include <set>
#include <string>
#include <memory>
#include <cassert>
#include <iostream>
#include <stdexcept>

#include "config.h"
#include "parsers/cli.h"
#include "solvers/dpll.h"
#include "solvers/tseitin.h"
#include "structures/difference_atom.h"
#include "structures/extended_formula.h"
#include "solvers/difference_assistant.h"
#include "extended_formula.y.hpp"

#define EF satsolver::ExtendedFormula
#define SPEF std::shared_ptr<EF>
#define DA theorysolver::DifferenceAtom
#define SPDA std::shared_ptr<DA>

extern FILE *yyin;
extern int yyparse();

bool VERBOSE = false;
bool WITH_WL = false;
bool DISPLAY_SAT;
bool DISPLAY_ATOMS;
bool DISPLAY_FORMULA;
satsolver::Heuristic HEURISTIC = satsolver::DUMB ;

void parser_result(SPEF ext_formula, std::vector<SPDA> &literal_to_DA) {
    /*********************
     * Reduce
     ********************/
    theorysolver::DifferenceAssistant *assistant;
    satsolver::Affectation *sat_solution;
    std::vector<unsigned int> affected_literals;
    std::shared_ptr<std::map<std::string, int>> name_to_variable;
    std::map<int, std::string> variable_to_name;
    std::shared_ptr<std::unordered_set<std::string>> literals = ext_formula->get_literals();
    std::shared_ptr<satsolver::Formula> formula;

    if (VERBOSE || DISPLAY_FORMULA)
        std::cout << "Interpreted formula as: " << ext_formula->to_string() << std::endl;
    if (VERBOSE || DISPLAY_ATOMS) {
        std::cout << "Atoms:" << std::endl;
        for (unsigned int i=0; i<literal_to_DA.size(); i++)
            std::cout << "\t#" << i+1 << ": " << literal_to_DA[i]->to_string() << std::endl;
    }
    ext_formula = theorysolver::DifferenceAssistant::canonize_formula(ext_formula, literal_to_DA);
    if (VERBOSE || DISPLAY_FORMULA)
        std::cout << "Canonized formula as: " << ext_formula->to_string() << std::endl;
    if (VERBOSE || DISPLAY_ATOMS) {
        std::cout << "Atoms:" << std::endl;
        for (unsigned int i=0; i<literal_to_DA.size(); i++)
            std::cout << "\t#" << i+1 << ": " << literal_to_DA[i]->to_string() << std::endl;
    }
    if (!tseitin_reduction(DISPLAY_SAT, ext_formula, name_to_variable, formula, &affected_literals)) {
        // The formula is always false
        if (DISPLAY_SAT)
            std::cout << "c The formula is so obviously wrong it is not even needed to convert it to conjonctive form." << std::endl;
        std::cout << "s UNSATISFIABLE" << std::endl;
        return;
    }
    if (!name_to_variable) {
        switch (ext_formula->get_type()) {
            case EF::TRUE:
                std::cout << "s SATISFIABLE (tautology)" << std::endl;
                return;
            case EF::FALSE:
                std::cout << "s UNSATISFIABLE" << std::endl;
                return;
            default:
                assert(false);
        }
    }
    assistant = new theorysolver::DifferenceAssistant(literal_to_DA, name_to_variable, formula);
    for (auto it : affected_literals) {
        if (1!=assistant->on_flip(it)) {
            std::cout << "s UNSATISFIABLE" << std::endl;
            return;
        }
    }

    /*********************
     * Solve
     ********************/
    try {
        sat_solution = satsolver::solve(formula, assistant);
    }
    catch (satsolver::Conflict) {
        std::cout << "s UNSATISFIABLE" << std::endl;
        return;
    }
    /*********************
     * Display solution
     ********************/
    assert(assistant->is_state_consistent());
    if (VERBOSE) {
        std::cout << "Solution to SAT problem: " << sat_solution->to_string() << std::endl;
        std::cout << assistant->get_graph().to_string() << std::endl;
    }
    for (auto literal : *literals) {
        try {
            std::cout << literal << " = " << (sat_solution->is_true(name_to_variable->at(literal)) ? "true" : "false") << std::endl;
        }
        catch (std::out_of_range) {
            SPEF f = literal_to_DA[atoi(literal.c_str()+1)-1]->canonical;
            std::cout << literal << " (inferred from " << f->to_string() << ")" << " = ";
            try {
                std::cout << (f->is_true(formula->get_aff(), name_to_variable) ? "true" : "false") << std::endl;
            }
            catch (std::out_of_range) {
                std::cout << "can be true or false" << std::endl ;
            }
        }
    }
    delete assistant;
}

int main (int argc, char *argv[]) {
    /*********************
     * Get input
     ********************/
    CommandLineParser cli_parser(argc, argv, std::unordered_set<std::string>({"-print-interpretation", "-print-sat", "-print-atoms"}), "[-print-interpretation] [-print-sat] [-print-atoms] [<filename>]");
    if (cli_parser.get_nb_parsed_args() == -1)
        return 1;
    int nb_remaining_args = argc - cli_parser.get_nb_parsed_args();
    if (nb_remaining_args == 0) {
        // No other option
    }
    else if (nb_remaining_args == 1) {
        // One option left; hopefully the file name
        yyin = fopen(argv[argc-nb_remaining_args], "r");
    }
    else {
        // Too many unknown options
        cli_parser.print_syntax_error(argv[0]);
        return 1;
    }
    DISPLAY_SAT = cli_parser.get_arg("-print-sat");
    DISPLAY_ATOMS = cli_parser.get_arg("-print-atoms");
    DISPLAY_FORMULA = cli_parser.get_arg("-print-interpretation");
    return yyparse();
}

<|endoftext|>


<commit_before>// Copyright eeGeo Ltd (2012-2015), All Rights Reserved

#include "MenuController.h"
#include "IOpenableControlViewModel.h"

namespace ExampleApp
{
    namespace Menu
    {
        namespace View
        {
            void MenuController::OnOpenableStateChanged(OpenableControl::View::IOpenableControlViewModel& viewModel, float& state)
            {
                if(m_dragInProgress)
                {
                    return;
                }

                if (m_viewModel.IsFullyClosed())
                {
                    m_view.SetFullyOnScreenClosed();
                }
                else if (m_viewModel.IsFullyOpen())
                {
                    m_view.SetFullyOnScreenOpen();
                }
                else
                {
                    m_view.SetOnScreenStateToIntermediateValue(state);
                }
            }

            void MenuController::OnScreenControlStateChanged(ScreenControl::View::IScreenControlViewModel& viewModel, float& state)
            {
                if (m_viewModel.IsFullyOnScreen())
                {
                    m_view.SetFullyOnScreenClosed();
                }
                else if (m_viewModel.IsFullyOffScreen())
                {
                    m_view.SetFullyOffScreen();
                }
                else
                {
                    m_view.SetOnScreenStateToIntermediateValue(state);
                }
            }

            bool MenuController::TryDrag()
            {
                if(m_viewModel.TryAcquireReactorControl())
                {
                    return true;
                }
                return false;
            }

            void MenuController::RefreshPresentation()
            {
                const int numSections = m_viewModel.SectionsCount();
                TSections sections;
                sections.reserve(numSections);

                for(size_t groupIndex = 0; groupIndex < numSections; groupIndex++)
                {
                    IMenuSectionViewModel& section = m_viewModel.GetMenuSection(groupIndex);
                    sections.push_back(&section);
                }

                m_view.UpdateMenuSectionViews(sections);
                m_presentationDirty = false;
            }

            void MenuController::UpdateUiThread(float dt)
            {
                if(m_presentationDirty)
                {
                    RefreshPresentation();
                }

                if(m_dragInProgress)
                {
                    return;
                }

                const bool isAnimating = m_view.IsAnimating();

                if(isAnimating)
                {
                    m_view.UpdateAnimation(dt);

                    if(m_viewModel.HasReactorControl())
                    {
                        const float normalisedAnimationProgress = m_view.GetAnimationProgress();
                        m_viewModel.UpdateOpenState(normalisedAnimationProgress);
                    }
                }

                m_view.SetCanInteract(m_viewModel.IsFullyOpen());
            }

            void MenuController::OnViewClicked()
            {
                Eegeo_ASSERT(!m_dragInProgress, "Cannot click on view while dragging it");

                if(!m_viewModel.TryAcquireReactorControl())
                {
                    return;
                }

                if(m_viewModel.IsFullyClosed())
                {
                    m_view.SetFullyOnScreenOpen();
                }
                else if(m_viewModel.IsFullyOpen())
                {
                    m_view.SetFullyOnScreenClosed();
                }
                else
                {
                    m_viewModel.ReleaseReactorControl();
                }
            }

            void MenuController::OnViewOpened()
            {
                Eegeo_ASSERT(!m_dragInProgress, "identity %d\n", Identity());

                if(!m_viewModel.IsFullyOpen())
                {
                    m_viewModel.Open();
                }

                if(m_viewModel.HasReactorControl())
                {
                    m_viewModel.ReleaseReactorControl();
                }
            }

            void MenuController::OnViewClosed()
            {
                Eegeo_ASSERT(!m_dragInProgress, "identity %d\n", Identity());

                if(!m_viewModel.IsFullyClosed())
                {
                    m_viewModel.Close();
                }

                if(m_viewModel.HasReactorControl())
                {
                    m_viewModel.ReleaseReactorControl();
                }
            }

            Eegeo::Helpers::TIdentity MenuController::Identity() const
            {
                return static_cast<OpenableControl::View::IOpenableControlViewModel&>(m_viewModel).GetIdentity();
            }

            void MenuController::OnDragStarted()
            {
                Eegeo_ASSERT(!m_dragInProgress, "identity %d\n", Identity());

                {
                    const bool acquiredReactorControl = m_viewModel.TryAcquireReactorControl();
                    Eegeo_ASSERT(acquiredReactorControl, "%d failed to acquire reactor control.\n", Identity());
                }

                m_dragInProgress = true;
            }

            void MenuController::OnDrag(float& value)
            {
                Eegeo_ASSERT(m_dragInProgress);

                {
                    const bool acquiredReactorControl = m_viewModel.TryAcquireReactorControl();
                    Eegeo_ASSERT(acquiredReactorControl, "%d failed to acquire reactor control.\n", Identity());
                }

                m_viewModel.UpdateOpenState(value);
            }

            void MenuController::OnDragCompleted()
            {
                Eegeo_ASSERT(m_dragInProgress);

                {
                    const bool acquiredReactorControl = m_viewModel.TryAcquireReactorControl();
                    Eegeo_ASSERT(acquiredReactorControl, "%d failed to acquire reactor control.\n", Identity());
                }

                m_dragInProgress = false;
            }

            void MenuController::OnItemAdded(MenuItemModel& item)
            {
                m_presentationDirty = true;
            }

            void MenuController::OnItemRemoved(MenuItemModel& item)
            {
                m_presentationDirty = true;
            }

            void MenuController::OnItemSelected(int& sectionIndex, int& itemIndex)
            {
                Eegeo_ASSERT(!m_dragInProgress, "Cannot select item on menu while dragging it");

                IMenuSectionViewModel& section = m_viewModel.GetMenuSection(sectionIndex);
                if (section.IsExpandable() && itemIndex == 0)
                {
                    if(section.IsExpanded())
                    {
                        section.Contract();
                    }
                    else
                    {
                        section.Expand();
                    }
                    m_presentationDirty = true;
                    return;
                }
                else
                {
                    int index = section.IsExpandable() ? itemIndex - 1 : itemIndex;
                    MenuItemModel item = section.GetItemAtIndex(index);
                    item.Select();
                }
            }

            MenuController::MenuController(
                IMenuModel& model,
                IMenuViewModel& viewModel,
                IMenuView& view
            )
                : m_model(model)
                , m_viewModel(viewModel)
                , m_view(view)
                , m_onClickedCallback(this, &MenuController::OnViewClicked)
                , m_onViewOpenedCallback(this, &MenuController::OnViewOpened)
                , m_onViewClosedCallback(this, &MenuController::OnViewClosed)
                , m_onDragStartedCallback(this, &MenuController::OnDragStarted)
                , m_onDragCallback(this, &MenuController::OnDrag)
                , m_onDragCompletedCallback(this, &MenuController::OnDragCompleted)
                , m_onItemSelectedCallback(this, &MenuController::OnItemSelected)
                , m_onItemAddedCallback(this, &MenuController::OnItemAdded)
                , m_onItemRemovedCallback(this, &MenuController::OnItemRemoved)
                , m_onScreenStateChanged(this, &MenuController::OnScreenControlStateChanged)
                , m_onOpenableStateChanged(this, &MenuController::OnOpenableStateChanged)
                , m_tryDragFunc(this, &MenuController::TryDrag)
                , m_dragInProgress(false)
                , m_presentationDirty(false)
            {
                m_viewModel.InsertOpenStateChangedCallback(m_onOpenableStateChanged);
                m_viewModel.InsertOnScreenStateChangedCallback(m_onScreenStateChanged);
                m_view.InsertOnDrag(m_onDragCallback);
                m_view.InsertOnDragCompleted(m_onDragCompletedCallback);
                m_view.InsertOnDragStarted(m_onDragStartedCallback);
                m_view.InsertOnItemSelected(m_onItemSelectedCallback);
                m_view.InsertOnViewClicked(m_onClickedCallback);
                m_view.InsertOnViewClosed(m_onViewClosedCallback);
                m_view.InsertOnViewOpened(m_onViewOpenedCallback);
                m_view.SetTryDragFunc(m_tryDragFunc);

                if(m_viewModel.IsFullyOnScreen())
                {
                    float value = m_viewModel.OpenState();
                    OnOpenableStateChanged(m_viewModel, value);
                }

                m_presentationDirty = true;

                for(size_t i = 0; i < m_viewModel.SectionsCount(); ++ i)
                {
                    IMenuSectionViewModel& section(m_viewModel.GetMenuSection(i));
                    IMenuModel& model = section.GetModel();
                    model.InsertItemAddedCallback(m_onItemAddedCallback);
                    model.InsertItemRemovedCallback(m_onItemRemovedCallback);
                }
            }

            MenuController::~MenuController()
            {
                for(size_t i = 0; i < m_viewModel.SectionsCount(); ++ i)
                {
                    IMenuSectionViewModel& section(m_viewModel.GetMenuSection(i));
                    IMenuModel& model = section.GetModel();
                    model.RemoveItemAddedCallback(m_onItemAddedCallback);
                    model.RemoveItemRemovedCallback(m_onItemRemovedCallback);
                }

                m_view.ClearTryDragFunc();
                m_view.RemoveOnViewOpened(m_onViewOpenedCallback);
                m_view.RemoveOnViewClosed(m_onViewClosedCallback);
                m_view.RemoveOnViewClicked(m_onClickedCallback);
                m_view.RemoveOnItemSelected(m_onItemSelectedCallback);
                m_view.RemoveOnDragStarted(m_onDragStartedCallback);
                m_view.RemoveOnDragCompleted(m_onDragCompletedCallback);
                m_view.RemoveOnDrag(m_onDragCallback);
                m_viewModel.RemoveOnScreenStateChangedCallback(m_onScreenStateChanged);
                m_viewModel.RemoveOpenStateChangedCallback(m_onOpenableStateChanged);
            }
        }
    }
}
<commit_msg>Attempt to address MPLY-5449. Menus no longer refresh their layout when closed, moving the iOS Stall when updating search results to a minor layout stall when opening results menu, Buddy: Tim, Scott<commit_after>// Copyright eeGeo Ltd (2012-2015), All Rights Reserved

#include "MenuController.h"
#include "IOpenableControlViewModel.h"

namespace ExampleApp
{
    namespace Menu
    {
        namespace View
        {
            void MenuController::OnOpenableStateChanged(OpenableControl::View::IOpenableControlViewModel& viewModel, float& state)
            {
                if(m_dragInProgress)
                {
                    return;
                }

                if (m_viewModel.IsFullyClosed())
                {
                    m_view.SetFullyOnScreenClosed();
                }
                else if (m_viewModel.IsFullyOpen())
                {
                    m_view.SetFullyOnScreenOpen();
                }
                else
                {
                    m_view.SetOnScreenStateToIntermediateValue(state);
                }
            }

            void MenuController::OnScreenControlStateChanged(ScreenControl::View::IScreenControlViewModel& viewModel, float& state)
            {
                if (m_viewModel.IsFullyOnScreen())
                {
                    m_view.SetFullyOnScreenClosed();
                }
                else if (m_viewModel.IsFullyOffScreen())
                {
                    m_view.SetFullyOffScreen();
                }
                else
                {
                    m_view.SetOnScreenStateToIntermediateValue(state);
                }
            }

            bool MenuController::TryDrag()
            {
                if(m_viewModel.TryAcquireReactorControl())
                {
                    return true;
                }
                return false;
            }

            void MenuController::RefreshPresentation()
            {
                const int numSections = m_viewModel.SectionsCount();
                TSections sections;
                sections.reserve(numSections);

                for(size_t groupIndex = 0; groupIndex < numSections; groupIndex++)
                {
                    IMenuSectionViewModel& section = m_viewModel.GetMenuSection(groupIndex);
                    sections.push_back(&section);
                }

                if(!m_viewModel.IsFullyClosed())
                {
                    m_view.UpdateMenuSectionViews(sections);
                    m_presentationDirty = false;
                }
            }

            void MenuController::UpdateUiThread(float dt)
            {
                if(m_presentationDirty)
                {
                    RefreshPresentation();
                }

                if(m_dragInProgress)
                {
                    return;
                }

                const bool isAnimating = m_view.IsAnimating();

                if(isAnimating)
                {
                    m_view.UpdateAnimation(dt);

                    if(m_viewModel.HasReactorControl())
                    {
                        const float normalisedAnimationProgress = m_view.GetAnimationProgress();
                        m_viewModel.UpdateOpenState(normalisedAnimationProgress);
                    }
                }

                m_view.SetCanInteract(m_viewModel.IsFullyOpen());
            }

            void MenuController::OnViewClicked()
            {
                Eegeo_ASSERT(!m_dragInProgress, "Cannot click on view while dragging it");

                if(!m_viewModel.TryAcquireReactorControl())
                {
                    return;
                }

                if(m_viewModel.IsFullyClosed())
                {
                    m_view.SetFullyOnScreenOpen();
                }
                else if(m_viewModel.IsFullyOpen())
                {
                    m_view.SetFullyOnScreenClosed();
                }
                else
                {
                    m_viewModel.ReleaseReactorControl();
                }
            }

            void MenuController::OnViewOpened()
            {
                Eegeo_ASSERT(!m_dragInProgress, "identity %d\n", Identity());

                if(!m_viewModel.IsFullyOpen())
                {
                    m_viewModel.Open();
                }

                if(m_viewModel.HasReactorControl())
                {
                    m_viewModel.ReleaseReactorControl();
                }
            }

            void MenuController::OnViewClosed()
            {
                Eegeo_ASSERT(!m_dragInProgress, "identity %d\n", Identity());

                if(!m_viewModel.IsFullyClosed())
                {
                    m_viewModel.Close();
                }

                if(m_viewModel.HasReactorControl())
                {
                    m_viewModel.ReleaseReactorControl();
                }
            }

            Eegeo::Helpers::TIdentity MenuController::Identity() const
            {
                return static_cast<OpenableControl::View::IOpenableControlViewModel&>(m_viewModel).GetIdentity();
            }

            void MenuController::OnDragStarted()
            {
                Eegeo_ASSERT(!m_dragInProgress, "identity %d\n", Identity());

                {
                    const bool acquiredReactorControl = m_viewModel.TryAcquireReactorControl();
                    Eegeo_ASSERT(acquiredReactorControl, "%d failed to acquire reactor control.\n", Identity());
                }

                m_dragInProgress = true;
            }

            void MenuController::OnDrag(float& value)
            {
                Eegeo_ASSERT(m_dragInProgress);

                {
                    const bool acquiredReactorControl = m_viewModel.TryAcquireReactorControl();
                    Eegeo_ASSERT(acquiredReactorControl, "%d failed to acquire reactor control.\n", Identity());
                }

                m_viewModel.UpdateOpenState(value);
            }

            void MenuController::OnDragCompleted()
            {
                Eegeo_ASSERT(m_dragInProgress);

                {
                    const bool acquiredReactorControl = m_viewModel.TryAcquireReactorControl();
                    Eegeo_ASSERT(acquiredReactorControl, "%d failed to acquire reactor control.\n", Identity());
                }

                m_dragInProgress = false;
            }

            void MenuController::OnItemAdded(MenuItemModel& item)
            {
                m_presentationDirty = true;
            }

            void MenuController::OnItemRemoved(MenuItemModel& item)
            {
                m_presentationDirty = true;
            }

            void MenuController::OnItemSelected(int& sectionIndex, int& itemIndex)
            {
                Eegeo_ASSERT(!m_dragInProgress, "Cannot select item on menu while dragging it");

                IMenuSectionViewModel& section = m_viewModel.GetMenuSection(sectionIndex);
                if (section.IsExpandable() && itemIndex == 0)
                {
                    if(section.IsExpanded())
                    {
                        section.Contract();
                    }
                    else
                    {
                        section.Expand();
                    }
                    m_presentationDirty = true;
                    return;
                }
                else
                {
                    int index = section.IsExpandable() ? itemIndex - 1 : itemIndex;
                    MenuItemModel item = section.GetItemAtIndex(index);
                    item.Select();
                }
            }

            MenuController::MenuController(
                IMenuModel& model,
                IMenuViewModel& viewModel,
                IMenuView& view
            )
                : m_model(model)
                , m_viewModel(viewModel)
                , m_view(view)
                , m_onClickedCallback(this, &MenuController::OnViewClicked)
                , m_onViewOpenedCallback(this, &MenuController::OnViewOpened)
                , m_onViewClosedCallback(this, &MenuController::OnViewClosed)
                , m_onDragStartedCallback(this, &MenuController::OnDragStarted)
                , m_onDragCallback(this, &MenuController::OnDrag)
                , m_onDragCompletedCallback(this, &MenuController::OnDragCompleted)
                , m_onItemSelectedCallback(this, &MenuController::OnItemSelected)
                , m_onItemAddedCallback(this, &MenuController::OnItemAdded)
                , m_onItemRemovedCallback(this, &MenuController::OnItemRemoved)
                , m_onScreenStateChanged(this, &MenuController::OnScreenControlStateChanged)
                , m_onOpenableStateChanged(this, &MenuController::OnOpenableStateChanged)
                , m_tryDragFunc(this, &MenuController::TryDrag)
                , m_dragInProgress(false)
                , m_presentationDirty(false)
            {
                m_viewModel.InsertOpenStateChangedCallback(m_onOpenableStateChanged);
                m_viewModel.InsertOnScreenStateChangedCallback(m_onScreenStateChanged);
                m_view.InsertOnDrag(m_onDragCallback);
                m_view.InsertOnDragCompleted(m_onDragCompletedCallback);
                m_view.InsertOnDragStarted(m_onDragStartedCallback);
                m_view.InsertOnItemSelected(m_onItemSelectedCallback);
                m_view.InsertOnViewClicked(m_onClickedCallback);
                m_view.InsertOnViewClosed(m_onViewClosedCallback);
                m_view.InsertOnViewOpened(m_onViewOpenedCallback);
                m_view.SetTryDragFunc(m_tryDragFunc);

                if(m_viewModel.IsFullyOnScreen())
                {
                    float value = m_viewModel.OpenState();
                    OnOpenableStateChanged(m_viewModel, value);
                }

                m_presentationDirty = true;

                for(size_t i = 0; i < m_viewModel.SectionsCount(); ++ i)
                {
                    IMenuSectionViewModel& section(m_viewModel.GetMenuSection(i));
                    IMenuModel& model = section.GetModel();
                    model.InsertItemAddedCallback(m_onItemAddedCallback);
                    model.InsertItemRemovedCallback(m_onItemRemovedCallback);
                }
            }

            MenuController::~MenuController()
            {
                for(size_t i = 0; i < m_viewModel.SectionsCount(); ++ i)
                {
                    IMenuSectionViewModel& section(m_viewModel.GetMenuSection(i));
                    IMenuModel& model = section.GetModel();
                    model.RemoveItemAddedCallback(m_onItemAddedCallback);
                    model.RemoveItemRemovedCallback(m_onItemRemovedCallback);
                }

                m_view.ClearTryDragFunc();
                m_view.RemoveOnViewOpened(m_onViewOpenedCallback);
                m_view.RemoveOnViewClosed(m_onViewClosedCallback);
                m_view.RemoveOnViewClicked(m_onClickedCallback);
                m_view.RemoveOnItemSelected(m_onItemSelectedCallback);
                m_view.RemoveOnDragStarted(m_onDragStartedCallback);
                m_view.RemoveOnDragCompleted(m_onDragCompletedCallback);
                m_view.RemoveOnDrag(m_onDragCallback);
                m_viewModel.RemoveOnScreenStateChangedCallback(m_onScreenStateChanged);
                m_viewModel.RemoveOpenStateChangedCallback(m_onOpenableStateChanged);
            }
        }
    }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: AccessiblePageShape.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 04:58:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SD_ACCESSIBILITY_ACCESSIBLE_PAGE_SHAPE_HXX
#define _SD_ACCESSIBILITY_ACCESSIBLE_PAGE_SHAPE_HXX

#ifndef _SVX_ACCESSIBILITY_ACCESSIBLE_SHAPE_HXX
#include <svx/AccessibleShape.hxx>
#endif
#ifndef _SVX_ACCESSIBILITY_ACCESSIBLE_SHAPE_TREE_INFO_HXX
#include <svx/AccessibleShapeTreeInfo.hxx>
#endif
#ifndef _SVX_ACCESSIBILITY_IACCESSIBLE_VIEW_FORWARDER_LISTENER_HXX
#include <svx/IAccessibleViewForwarderListener.hxx>
#endif

#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_
#include <com/sun/star/accessibility/XAccessible.hpp>
#endif
#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEXTENDEDCOMPONENT_HPP_
#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGE_HPP_
#include <com/sun/star/drawing/XDrawPage.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XEVENTLISTENER_HPP_
#include <com/sun/star/lang/XEventListener.hpp>
#endif

#ifndef _SVX_UNOEDACC_HXX_
#include <svx/AccessibleTextHelper.hxx>
#endif

namespace accessibility {

/** A page shape represents the actual page as seen on the screen.
*/
class AccessiblePageShape
    :   public AccessibleShape
{
public:
    //=====  internal  ========================================================

    /** Create a new accessible object that makes the given shape accessible.
        @param rxParent
            The accessible parent object.  It will be used, for example when
            the <member>getIndexInParent</member> method is called.
        @param rShapeTreeInfo
            Bundel of information passed to this shape and all of its desendants.
        @param nIndex
            Index used to disambiguate between objects that have the same
            name.  Passing a value of -1 leads to the use of the object's
            z-order instead.  Because that is not a good substitute, better
            pass an ever increasing counter.
        @attention
            Always call the <member>init</member> method after creating a
            new accessible shape.  This is one way to overcome the potential
            problem of registering the new object with e.g. event
            broadcasters.  That would delete the new object if a broadcaster
            would not keep a strong reference to the new object.
    */
    AccessiblePageShape (
        const ::com::sun::star::uno::Reference<
            ::com::sun::star::drawing::XDrawPage>& rxPage,
        const ::com::sun::star::uno::Reference<
            ::com::sun::star::accessibility::XAccessible>& rxParent,
        const AccessibleShapeTreeInfo& rShapeTreeInfo,
        long nIndex = -1);

    virtual ~AccessiblePageShape (void);

    /** Initialize a new shape.  See the documentation of the constructor
        for the reason of this method's existence.
    */
    virtual void Init (void);

    //=====  XAccessibleContext  ==============================================

    /// Returns always 0 because there can be no children.
    virtual long SAL_CALL
        getAccessibleChildCount (void)
        throw ();

    /** Return the specified child.
        @param nIndex
            Index of the requested child.
        @return
            Reference of the requested child which is the accessible object
            of a visible shape.
        @raises IndexOutOfBoundsException
            Throws always an exception because there are no children.
    */
    virtual ::com::sun::star::uno::Reference<
            ::com::sun::star::accessibility::XAccessible> SAL_CALL
        getAccessibleChild (long nIndex)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  XAccessibleComponent  ============================================

    virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual sal_Int32 SAL_CALL getForeground (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual sal_Int32 SAL_CALL getBackground (void)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  XComponent  ======================================================

    virtual void SAL_CALL
        dispose (void)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  XServiceInfo  ====================================================

    virtual ::rtl::OUString SAL_CALL
        getImplementationName (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL
        getSupportedServiceNames (void)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  lang::XEventListener  ============================================

    virtual void SAL_CALL
        disposing (const ::com::sun::star::lang::EventObject& Source)
        throw (::com::sun::star::uno::RuntimeException);

protected:
    /** Create a base name string that contains the accessible name.
    */
    virtual ::rtl::OUString
        CreateAccessibleBaseName (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual ::rtl::OUString
        CreateAccessibleName (void)
        throw (::com::sun::star::uno::RuntimeException);

    /// Create a description string that contains the accessible description.
    virtual ::rtl::OUString
        CreateAccessibleDescription (void)
        throw (::com::sun::star::uno::RuntimeException);

private:
    ::com::sun::star::uno::Reference<
        ::com::sun::star::drawing::XDrawPage> mxPage;

    /** Don't use the default constructor.  Use the public constructor that
        takes the original shape and the parent as arguments instead.
    */
    explicit AccessiblePageShape (void);
    /// Don't use the copy constructor.  Is there any use for it?
    explicit AccessiblePageShape (const AccessiblePageShape&);
    /// Don't use the assignment operator.  Do we need this?
    AccessibleShape& operator= (const AccessiblePageShape&);
};

} // end of namespace accessibility

#endif
<commit_msg>INTEGRATION: CWS long2int (1.7.50); FILE MERGED 2005/10/26 18:06:47 kendy 1.7.50.1: #i56715# Trivial long/ULONG -> sal_Int32/sal_uInt32 patches extracted from ooo64bit02 CWS.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: AccessiblePageShape.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: vg $ $Date: 2006-03-31 09:06:21 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SD_ACCESSIBILITY_ACCESSIBLE_PAGE_SHAPE_HXX
#define _SD_ACCESSIBILITY_ACCESSIBLE_PAGE_SHAPE_HXX

#ifndef _SVX_ACCESSIBILITY_ACCESSIBLE_SHAPE_HXX
#include <svx/AccessibleShape.hxx>
#endif
#ifndef _SVX_ACCESSIBILITY_ACCESSIBLE_SHAPE_TREE_INFO_HXX
#include <svx/AccessibleShapeTreeInfo.hxx>
#endif
#ifndef _SVX_ACCESSIBILITY_IACCESSIBLE_VIEW_FORWARDER_LISTENER_HXX
#include <svx/IAccessibleViewForwarderListener.hxx>
#endif

#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_
#include <com/sun/star/accessibility/XAccessible.hpp>
#endif
#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEXTENDEDCOMPONENT_HPP_
#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGE_HPP_
#include <com/sun/star/drawing/XDrawPage.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XEVENTLISTENER_HPP_
#include <com/sun/star/lang/XEventListener.hpp>
#endif

#ifndef _SVX_UNOEDACC_HXX_
#include <svx/AccessibleTextHelper.hxx>
#endif

namespace accessibility {

/** A page shape represents the actual page as seen on the screen.
*/
class AccessiblePageShape
    :   public AccessibleShape
{
public:
    //=====  internal  ========================================================

    /** Create a new accessible object that makes the given shape accessible.
        @param rxParent
            The accessible parent object.  It will be used, for example when
            the <member>getIndexInParent</member> method is called.
        @param rShapeTreeInfo
            Bundel of information passed to this shape and all of its desendants.
        @param nIndex
            Index used to disambiguate between objects that have the same
            name.  Passing a value of -1 leads to the use of the object's
            z-order instead.  Because that is not a good substitute, better
            pass an ever increasing counter.
        @attention
            Always call the <member>init</member> method after creating a
            new accessible shape.  This is one way to overcome the potential
            problem of registering the new object with e.g. event
            broadcasters.  That would delete the new object if a broadcaster
            would not keep a strong reference to the new object.
    */
    AccessiblePageShape (
        const ::com::sun::star::uno::Reference<
            ::com::sun::star::drawing::XDrawPage>& rxPage,
        const ::com::sun::star::uno::Reference<
            ::com::sun::star::accessibility::XAccessible>& rxParent,
        const AccessibleShapeTreeInfo& rShapeTreeInfo,
        long nIndex = -1);

    virtual ~AccessiblePageShape (void);

    /** Initialize a new shape.  See the documentation of the constructor
        for the reason of this method's existence.
    */
    virtual void Init (void);

    //=====  XAccessibleContext  ==============================================

    /// Returns always 0 because there can be no children.
    virtual sal_Int32 SAL_CALL
        getAccessibleChildCount (void)
        throw ();

    /** Return the specified child.
        @param nIndex
            Index of the requested child.
        @return
            Reference of the requested child which is the accessible object
            of a visible shape.
        @raises IndexOutOfBoundsException
            Throws always an exception because there are no children.
    */
    virtual ::com::sun::star::uno::Reference<
            ::com::sun::star::accessibility::XAccessible> SAL_CALL
        getAccessibleChild (long nIndex)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  XAccessibleComponent  ============================================

    virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual sal_Int32 SAL_CALL getForeground (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual sal_Int32 SAL_CALL getBackground (void)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  XComponent  ======================================================

    virtual void SAL_CALL
        dispose (void)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  XServiceInfo  ====================================================

    virtual ::rtl::OUString SAL_CALL
        getImplementationName (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL
        getSupportedServiceNames (void)
        throw (::com::sun::star::uno::RuntimeException);

    //=====  lang::XEventListener  ============================================

    virtual void SAL_CALL
        disposing (const ::com::sun::star::lang::EventObject& Source)
        throw (::com::sun::star::uno::RuntimeException);

protected:
    /** Create a base name string that contains the accessible name.
    */
    virtual ::rtl::OUString
        CreateAccessibleBaseName (void)
        throw (::com::sun::star::uno::RuntimeException);

    virtual ::rtl::OUString
        CreateAccessibleName (void)
        throw (::com::sun::star::uno::RuntimeException);

    /// Create a description string that contains the accessible description.
    virtual ::rtl::OUString
        CreateAccessibleDescription (void)
        throw (::com::sun::star::uno::RuntimeException);

private:
    ::com::sun::star::uno::Reference<
        ::com::sun::star::drawing::XDrawPage> mxPage;

    /** Don't use the default constructor.  Use the public constructor that
        takes the original shape and the parent as arguments instead.
    */
    explicit AccessiblePageShape (void);
    /// Don't use the copy constructor.  Is there any use for it?
    explicit AccessiblePageShape (const AccessiblePageShape&);
    /// Don't use the assignment operator.  Do we need this?
    AccessibleShape& operator= (const AccessiblePageShape&);
};

} // end of namespace accessibility

#endif
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program 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 license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <thread>
#include <eventql/util/util/Base64.h>
#include <eventql/util/fnv.h>
#include <eventql/util/protobuf/msg.h>
#include <eventql/util/io/fileutil.h>
#include <eventql/io/sstable/sstablereader.h>
#include <eventql/db/partition_map.h>
#include <eventql/db/PartitionState.pb.h>
#include <eventql/db/PartitionReplication.h>

#include "eventql/eventql.h"

namespace eventql {

static mdb::MDBOptions tsdb_mdb_opts() {
  mdb::MDBOptions opts;
  opts.data_filename = "index.db";
  opts.lock_filename = "index.db.lck";
  return opts;
};

PartitionMap::PartitionMap(
    ServerCfg* cfg) :
    cfg_(cfg),
    db_(mdb::MDB::open(cfg_->db_path, tsdb_mdb_opts())) {}

Option<RefPtr<Table>> PartitionMap::findTable(
    const String& stream_ns,
    const String& table_name) const {
  std::unique_lock<std::mutex> lk(mutex_);
  return findTableWithLock(stream_ns, table_name);
}

Option<RefPtr<Table>> PartitionMap::findTableWithLock(
    const String& stream_ns,
    const String& table_name) const {
  auto stream_ns_key = stream_ns + "~" + table_name;

  const auto& iter = tables_.find(stream_ns_key);
  if (iter == tables_.end()) {
    return None<RefPtr<Table>>();
  } else {
    return Some(iter->second);
  }
}

void PartitionMap::configureTable(
    const TableDefinition& table,
    Set<SHA1Hash>* affected_partitions /* = nullptr */) {
  std::unique_lock<std::mutex> lk(mutex_);
  auto tbl_key = table.customer() + "~" + table.table_name();
  bool metadata_changed = false;

  {
    auto iter = tables_.find(tbl_key);
    if (iter == tables_.end()) {
      tables_.emplace(tbl_key, new Table(table));
    } else {
      auto last_metadata_txn = iter->second->getLastMetadataTransaction();
      if (table.metadata_txnseq() > last_metadata_txn.getSequenceNumber()) {
        metadata_changed = true;
      }

      iter->second->updateConfig(table);
    }
  }

  if (metadata_changed && affected_partitions != nullptr) {
    auto key_prefix = tbl_key + "~";
    auto iter = partitions_.lower_bound(key_prefix);
    for (; iter != partitions_.end(); ++iter) {
      if (!StringUtil::beginsWith(iter->first, key_prefix)) {
        break;
      }

      auto partition_id_str = iter->first.substr(key_prefix.size());
      affected_partitions->emplace(
          SHA1Hash(partition_id_str.data(), partition_id_str.size()));
    }
  }
}

void PartitionMap::open() {
  auto txn = db_->startTransaction(false);
  auto cursor = txn->getCursor();

  Vector<PartitionKey> partitions;
  for (int i = 0; ; ++i) {
    Buffer key;
    Buffer value;
    if (i == 0) {
      if (!cursor->getFirst(&key, &value)) {
        break;
      }
    } else {
      if (!cursor->getNext(&key, &value)) {
        break;
      }
    }

    auto db_key = key.toString();
    if (db_key.size() == 0) {
      continue;
    }

    if (db_key[0] == 0x1b) {
      continue;
    }

    auto tsdb_namespace_off = StringUtil::find(db_key, '~');
    if (tsdb_namespace_off == String::npos) {
      RAISEF(kRuntimeError, "invalid partition key: $0", db_key);
    }

    auto tsdb_namespace = db_key.substr(0, tsdb_namespace_off);
    SHA1Hash partition_key(
        db_key.data() + tsdb_namespace_off + 1,
        db_key.size() - tsdb_namespace_off - 1);

    auto table_key = value.toString();
    auto table = findTableWithLock(tsdb_namespace, table_key);

    auto mem_key = tsdb_namespace + "~" + table_key + "~";
    mem_key.append((char*) partition_key.data(), partition_key.size());

    partitions_.emplace(mem_key, mkScoped(new LazyPartition()));

    if (table.isEmpty()) {
      logWarning(
          "tsdb",
          "Orphaned partition: $0/$1",
          table_key,
          partition_key.toString());
      continue;
    }

    partitions.emplace_back(
        std::make_tuple(tsdb_namespace, table_key, partition_key));
  }

  cursor->close();
  txn->abort();

  auto background_load_thread = std::thread(
      std::bind(&PartitionMap::loadPartitions, this, partitions));

  background_load_thread.detach();
}

void PartitionMap::loadPartitions(const Vector<PartitionKey>& partitions) {
  for (const auto& p : partitions) {
    try {
      findPartition(std::get<0>(p), std::get<1>(p), std::get<2>(p));
    } catch (const StandardException& e) {
      logError(
          "tsdb",
          e,
          "error while loading partition $0/$1/$2",
          std::get<0>(p),
          std::get<1>(p),
          std::get<2>(p).toString());
    }
  }
}

RefPtr<Partition> PartitionMap::findOrCreatePartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key) {
  auto db_key = tsdb_namespace + "~";
  db_key.append((char*) partition_key.data(), partition_key.size());

  auto mem_key = tsdb_namespace + "~" + table_name + "~";
  mem_key.append((char*) partition_key.data(), partition_key.size());

  std::unique_lock<std::mutex> lk(mutex_);
  auto iter = partitions_.find(mem_key);
  if (iter != partitions_.end()) {
    if (iter->second->isLoaded()) {
      return iter->second->getPartition();
    }
  }

  auto table = findTableWithLock(tsdb_namespace, table_name);
  if (table.isEmpty()) {
    RAISEF(kNotFoundError, "table not found: $0", table_name);
  }

  if (iter != partitions_.end()) {
    auto partition = iter->second.get();
    lk.unlock();

    return partition->getPartition(
        tsdb_namespace,
        table.get(),
        partition_key,
        cfg_,
        this);
  }

  auto partition = Partition::create(
      tsdb_namespace,
      table.get(),
      partition_key,
      cfg_);

  partitions_.emplace(mem_key, mkScoped(new LazyPartition(partition)));

  auto txn = db_->startTransaction(false);
  txn->update(
      db_key.data(),
      db_key.size(),
      table_name.data(),
      table_name.size());

  txn->commit();
  lk.unlock();

  auto change = mkRef(new PartitionChangeNotification());
  change->partition = partition;
  publishPartitionChange(change);

  return partition;
}

Option<RefPtr<Partition>> PartitionMap::findPartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key) {
  auto db_key = tsdb_namespace + "~";
  db_key.append((char*) partition_key.data(), partition_key.size());

  auto mem_key = tsdb_namespace + "~" + table_name + "~";
  mem_key.append((char*) partition_key.data(), partition_key.size());

  std::unique_lock<std::mutex> lk(mutex_);
  auto iter = partitions_.find(mem_key);
  if (iter == partitions_.end()) {
    return None<RefPtr<Partition>>();
  } else {
    if (iter->second->isLoaded()) {
      return Some(iter->second->getPartition());
    }

    auto table = findTableWithLock(tsdb_namespace, table_name);
    if (table.isEmpty()) {
      RAISEF(kNotFoundError, "table not found: $0", table_name);
    }

    auto partition = iter->second.get();
    lk.unlock();

    return Some(
        partition->getPartition(
            tsdb_namespace,
            table.get(),
            partition_key,
            cfg_,
            this));
  }
}

void PartitionMap::listTables(
    const String& tsdb_namespace,
    Function<void (const TSDBTableInfo& table)> fn) const {
  for (const auto& tbl : tables_) {
    if (tbl.second->tsdbNamespace() != tsdb_namespace) {
      continue;
    }

    TSDBTableInfo ti;
    ti.table_name = tbl.second->name();
    ti.config = tbl.second->config();
    ti.schema = tbl.second->schema();
    fn(ti);
  }
}

void PartitionMap::listTablesReverse(
    const String& tsdb_namespace,
    Function<void (const TSDBTableInfo& table)> fn) const {
  for (auto cur = tables_.rbegin(); cur != tables_.rend(); ++cur) {
    if (cur->second->tsdbNamespace() != tsdb_namespace) {
      continue;
    }

    TSDBTableInfo ti;
    ti.table_name = cur->second->name();
    ti.config = cur->second->config();
    ti.schema = cur->second->schema();
    fn(ti);
  }
}

bool PartitionMap::dropLocalPartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key) {
  auto partition_opt = findPartition(tsdb_namespace, table_name, partition_key);
  if (partition_opt.isEmpty()) {
    RAISE(kNotFoundError, "partition not found");
  }

  auto partition = partition_opt.get();
  auto partition_writer = partition->getWriter();

  /* lock partition */
  partition_writer->lock();

  /* check preconditions */
  size_t full_copies = 0;
  try {
    auto repl_scheme = cfg_->repl_scheme;

    full_copies = partition
        ->getReplicationStrategy(repl_scheme, nullptr)
        ->numFullRemoteCopies();

    if (repl_scheme->hasLocalReplica(partition_key) ||
        full_copies < repl_scheme->minNumCopies()) {
      RAISE(kIllegalStateError, "can't delete partition");
    }
  } catch (const StandardException& e) {
    /* unlock partition and bail */
    partition_writer->unlock();
    return false;
  }

  /* start deletion */
  logInfo(
      "z1.core",
      "Partition $0/$1/$2 is not owned by this node and has $3 other " \
      "full copies, trying to unload and drop",
      tsdb_namespace,
      table_name,
      partition_key.toString(),
      full_copies);

  /* freeze partition and unlock waiting writers (they will fail) */
  partition_writer->freeze();
  partition_writer->unlock();

  auto db_key = tsdb_namespace + "~";
  db_key.append((char*) partition_key.data(), partition_key.size());

  auto mem_key = tsdb_namespace + "~" + table_name + "~";
  mem_key.append((char*) partition_key.data(), partition_key.size());

  /* grab the main lock */
  std::unique_lock<std::mutex> lk(mutex_);

  /* delete from in memory partition map */
  auto iter = partitions_.find(mem_key);
  if (iter == partitions_.end()) {
    /* somebody else already deleted this partition */
    return true;
  } else {
    partitions_.erase(iter);
  }

  /* delete from on disk partition map */
  auto txn = db_->startTransaction(false);
  txn->del(db_key);
  txn->commit();

  /* delete partition data from disk (move to trash) */
  {
    auto src_path = FileUtil::joinPaths(
        cfg_->db_path,
        StringUtil::format(
            "$0/$1/$2",
            tsdb_namespace,
            SHA1::compute(table_name).toString(),
            partition_key.toString()));

    auto dst_path = FileUtil::joinPaths(
        cfg_->db_path,
        StringUtil::format(
            "../../trash/$0~$1~$2~$3",
            tsdb_namespace,
            SHA1::compute(table_name).toString(),
            partition_key.toString(),
            Random::singleton()->hex64()));

    FileUtil::mv(src_path, dst_path);
  }

  return true;
}

Option<TSDBTableInfo> PartitionMap::tableInfo(
      const String& tsdb_namespace,
      const String& table_key) const {
  auto table = findTable(tsdb_namespace, table_key);
  if (table.isEmpty()) {
    return None<TSDBTableInfo>();
  }

  TSDBTableInfo ti;
  ti.table_name = table.get()->name();
  ti.config = table.get()->config();
  ti.schema = table.get()->schema();
  return Some(ti);
}

void PartitionMap::subscribeToPartitionChanges(PartitionChangeCallbackFn fn) {
  callbacks_.emplace_back(fn);
}

void PartitionMap::publishPartitionChange(
    RefPtr<PartitionChangeNotification> change) {
  for (const auto& cb : callbacks_) {
    cb(change);
  }
}

} // namespace tdsb

<commit_msg>deliver metadata change notification only for timeseries partitions<commit_after>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program 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 license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <thread>
#include <eventql/util/util/Base64.h>
#include <eventql/util/fnv.h>
#include <eventql/util/protobuf/msg.h>
#include <eventql/util/io/fileutil.h>
#include <eventql/io/sstable/sstablereader.h>
#include <eventql/db/partition_map.h>
#include <eventql/db/PartitionState.pb.h>
#include <eventql/db/PartitionReplication.h>

#include "eventql/eventql.h"

namespace eventql {

static mdb::MDBOptions tsdb_mdb_opts() {
  mdb::MDBOptions opts;
  opts.data_filename = "index.db";
  opts.lock_filename = "index.db.lck";
  return opts;
};

PartitionMap::PartitionMap(
    ServerCfg* cfg) :
    cfg_(cfg),
    db_(mdb::MDB::open(cfg_->db_path, tsdb_mdb_opts())) {}

Option<RefPtr<Table>> PartitionMap::findTable(
    const String& stream_ns,
    const String& table_name) const {
  std::unique_lock<std::mutex> lk(mutex_);
  return findTableWithLock(stream_ns, table_name);
}

Option<RefPtr<Table>> PartitionMap::findTableWithLock(
    const String& stream_ns,
    const String& table_name) const {
  auto stream_ns_key = stream_ns + "~" + table_name;

  const auto& iter = tables_.find(stream_ns_key);
  if (iter == tables_.end()) {
    return None<RefPtr<Table>>();
  } else {
    return Some(iter->second);
  }
}

void PartitionMap::configureTable(
    const TableDefinition& table,
    Set<SHA1Hash>* affected_partitions /* = nullptr */) {
  std::unique_lock<std::mutex> lk(mutex_);
  auto tbl_key = table.customer() + "~" + table.table_name();
  bool metadata_changed = false;

  {
    auto iter = tables_.find(tbl_key);
    if (iter == tables_.end()) {
      tables_.emplace(tbl_key, new Table(table));
    } else {
      if (table.config().partitioner() == TBL_PARTITION_TIMEWINDOW) {
        auto last_metadata_txn = iter->second->getLastMetadataTransaction();
        if (table.metadata_txnseq() > last_metadata_txn.getSequenceNumber()) {
          metadata_changed = true;
        }
      }

      iter->second->updateConfig(table);
    }
  }

  if (metadata_changed && affected_partitions != nullptr) {
    auto key_prefix = tbl_key + "~";
    auto iter = partitions_.lower_bound(key_prefix);
    for (; iter != partitions_.end(); ++iter) {
      if (!StringUtil::beginsWith(iter->first, key_prefix)) {
        break;
      }

      auto partition_id_str = iter->first.substr(key_prefix.size());
      affected_partitions->emplace(
          SHA1Hash(partition_id_str.data(), partition_id_str.size()));
    }
  }
}

void PartitionMap::open() {
  auto txn = db_->startTransaction(false);
  auto cursor = txn->getCursor();

  Vector<PartitionKey> partitions;
  for (int i = 0; ; ++i) {
    Buffer key;
    Buffer value;
    if (i == 0) {
      if (!cursor->getFirst(&key, &value)) {
        break;
      }
    } else {
      if (!cursor->getNext(&key, &value)) {
        break;
      }
    }

    auto db_key = key.toString();
    if (db_key.size() == 0) {
      continue;
    }

    if (db_key[0] == 0x1b) {
      continue;
    }

    auto tsdb_namespace_off = StringUtil::find(db_key, '~');
    if (tsdb_namespace_off == String::npos) {
      RAISEF(kRuntimeError, "invalid partition key: $0", db_key);
    }

    auto tsdb_namespace = db_key.substr(0, tsdb_namespace_off);
    SHA1Hash partition_key(
        db_key.data() + tsdb_namespace_off + 1,
        db_key.size() - tsdb_namespace_off - 1);

    auto table_key = value.toString();
    auto table = findTableWithLock(tsdb_namespace, table_key);

    auto mem_key = tsdb_namespace + "~" + table_key + "~";
    mem_key.append((char*) partition_key.data(), partition_key.size());

    partitions_.emplace(mem_key, mkScoped(new LazyPartition()));

    if (table.isEmpty()) {
      logWarning(
          "tsdb",
          "Orphaned partition: $0/$1",
          table_key,
          partition_key.toString());
      continue;
    }

    partitions.emplace_back(
        std::make_tuple(tsdb_namespace, table_key, partition_key));
  }

  cursor->close();
  txn->abort();

  auto background_load_thread = std::thread(
      std::bind(&PartitionMap::loadPartitions, this, partitions));

  background_load_thread.detach();
}

void PartitionMap::loadPartitions(const Vector<PartitionKey>& partitions) {
  for (const auto& p : partitions) {
    try {
      findPartition(std::get<0>(p), std::get<1>(p), std::get<2>(p));
    } catch (const StandardException& e) {
      logError(
          "tsdb",
          e,
          "error while loading partition $0/$1/$2",
          std::get<0>(p),
          std::get<1>(p),
          std::get<2>(p).toString());
    }
  }
}

RefPtr<Partition> PartitionMap::findOrCreatePartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key) {
  auto db_key = tsdb_namespace + "~";
  db_key.append((char*) partition_key.data(), partition_key.size());

  auto mem_key = tsdb_namespace + "~" + table_name + "~";
  mem_key.append((char*) partition_key.data(), partition_key.size());

  std::unique_lock<std::mutex> lk(mutex_);
  auto iter = partitions_.find(mem_key);
  if (iter != partitions_.end()) {
    if (iter->second->isLoaded()) {
      return iter->second->getPartition();
    }
  }

  auto table = findTableWithLock(tsdb_namespace, table_name);
  if (table.isEmpty()) {
    RAISEF(kNotFoundError, "table not found: $0", table_name);
  }

  if (iter != partitions_.end()) {
    auto partition = iter->second.get();
    lk.unlock();

    return partition->getPartition(
        tsdb_namespace,
        table.get(),
        partition_key,
        cfg_,
        this);
  }

  auto partition = Partition::create(
      tsdb_namespace,
      table.get(),
      partition_key,
      cfg_);

  partitions_.emplace(mem_key, mkScoped(new LazyPartition(partition)));

  auto txn = db_->startTransaction(false);
  txn->update(
      db_key.data(),
      db_key.size(),
      table_name.data(),
      table_name.size());

  txn->commit();
  lk.unlock();

  auto change = mkRef(new PartitionChangeNotification());
  change->partition = partition;
  publishPartitionChange(change);

  return partition;
}

Option<RefPtr<Partition>> PartitionMap::findPartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key) {
  auto db_key = tsdb_namespace + "~";
  db_key.append((char*) partition_key.data(), partition_key.size());

  auto mem_key = tsdb_namespace + "~" + table_name + "~";
  mem_key.append((char*) partition_key.data(), partition_key.size());

  std::unique_lock<std::mutex> lk(mutex_);
  auto iter = partitions_.find(mem_key);
  if (iter == partitions_.end()) {
    return None<RefPtr<Partition>>();
  } else {
    if (iter->second->isLoaded()) {
      return Some(iter->second->getPartition());
    }

    auto table = findTableWithLock(tsdb_namespace, table_name);
    if (table.isEmpty()) {
      RAISEF(kNotFoundError, "table not found: $0", table_name);
    }

    auto partition = iter->second.get();
    lk.unlock();

    return Some(
        partition->getPartition(
            tsdb_namespace,
            table.get(),
            partition_key,
            cfg_,
            this));
  }
}

void PartitionMap::listTables(
    const String& tsdb_namespace,
    Function<void (const TSDBTableInfo& table)> fn) const {
  for (const auto& tbl : tables_) {
    if (tbl.second->tsdbNamespace() != tsdb_namespace) {
      continue;
    }

    TSDBTableInfo ti;
    ti.table_name = tbl.second->name();
    ti.config = tbl.second->config();
    ti.schema = tbl.second->schema();
    fn(ti);
  }
}

void PartitionMap::listTablesReverse(
    const String& tsdb_namespace,
    Function<void (const TSDBTableInfo& table)> fn) const {
  for (auto cur = tables_.rbegin(); cur != tables_.rend(); ++cur) {
    if (cur->second->tsdbNamespace() != tsdb_namespace) {
      continue;
    }

    TSDBTableInfo ti;
    ti.table_name = cur->second->name();
    ti.config = cur->second->config();
    ti.schema = cur->second->schema();
    fn(ti);
  }
}

bool PartitionMap::dropLocalPartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key) {
  auto partition_opt = findPartition(tsdb_namespace, table_name, partition_key);
  if (partition_opt.isEmpty()) {
    RAISE(kNotFoundError, "partition not found");
  }

  auto partition = partition_opt.get();
  auto partition_writer = partition->getWriter();

  /* lock partition */
  partition_writer->lock();

  /* check preconditions */
  size_t full_copies = 0;
  try {
    auto repl_scheme = cfg_->repl_scheme;

    full_copies = partition
        ->getReplicationStrategy(repl_scheme, nullptr)
        ->numFullRemoteCopies();

    if (repl_scheme->hasLocalReplica(partition_key) ||
        full_copies < repl_scheme->minNumCopies()) {
      RAISE(kIllegalStateError, "can't delete partition");
    }
  } catch (const StandardException& e) {
    /* unlock partition and bail */
    partition_writer->unlock();
    return false;
  }

  /* start deletion */
  logInfo(
      "z1.core",
      "Partition $0/$1/$2 is not owned by this node and has $3 other " \
      "full copies, trying to unload and drop",
      tsdb_namespace,
      table_name,
      partition_key.toString(),
      full_copies);

  /* freeze partition and unlock waiting writers (they will fail) */
  partition_writer->freeze();
  partition_writer->unlock();

  auto db_key = tsdb_namespace + "~";
  db_key.append((char*) partition_key.data(), partition_key.size());

  auto mem_key = tsdb_namespace + "~" + table_name + "~";
  mem_key.append((char*) partition_key.data(), partition_key.size());

  /* grab the main lock */
  std::unique_lock<std::mutex> lk(mutex_);

  /* delete from in memory partition map */
  auto iter = partitions_.find(mem_key);
  if (iter == partitions_.end()) {
    /* somebody else already deleted this partition */
    return true;
  } else {
    partitions_.erase(iter);
  }

  /* delete from on disk partition map */
  auto txn = db_->startTransaction(false);
  txn->del(db_key);
  txn->commit();

  /* delete partition data from disk (move to trash) */
  {
    auto src_path = FileUtil::joinPaths(
        cfg_->db_path,
        StringUtil::format(
            "$0/$1/$2",
            tsdb_namespace,
            SHA1::compute(table_name).toString(),
            partition_key.toString()));

    auto dst_path = FileUtil::joinPaths(
        cfg_->db_path,
        StringUtil::format(
            "../../trash/$0~$1~$2~$3",
            tsdb_namespace,
            SHA1::compute(table_name).toString(),
            partition_key.toString(),
            Random::singleton()->hex64()));

    FileUtil::mv(src_path, dst_path);
  }

  return true;
}

Option<TSDBTableInfo> PartitionMap::tableInfo(
      const String& tsdb_namespace,
      const String& table_key) const {
  auto table = findTable(tsdb_namespace, table_key);
  if (table.isEmpty()) {
    return None<TSDBTableInfo>();
  }

  TSDBTableInfo ti;
  ti.table_name = table.get()->name();
  ti.config = table.get()->config();
  ti.schema = table.get()->schema();
  return Some(ti);
}

void PartitionMap::subscribeToPartitionChanges(PartitionChangeCallbackFn fn) {
  callbacks_.emplace_back(fn);
}

void PartitionMap::publishPartitionChange(
    RefPtr<PartitionChangeNotification> change) {
  for (const auto& cb : callbacks_) {
    cb(change);
  }
}

} // namespace tdsb

<|endoftext|>