<commit_before>#pragma once
#include "feature_emitter_iface.hpp"

#include "../indexer/feature.hpp"

#include "../std/map.hpp"
#include "../std/vector.hpp"

/// Feature builder class that used while feature type processing and merging.
class MergedFeatureBuilder1 : public FeatureBuilder1
{
  bool m_isRound;

  points_t m_roundBounds[2];

public:
  MergedFeatureBuilder1() : m_isRound(false) {}
  MergedFeatureBuilder1(FeatureBuilder1 const & fb);

  void SetRound();
  bool IsRound() const { return m_isRound; }

  void AppendFeature(MergedFeatureBuilder1 const & fb, bool fromBegin, bool toBack);

  bool EqualGeometry(MergedFeatureBuilder1 const & fb) const;

  inline bool NotEmpty() const { return !m_Geometry.empty(); }

  inline m2::PointD FirstPoint() const { return m_Geometry.front(); }
  inline m2::PointD LastPoint() const { return m_Geometry.back(); }

  inline void SetType(uint32_t type) { m_Params.SetType(type); }
  inline bool PopAnyType(uint32_t & type) { return m_Params.PopAnyType(type); }
  inline bool PopExactType(uint32_t type) { return m_Params.PopExactType(type); }

  template <class ToDo> void ForEachChangeTypes(ToDo toDo)
  {
    for_each(m_Params.m_Types.begin(), m_Params.m_Types.end(), toDo);
    m_Params.FinishAddingTypes();
  }

  template <class ToDo> void ForEachMiddlePoints(ToDo toDo) const
  {
    for (size_t i = 1; i < m_Geometry.size()-1; ++i)
      toDo(m_Geometry[i]);
  }

  pair<m2::PointD, bool> GetKeyPoint(size_t i) const;
  size_t GetKeyPointsCount() const;

  double GetPriority() const;
};

/// Feature merger.
class FeatureMergeProcessor
{
  typedef int64_t key_t;
  inline key_t get_key(m2::PointD const & p);

  MergedFeatureBuilder1 m_last;

  typedef vector<MergedFeatureBuilder1 *> vector_t;
  typedef map<key_t, vector_t> map_t;
  map_t m_map;

  void Insert(m2::PointD const & pt, MergedFeatureBuilder1 * p);

  void Remove(key_t key, MergedFeatureBuilder1 const * p);
  inline void Remove1(m2::PointD const & pt, MergedFeatureBuilder1 const * p)
  {
    Remove(get_key(pt), p);
  }
  void Remove(MergedFeatureBuilder1 const * p);

  uint32_t m_coordBits;

public:
  FeatureMergeProcessor(uint32_t coordBits);

  void operator() (FeatureBuilder1 const & fb);
  void operator() (MergedFeatureBuilder1 * p);

  void DoMerge(FeatureEmitterIFace & emitter);
};

/// Feature types corrector.
class FeatureTypesProcessor
{
  map<uint32_t, uint32_t> m_mapping;

  static uint32_t GetType(char const * arr[2]);

  void CorrectType(uint32_t & t) const;

  class do_change_types
  {
    FeatureTypesProcessor const & m_pr;
  public:
    do_change_types(FeatureTypesProcessor const & pr) : m_pr(pr) {}
    void operator() (uint32_t & t) { m_pr.CorrectType(t); }
  };

public:
  /// For example: highway-motorway_link => highway-motorway
  void SetMappingTypes(char const * arr1[2], char const * arr2[2]);

  MergedFeatureBuilder1 * operator() (FeatureBuilder1 const & fb);
};
<commit_msg>Warning fix.<commit_after>#pragma once
#include "feature_emitter_iface.hpp"

#include "../indexer/feature.hpp"

#include "../std/map.hpp"
#include "../std/vector.hpp"

/// Feature builder class that used while feature type processing and merging.
class MergedFeatureBuilder1 : public FeatureBuilder1
{
  bool m_isRound;

  points_t m_roundBounds[2];

public:
  MergedFeatureBuilder1() : m_isRound(false) {}
  MergedFeatureBuilder1(FeatureBuilder1 const & fb);

  void SetRound();
  bool IsRound() const { return m_isRound; }

  void AppendFeature(MergedFeatureBuilder1 const & fb, bool fromBegin, bool toBack);

  bool EqualGeometry(MergedFeatureBuilder1 const & fb) const;

  inline bool NotEmpty() const { return !m_Geometry.empty(); }

  inline m2::PointD FirstPoint() const { return m_Geometry.front(); }
  inline m2::PointD LastPoint() const { return m_Geometry.back(); }

  inline void SetType(uint32_t type) { m_Params.SetType(type); }
  inline bool PopAnyType(uint32_t & type) { return m_Params.PopAnyType(type); }
  inline bool PopExactType(uint32_t type) { return m_Params.PopExactType(type); }

  template <class ToDo> void ForEachChangeTypes(ToDo toDo)
  {
    for_each(m_Params.m_Types.begin(), m_Params.m_Types.end(), toDo);
    m_Params.FinishAddingTypes();
  }

  template <class ToDo> void ForEachMiddlePoints(ToDo toDo) const
  {
    for (size_t i = 1; i < m_Geometry.size()-1; ++i)
      toDo(m_Geometry[i]);
  }

  pair<m2::PointD, bool> GetKeyPoint(size_t i) const;
  size_t GetKeyPointsCount() const;

  double GetPriority() const;
};

/// Feature merger.
class FeatureMergeProcessor
{
  typedef int64_t key_t;
  key_t get_key(m2::PointD const & p);

  MergedFeatureBuilder1 m_last;

  typedef vector<MergedFeatureBuilder1 *> vector_t;
  typedef map<key_t, vector_t> map_t;
  map_t m_map;

  void Insert(m2::PointD const & pt, MergedFeatureBuilder1 * p);

  void Remove(key_t key, MergedFeatureBuilder1 const * p);
  inline void Remove1(m2::PointD const & pt, MergedFeatureBuilder1 const * p)
  {
    Remove(get_key(pt), p);
  }
  void Remove(MergedFeatureBuilder1 const * p);

  uint32_t m_coordBits;

public:
  FeatureMergeProcessor(uint32_t coordBits);

  void operator() (FeatureBuilder1 const & fb);
  void operator() (MergedFeatureBuilder1 * p);

  void DoMerge(FeatureEmitterIFace & emitter);
};

/// Feature types corrector.
class FeatureTypesProcessor
{
  map<uint32_t, uint32_t> m_mapping;

  static uint32_t GetType(char const * arr[2]);

  void CorrectType(uint32_t & t) const;

  class do_change_types
  {
    FeatureTypesProcessor const & m_pr;
  public:
    do_change_types(FeatureTypesProcessor const & pr) : m_pr(pr) {}
    void operator() (uint32_t & t) { m_pr.CorrectType(t); }
  };

public:
  /// For example: highway-motorway_link => highway-motorway
  void SetMappingTypes(char const * arr1[2], char const * arr2[2]);

  MergedFeatureBuilder1 * operator() (FeatureBuilder1 const & fb);
};
<|endoftext|>


<commit_before>#include <process.hpp>

#include <vector>

#include <glog/logging.h>

#include <boost/lexical_cast.hpp>

#include "config/config.hpp"

#include "common/fatal.hpp"
#include "common/foreach.hpp"
#ifdef WITH_ZOOKEEPER
#include "common/zookeeper.hpp"
#endif

#include "messaging/messages.hpp"

#include "detector.hpp"
#include "url_processor.hpp"

using namespace mesos;
using namespace mesos::internal;

using boost::lexical_cast;

using process::Process;
using process::UPID;

using std::pair;
using std::string;
using std::vector;

#ifdef WITH_ZOOKEEPER
class ZooKeeperMasterDetector : public MasterDetector, public Watcher
{
public:
  /**
   * Uses ZooKeeper for both detecting masters and contending to be a
   * master.
   *
   * @param server comma separated list of server host:port pairs
   *
   * @param znode top-level "ZooKeeper node" (directory) to use
   * @param pid libprocess pid to send messages/updates to (and to
   * use for contending to be a master)
   * @param contend true if should contend to be master (not needed
   * for slaves and frameworks)
   * @param quiet verbosity logging level for undelying ZooKeeper library
   */
  ZooKeeperMasterDetector(const string& servers,
			  const string& znode,
			  const UPID& pid,
			  bool contend = false,
			  bool quiet = false);

  virtual ~ZooKeeperMasterDetector();

  /**
   * ZooKeeper watcher callback.
   */
  virtual void process(ZooKeeper *zk, int type, int state, const string &path);

private:
  void connected();
  void reconnecting();
  void reconnected();
  void expired();
  void updated(const string& path);

  /**
   * @param s sequence id
   */
  void setId(const string &s);

  /**
   * @return current sequence id if contending to be a master
   */
  string getId();

  /**
   * Attempts to detect a master.
   */
  void detectMaster();

  /**
   * @param seq sequence id of a master
   * @return PID corresponding to a master
   */
  UPID lookupMasterPID(const string &seq) const;

  const string servers;
  const string znode;
  const UPID pid;
  bool contend;
  bool reconnect;

  ZooKeeper *zk;

  // Our sequence string if contending to be a master.
  string mySeq;

  string currentMasterSeq;
  UPID currentMasterPID;
};
#endif // WITH_ZOOKEEPER

MasterDetector::~MasterDetector() {}

MasterDetector* MasterDetector::create(const string &url,
                                       const UPID &pid,
                                       bool contend,
                                       bool quiet)
{
  if (url == "")
    if (contend) {
      return new BasicMasterDetector(pid);
    } else {
      fatal("cannot use specified url to detect master");
    }

  MasterDetector *detector = NULL;

  // Parse the url.
  pair<UrlProcessor::URLType, string> urlPair = UrlProcessor::process(url);

  switch (urlPair.first) {
    // ZooKeeper URL.
    case UrlProcessor::ZOO: {
#ifdef WITH_ZOOKEEPER
      // TODO(benh): Consider actually using the chroot feature of
      // ZooKeeper, rather than just using it's syntax.
      size_t index = urlPair.second.find("/");
      if (index == string::npos) {
	fatal("expecting chroot path for ZooKeeper");
      }

      const string &servers = urlPair.second.substr(0, index);

      const string &znode = urlPair.second.substr(index);
      if (znode == "/") {
	fatal("expecting chroot path for ZooKeeper ('/' is not supported)");
      }

      detector = new ZooKeeperMasterDetector(servers, znode, pid, contend, quiet);
#else
      fatal("Cannot detect masters with 'zoo://', "
            "ZooKeeper is not supported in this build");
#endif // WITH_ZOOKEEPER
      break;
    }

    // Mesos URL or libprocess pid.
    case UrlProcessor::MESOS:
    case UrlProcessor::UNKNOWN: {
      if (contend) {
	// TODO(benh): Wierdnesses like this makes it seem like there
	// should be a separate elector and detector. In particular,
	// it doesn't make sense to pass a libprocess pid and attempt
	// to contend (at least not right now).
	fatal("cannot contend to be a master with specified url");
      } else {
	UPID master(urlPair.second);
	if (!master)
	  fatal("cannot use specified url to detect master");
	detector = new BasicMasterDetector(master, pid);
      }
      break;
    }
  }

  return detector;
}

void MasterDetector::destroy(MasterDetector *detector)
{
  if (detector != NULL)
    delete detector;
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master)
  : master(_master)
{
  // Send a master token.
  {
    MSG<GOT_MASTER_TOKEN> msg;
    msg.set_token("0");
    MesosProcess<class T>::post(master, msg);
  }

  // Elect the master.
  {
    MSG<NEW_MASTER_DETECTED> msg;
    msg.set_pid(master);
    MesosProcess<class T>::post(master, msg);
  }
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const UPID& pid,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Send a master token.
    {
      MSG<GOT_MASTER_TOKEN> msg;
      msg.set_token("0");
      MesosProcess<class T>::post(master, msg);
    }

    // Elect the master.
    {
      MSG<NEW_MASTER_DETECTED> msg;
      msg.set_pid(master);
      MesosProcess<class T>::post(master, msg);
    }
  }

  // Tell the pid about the master.
  MSG<NEW_MASTER_DETECTED> msg;
  msg.set_pid(master);
  MesosProcess<class T>::post(pid, msg);
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const vector<UPID>& pids,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Send a master token.
    {
      MSG<GOT_MASTER_TOKEN> msg;
      msg.set_token("0");
      MesosProcess<class T>::post(master, msg);
    }

    // Elect the master.
    {
      MSG<NEW_MASTER_DETECTED> msg;
      msg.set_pid(master);
      MesosProcess<class T>::post(master, msg);
    }
  }

  // Tell each pid about the master.
  foreach (const UPID& pid, pids) {
    MSG<NEW_MASTER_DETECTED> msg;
    msg.set_pid(master);
    MesosProcess<class T>::post(pid, msg);
  }
}

BasicMasterDetector::~BasicMasterDetector() {}

#ifdef WITH_ZOOKEEPER
ZooKeeperMasterDetector::ZooKeeperMasterDetector(const string& servers,
						 const string& znode,
						 const UPID& pid,
						 bool contend,
						 bool quiet)
  : servers(servers), znode(znode), pid(pid),
    contend(contend), reconnect(false)
{
  // Set verbosity level for underlying ZooKeeper library logging.
  // TODO(benh): Put this in the C++ API.
  zoo_set_debug_level(quiet ? ZOO_LOG_LEVEL_ERROR : ZOO_LOG_LEVEL_DEBUG);

  // Start up the ZooKeeper connection!
  zk = new ZooKeeper(servers, 10000, this);
}

ZooKeeperMasterDetector::~ZooKeeperMasterDetector()
{
  if (zk != NULL) {
    delete zk;
  }
}

void ZooKeeperMasterDetector::connected()
{
  LOG(INFO) << "Master detector connected to ZooKeeper ...";

  int ret;
  string result;

  static const string delimiter = "/";

  // Assume the znode that was created does not end with a "/".
  CHECK(znode.at(znode.length() - 1) != '/');

  // Create directory path znodes as necessary.
  size_t index = znode.find(delimiter, 0);

  while (index < string::npos) {
    // Get out the prefix to create.
    index = znode.find(delimiter, index + 1);
    string prefix = znode.substr(0, index);

    LOG(INFO) << "Trying to create znode '" << prefix << "' in ZooKeeper";

    // Create the node (even if it already exists).
    ret = zk->create(prefix, "", ZOO_OPEN_ACL_UNSAFE,
		     // ZOO_CREATOR_ALL_ACL, // needs authentication
		     0, &result);

    if (ret != ZOK && ret != ZNODEEXISTS) {
      fatal("failed to create ZooKeeper znode! (%s)", zk->error(ret));
    }
  }

  // Wierdness in ZooKeeper timing, let's check that everything is created.
  ret = zk->get(znode, false, &result, NULL);

  if (ret != ZOK) {
    fatal("ZooKeeper not responding correctly (%s). "
	  "Make sure ZooKeeper is running on: %s",
	  zk->error(ret), servers.c_str());
  }

  if (contend) {
    // We contend with the pid given in constructor.
    ret = zk->create(znode + "/", pid, ZOO_OPEN_ACL_UNSAFE,
		     // ZOO_CREATOR_ALL_ACL, // needs authentication
		     ZOO_SEQUENCE | ZOO_EPHEMERAL, &result);

    if (ret != ZOK) {
      fatal("ZooKeeper not responding correctly (%s). "
	    "Make sure ZooKeeper is running on: %s",
	    zk->error(ret), servers.c_str());
    }

    setId(result);
    LOG(INFO) << "Created ephemeral/sequence:" << getId();

    MSG<GOT_MASTER_TOKEN> msg;
    msg.set_token(getId());
    MesosProcess<class T>::post(pid, msg);
  }

  // Now determine who the master is (it may be us).
  detectMaster();
}

void ZooKeeperMasterDetector::reconnecting()
{
  LOG(INFO) << "Master detector lost connection to ZooKeeper, "
	    << "attempting to reconnect ...";
}

void ZooKeeperMasterDetector::reconnected()
{
  LOG(INFO) << "Master detector reconnected ...";

  int ret;
  string result;

  static const string delimiter = "/";

  if (contend) {
    // Contending for master, confirm our ephemeral sequence znode exists.
    ret = zk->get(znode + "/" + mySeq, false, &result, NULL);

    // We might no longer be the master! Commit suicide for now
    // (hoping another master is on standbye), but in the future
    // it would be nice if we could go back on standbye.
    if (ret == ZNONODE) {
      fatal("failed to reconnect to ZooKeeper quickly enough "
	    "(our ephemeral sequence znode is gone), commiting suicide!");
    }

    if (ret != ZOK) {
      fatal("ZooKeeper not responding correctly (%s). "
	    "Make sure ZooKeeper is running on: %s",
	    zk->error(ret), servers.c_str());
    }

    // We are still the master!
    LOG(INFO) << "Still acting as master";
  } else {
    // Reconnected, but maybe the master changed?
    detectMaster();
  }
}

void ZooKeeperMasterDetector::expired()
{
  LOG(WARNING) << "Master detector ZooKeeper session expired!";

  CHECK(zk != NULL);
  delete zk;

  zk = new ZooKeeper(servers, 10000, this);
}

void ZooKeeperMasterDetector::updated(const string& path)
{
  // A new master might have showed up and created a sequence
  // identifier or a master may have died, determine who the master is now!
  detectMaster();
}

void ZooKeeperMasterDetector::process(ZooKeeper* zk, int type, int state,
				      const string &path)
{
  if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_SESSION_EVENT)) {
    // Check if this is a reconnect.
    if (!reconnect) {
      // Initial connect.
      connected();
    } else {
      // Reconnected.
      reconnected();
    }
  } else if ((state == ZOO_CONNECTING_STATE) && (type == ZOO_SESSION_EVENT)) {
    // The client library automatically reconnects, taking into
    // account failed servers in the connection string,
    // appropriately handling the "herd effect", etc.
    reconnect = true;
    reconnecting();
  } else if ((state == ZOO_EXPIRED_SESSION_STATE) && (type == ZOO_SESSION_EVENT)) {
    // Session expiration. Let the manager take care of it.
    expired();

    // If this watcher is reused, the next connect won't be a reconnect.
    reconnect = false;
  } else if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_CHILD_EVENT)) {
    updated(path);
  } else if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_CHANGED_EVENT)) {
    updated(path);
  } else {
    LOG(WARNING) << "Unimplemented watch event: (state is "
		 << state << " and type is " << type << ")";
  }
}

void ZooKeeperMasterDetector::setId(const string& s)
{
  string seq = s;
  // Converts "/path/to/znode/000000131" to "000000131".
  int pos;
  if ((pos = seq.find_last_of('/')) != string::npos) {
    mySeq = seq.erase(0, pos + 1);
  } else
    mySeq = "";
}

string ZooKeeperMasterDetector::getId()
{
  return mySeq;
}

void ZooKeeperMasterDetector::detectMaster()
{
  vector<string> results;

  int ret = zk->getChildren(znode, true, &results);

  if (ret != ZOK) {
    LOG(ERROR) << "Master detector failed to get masters: "
	       << zk->error(ret);
  } else {
    LOG(INFO) << "Master detector found " << results.size()
	      << " registered masters";
  }

  string masterSeq;
  long min = LONG_MAX;
  foreach (const string& result, results) {
    int i = lexical_cast<int>(result);
    if (i < min) {
      min = i;
      masterSeq = result;
    }
  }

  // No master present (lost or possibly hasn't come up yet).
  if (masterSeq.empty()) {
    process::post(pid, NO_MASTER_DETECTED);
  } else if (masterSeq != currentMasterSeq) {
    currentMasterSeq = masterSeq;
    currentMasterPID = lookupMasterPID(masterSeq);

    // While trying to get the master PID, master might have crashed,
    // so PID might be empty.
    if (currentMasterPID == UPID()) {
      process::post(pid, NO_MASTER_DETECTED);
    } else {
      MSG<NEW_MASTER_DETECTED> msg;
      msg.set_pid(currentMasterPID);
      MesosProcess<class T>::post(pid, msg);
    }
  }
}

UPID ZooKeeperMasterDetector::lookupMasterPID(const string& seq) const
{
  CHECK(!seq.empty());

  int ret;
  string result;

  ret = zk->get(znode + "/" + seq, false, &result, NULL);

  if (ret != ZOK) {
    LOG(ERROR) << "Master detector failed to fetch new master pid: "
	       << zk->error(ret);
  } else {
    LOG(INFO) << "Master detector got new master pid: " << result;
  }

  return result;
}

#endif // WITH_ZOOKEEPER
<commit_msg>Minor formating tweak.<commit_after>#include <process.hpp>

#include <vector>

#include <glog/logging.h>

#include <boost/lexical_cast.hpp>

#include "config/config.hpp"

#include "common/fatal.hpp"
#include "common/foreach.hpp"
#ifdef WITH_ZOOKEEPER
#include "common/zookeeper.hpp"
#endif

#include "messaging/messages.hpp"

#include "detector.hpp"
#include "url_processor.hpp"

using namespace mesos;
using namespace mesos::internal;

using boost::lexical_cast;

using process::Process;
using process::UPID;

using std::pair;
using std::string;
using std::vector;

#ifdef WITH_ZOOKEEPER
class ZooKeeperMasterDetector : public MasterDetector, public Watcher
{
public:
  /**
   * Uses ZooKeeper for both detecting masters and contending to be a
   * master.
   *
   * @param server comma separated list of server host:port pairs
   *
   * @param znode top-level "ZooKeeper node" (directory) to use
   * @param pid libprocess pid to send messages/updates to (and to
   * use for contending to be a master)
   * @param contend true if should contend to be master (not needed
   * for slaves and frameworks)
   * @param quiet verbosity logging level for undelying ZooKeeper library
   */
  ZooKeeperMasterDetector(const string& servers,
			  const string& znode,
			  const UPID& pid,
			  bool contend = false,
			  bool quiet = false);

  virtual ~ZooKeeperMasterDetector();

  /**
   * ZooKeeper watcher callback.
   */
  virtual void process(ZooKeeper *zk, int type, int state, const string &path);

private:
  void connected();
  void reconnecting();
  void reconnected();
  void expired();
  void updated(const string& path);

  /**
   * @param s sequence id
   */
  void setId(const string &s);

  /**
   * @return current sequence id if contending to be a master
   */
  string getId();

  /**
   * Attempts to detect a master.
   */
  void detectMaster();

  /**
   * @param seq sequence id of a master
   * @return PID corresponding to a master
   */
  UPID lookupMasterPID(const string &seq) const;

  const string servers;
  const string znode;
  const UPID pid;
  bool contend;
  bool reconnect;

  ZooKeeper *zk;

  // Our sequence string if contending to be a master.
  string mySeq;

  string currentMasterSeq;
  UPID currentMasterPID;
};
#endif // WITH_ZOOKEEPER

MasterDetector::~MasterDetector() {}

MasterDetector* MasterDetector::create(const string &url,
                                       const UPID &pid,
                                       bool contend,
                                       bool quiet)
{
  if (url == "")
    if (contend) {
      return new BasicMasterDetector(pid);
    } else {
      fatal("cannot use specified url to detect master");
    }

  MasterDetector *detector = NULL;

  // Parse the url.
  pair<UrlProcessor::URLType, string> urlPair = UrlProcessor::process(url);

  switch (urlPair.first) {
    // ZooKeeper URL.
    case UrlProcessor::ZOO: {
#ifdef WITH_ZOOKEEPER
      // TODO(benh): Consider actually using the chroot feature of
      // ZooKeeper, rather than just using it's syntax.
      size_t index = urlPair.second.find("/");
      if (index == string::npos) {
	fatal("expecting chroot path for ZooKeeper");
      }

      const string &servers = urlPair.second.substr(0, index);

      const string &znode = urlPair.second.substr(index);
      if (znode == "/") {
	fatal("expecting chroot path for ZooKeeper ('/' is not supported)");
      }

      detector = new ZooKeeperMasterDetector(servers, znode, pid, contend, quiet);
#else
      fatal("Cannot detect masters with 'zoo://', "
            "ZooKeeper is not supported in this build");
#endif // WITH_ZOOKEEPER
      break;
    }

    // Mesos URL or libprocess pid.
    case UrlProcessor::MESOS:
    case UrlProcessor::UNKNOWN: {
      if (contend) {
	// TODO(benh): Wierdnesses like this makes it seem like there
	// should be a separate elector and detector. In particular,
	// it doesn't make sense to pass a libprocess pid and attempt
	// to contend (at least not right now).
	fatal("cannot contend to be a master with specified url");
      } else {
	UPID master(urlPair.second);
	if (!master)
	  fatal("cannot use specified url to detect master");
	detector = new BasicMasterDetector(master, pid);
      }
      break;
    }
  }

  return detector;
}

void MasterDetector::destroy(MasterDetector *detector)
{
  if (detector != NULL)
    delete detector;
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master)
  : master(_master)
{
  // Send a master token.
  {
    MSG<GOT_MASTER_TOKEN> msg;
    msg.set_token("0");
    MesosProcess<class T>::post(master, msg);
  }

  // Elect the master.
  {
    MSG<NEW_MASTER_DETECTED> msg;
    msg.set_pid(master);
    MesosProcess<class T>::post(master, msg);
  }
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const UPID& pid,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Send a master token.
    {
      MSG<GOT_MASTER_TOKEN> msg;
      msg.set_token("0");
      MesosProcess<class T>::post(master, msg);
    }

    // Elect the master.
    {
      MSG<NEW_MASTER_DETECTED> msg;
      msg.set_pid(master);
      MesosProcess<class T>::post(master, msg);
    }
  }

  // Tell the pid about the master.
  MSG<NEW_MASTER_DETECTED> msg;
  msg.set_pid(master);
  MesosProcess<class T>::post(pid, msg);
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const vector<UPID>& pids,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Send a master token.
    {
      MSG<GOT_MASTER_TOKEN> msg;
      msg.set_token("0");
      MesosProcess<class T>::post(master, msg);
    }

    // Elect the master.
    {
      MSG<NEW_MASTER_DETECTED> msg;
      msg.set_pid(master);
      MesosProcess<class T>::post(master, msg);
    }
  }

  // Tell each pid about the master.
  foreach (const UPID& pid, pids) {
    MSG<NEW_MASTER_DETECTED> msg;
    msg.set_pid(master);
    MesosProcess<class T>::post(pid, msg);
  }
}

BasicMasterDetector::~BasicMasterDetector() {}

#ifdef WITH_ZOOKEEPER
ZooKeeperMasterDetector::ZooKeeperMasterDetector(const string& servers,
						 const string& znode,
						 const UPID& pid,
						 bool contend,
						 bool quiet)
  : servers(servers), znode(znode), pid(pid),
    contend(contend), reconnect(false)
{
  // Set verbosity level for underlying ZooKeeper library logging.
  // TODO(benh): Put this in the C++ API.
  zoo_set_debug_level(quiet ? ZOO_LOG_LEVEL_ERROR : ZOO_LOG_LEVEL_DEBUG);

  // Start up the ZooKeeper connection!
  zk = new ZooKeeper(servers, 10000, this);
}

ZooKeeperMasterDetector::~ZooKeeperMasterDetector()
{
  if (zk != NULL) {
    delete zk;
  }
}

void ZooKeeperMasterDetector::connected()
{
  LOG(INFO) << "Master detector connected to ZooKeeper ...";

  int ret;
  string result;

  static const string delimiter = "/";

  // Assume the znode that was created does not end with a "/".
  CHECK(znode.at(znode.length() - 1) != '/');

  // Create directory path znodes as necessary.
  size_t index = znode.find(delimiter, 0);

  while (index < string::npos) {
    // Get out the prefix to create.
    index = znode.find(delimiter, index + 1);
    string prefix = znode.substr(0, index);

    LOG(INFO) << "Trying to create znode '" << prefix << "' in ZooKeeper";

    // Create the node (even if it already exists).
    ret = zk->create(prefix, "", ZOO_OPEN_ACL_UNSAFE,
		     // ZOO_CREATOR_ALL_ACL, // needs authentication
		     0, &result);

    if (ret != ZOK && ret != ZNODEEXISTS) {
      fatal("failed to create ZooKeeper znode! (%s)", zk->error(ret));
    }
  }

  // Wierdness in ZooKeeper timing, let's check that everything is created.
  ret = zk->get(znode, false, &result, NULL);

  if (ret != ZOK) {
    fatal("ZooKeeper not responding correctly (%s). "
	  "Make sure ZooKeeper is running on: %s",
	  zk->error(ret), servers.c_str());
  }

  if (contend) {
    // We contend with the pid given in constructor.
    ret = zk->create(znode + "/", pid, ZOO_OPEN_ACL_UNSAFE,
		     // ZOO_CREATOR_ALL_ACL, // needs authentication
		     ZOO_SEQUENCE | ZOO_EPHEMERAL, &result);

    if (ret != ZOK) {
      fatal("ZooKeeper not responding correctly (%s). "
	    "Make sure ZooKeeper is running on: %s",
	    zk->error(ret), servers.c_str());
    }

    setId(result);
    LOG(INFO) << "Created ephemeral/sequence:" << getId();

    MSG<GOT_MASTER_TOKEN> msg;
    msg.set_token(getId());
    MesosProcess<class T>::post(pid, msg);
  }

  // Now determine who the master is (it may be us).
  detectMaster();
}

void ZooKeeperMasterDetector::reconnecting()
{
  LOG(INFO) << "Master detector lost connection to ZooKeeper, "
	    << "attempting to reconnect ...";
}

void ZooKeeperMasterDetector::reconnected()
{
  LOG(INFO) << "Master detector reconnected ...";

  int ret;
  string result;

  static const string delimiter = "/";

  if (contend) {
    // Contending for master, confirm our ephemeral sequence znode exists.
    ret = zk->get(znode + "/" + mySeq, false, &result, NULL);

    // We might no longer be the master! Commit suicide for now
    // (hoping another master is on standbye), but in the future
    // it would be nice if we could go back on standbye.
    if (ret == ZNONODE) {
      fatal("failed to reconnect to ZooKeeper quickly enough "
	    "(our ephemeral sequence znode is gone), commiting suicide!");
    }

    if (ret != ZOK) {
      fatal("ZooKeeper not responding correctly (%s). "
	    "Make sure ZooKeeper is running on: %s",
	    zk->error(ret), servers.c_str());
    }

    // We are still the master!
    LOG(INFO) << "Still acting as master";
  } else {
    // Reconnected, but maybe the master changed?
    detectMaster();
  }
}

void ZooKeeperMasterDetector::expired()
{
  LOG(WARNING) << "Master detector ZooKeeper session expired!";

  CHECK(zk != NULL);
  delete zk;

  zk = new ZooKeeper(servers, 10000, this);
}

void ZooKeeperMasterDetector::updated(const string& path)
{
  // A new master might have showed up and created a sequence
  // identifier or a master may have died, determine who the master is now!
  detectMaster();
}

void ZooKeeperMasterDetector::process(ZooKeeper* zk, int type, int state,
				      const string& path)
{
  if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_SESSION_EVENT)) {
    // Check if this is a reconnect.
    if (!reconnect) {
      // Initial connect.
      connected();
    } else {
      // Reconnected.
      reconnected();
    }
  } else if ((state == ZOO_CONNECTING_STATE) && (type == ZOO_SESSION_EVENT)) {
    // The client library automatically reconnects, taking into
    // account failed servers in the connection string,
    // appropriately handling the "herd effect", etc.
    reconnect = true;
    reconnecting();
  } else if ((state == ZOO_EXPIRED_SESSION_STATE) && (type == ZOO_SESSION_EVENT)) {
    // Session expiration. Let the manager take care of it.
    expired();

    // If this watcher is reused, the next connect won't be a reconnect.
    reconnect = false;
  } else if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_CHILD_EVENT)) {
    updated(path);
  } else if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_CHANGED_EVENT)) {
    updated(path);
  } else {
    LOG(WARNING) << "Unimplemented watch event: (state is "
		 << state << " and type is " << type << ")";
  }
}

void ZooKeeperMasterDetector::setId(const string& s)
{
  string seq = s;
  // Converts "/path/to/znode/000000131" to "000000131".
  int pos;
  if ((pos = seq.find_last_of('/')) != string::npos) {
    mySeq = seq.erase(0, pos + 1);
  } else
    mySeq = "";
}

string ZooKeeperMasterDetector::getId()
{
  return mySeq;
}

void ZooKeeperMasterDetector::detectMaster()
{
  vector<string> results;

  int ret = zk->getChildren(znode, true, &results);

  if (ret != ZOK) {
    LOG(ERROR) << "Master detector failed to get masters: "
	       << zk->error(ret);
  } else {
    LOG(INFO) << "Master detector found " << results.size()
	      << " registered masters";
  }

  string masterSeq;
  long min = LONG_MAX;
  foreach (const string& result, results) {
    int i = lexical_cast<int>(result);
    if (i < min) {
      min = i;
      masterSeq = result;
    }
  }

  // No master present (lost or possibly hasn't come up yet).
  if (masterSeq.empty()) {
    process::post(pid, NO_MASTER_DETECTED);
  } else if (masterSeq != currentMasterSeq) {
    currentMasterSeq = masterSeq;
    currentMasterPID = lookupMasterPID(masterSeq);

    // While trying to get the master PID, master might have crashed,
    // so PID might be empty.
    if (currentMasterPID == UPID()) {
      process::post(pid, NO_MASTER_DETECTED);
    } else {
      MSG<NEW_MASTER_DETECTED> msg;
      msg.set_pid(currentMasterPID);
      MesosProcess<class T>::post(pid, msg);
    }
  }
}

UPID ZooKeeperMasterDetector::lookupMasterPID(const string& seq) const
{
  CHECK(!seq.empty());

  int ret;
  string result;

  ret = zk->get(znode + "/" + seq, false, &result, NULL);

  if (ret != ZOK) {
    LOG(ERROR) << "Master detector failed to fetch new master pid: "
	       << zk->error(ret);
  } else {
    LOG(INFO) << "Master detector got new master pid: " << result;
  }

  return result;
}

#endif // WITH_ZOOKEEPER
<|endoftext|>


<commit_before>/* $Id$ */

/* @file
 * Emulation of the Tsunami CChip CSRs
 */

#include <deque>
#include <string>
#include <vector>

#include "base/trace.hh"
#include "cpu/exec_context.hh"
#include "dev/console.hh"
#include "dev/tsunami_cchip.hh"
#include "dev/tsunamireg.h"
#include "dev/tsunami.hh"
#include "cpu/intr_control.hh"
#include "mem/functional_mem/memory_control.hh"
#include "sim/builder.hh"
#include "sim/system.hh"

using namespace std;

TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
                           MemoryController *mmu)
    : FunctionalMemory(name), addr(a), tsunami(t)
{
    mmu->add_child(this, Range<Addr>(addr, addr + size));

    for(int i=0; i < Tsunami::Max_CPUs; i++) {
        dim[i] = 0;
        dir[i] = 0;
        dirInterrupting[i] = false;
    }

    drir = 0;
    misc = 0;
    RTCInterrupting = false;

    //Put back pointer in tsunami
    tsunami->cchip = this;
}

Fault
TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
{
    DPRINTF(Tsunami, "read  va=%#x size=%d\n",
            req->vaddr, req->size);

    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
    ExecContext *xc = req->xc;

    switch (req->size) {

      case sizeof(uint64_t):
          switch(daddr) {
              case TSDEV_CC_CSR:
                  *(uint64_t*)data = 0x0;
                  return No_Fault;
              case TSDEV_CC_MTR:
                  panic("TSDEV_CC_MTR not implemeted\n");
                   return No_Fault;
              case TSDEV_CC_MISC:
                *(uint64_t*)data = misc | (xc->cpu_id & 0x3);
                  return No_Fault;
              case TSDEV_CC_AAR0:
              case TSDEV_CC_AAR1:
              case TSDEV_CC_AAR2:
              case TSDEV_CC_AAR3:
                  panic("TSDEV_CC_AARx not implemeted\n");
                  return No_Fault;
              case TSDEV_CC_DIM0:
                  *(uint64_t*)data = dim[0];
                  return No_Fault;
              case TSDEV_CC_DIM1:
                  *(uint64_t*)data = dim[1];
                  return No_Fault;
              case TSDEV_CC_DIM2:
                  *(uint64_t*)data = dim[2];
                  return No_Fault;
              case TSDEV_CC_DIM3:
                  *(uint64_t*)data = dim[3];
                  return No_Fault;
              case TSDEV_CC_DIR0:
                  *(uint64_t*)data = dir[0];
                  return No_Fault;
              case TSDEV_CC_DIR1:
                  *(uint64_t*)data = dir[1];
                  return No_Fault;
              case TSDEV_CC_DIR2:
                  *(uint64_t*)data = dir[2];
                  return No_Fault;
              case TSDEV_CC_DIR3:
                  *(uint64_t*)data = dir[3];
                  return No_Fault;
              case TSDEV_CC_DRIR:
                  *(uint64_t*)data = drir;
                  return No_Fault;
              case TSDEV_CC_PRBEN:
                  panic("TSDEV_CC_PRBEN not implemented\n");
                  return No_Fault;
              case TSDEV_CC_IIC0:
              case TSDEV_CC_IIC1:
              case TSDEV_CC_IIC2:
              case TSDEV_CC_IIC3:
                  panic("TSDEV_CC_IICx not implemented\n");
                  return No_Fault;
              case TSDEV_CC_MPR0:
              case TSDEV_CC_MPR1:
              case TSDEV_CC_MPR2:
              case TSDEV_CC_MPR3:
                  panic("TSDEV_CC_MPRx not implemented\n");
                  return No_Fault;
              default:
                  panic("default in cchip read reached, accessing 0x%x\n");
           } // uint64_t

      break;
      case sizeof(uint32_t):
      case sizeof(uint16_t):
      case sizeof(uint8_t):
      default:
        panic("invalid access size(?) for tsunami register!\n");
    }
    DPRINTFN("Tsunami CChip ERROR: read  daddr=%#x size=%d\n", daddr, req->size);

    return No_Fault;
}

Fault
TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
{
    DPRINTF(Tsunami, "write - va=%#x size=%d \n",
            req->vaddr, req->size);

    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
    uint64_t olddim;

    switch (req->size) {

      case sizeof(uint64_t):
          switch(daddr) {
              case TSDEV_CC_CSR:
                  panic("TSDEV_CC_CSR write\n");
                  return No_Fault;
              case TSDEV_CC_MTR:
                  panic("TSDEV_CC_MTR write not implemented\n");
                   return No_Fault;
              case TSDEV_CC_MISC:
                //If it is the seventh bit, clear the RTC interrupt
                if ((*(uint64_t*) data) & (1<<4)) {
                    RTCInterrupting = false;
                    tsunami->intrctrl->clear(0, TheISA::INTLEVEL_IRQ2, 0);
                    DPRINTF(Tsunami, "clearing rtc interrupt\n");
                    misc &= ~(1<<4);
                } else panic("TSDEV_CC_MISC write not implemented\n");
                  return No_Fault;
              case TSDEV_CC_AAR0:
              case TSDEV_CC_AAR1:
              case TSDEV_CC_AAR2:
              case TSDEV_CC_AAR3:
                  panic("TSDEV_CC_AARx write not implemeted\n");
                  return No_Fault;
              case TSDEV_CC_DIM0:
              case TSDEV_CC_DIM1:
              case TSDEV_CC_DIM2:
              case TSDEV_CC_DIM3:
                  int number;
                  if(daddr == TSDEV_CC_DIM0)
                      number = 0;
                  else if(daddr == TSDEV_CC_DIM1)
                      number = 1;
                  else if(daddr == TSDEV_CC_DIM2)
                      number = 2;
                  else
                      number = 3;

                  olddim = dim[number];
                  dim[number] = *(uint64_t*)data;
                  dir[number] = dim[number] & drir;
                  uint64_t bitvector;
                  for(int x = 0; x < 64; x++)
                  {
                      bitvector = 1 << x;
                      // Figure out which bits have changed
                      if ((dim[number] & bitvector) != (olddim & bitvector))
                      {
                          // The bit is now set and it wasn't before (set)
                          if((dim[number] & bitvector) && (dir[number] & bitvector))
                          {
                              tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ0, x);
                              DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
                          }
                          else if (!(dir[number] & bitvector))
                          {
                              // The bit was set and now its now clear and
                              // we were interrupting on that bit before
                              tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ0, x);
                              DPRINTF(Tsunami, "dim write resulting in clear"
                                      "dir interrupt to cpu 0\n");

                          }

                      }
                  }
                  return No_Fault;
              case TSDEV_CC_DIR0:
              case TSDEV_CC_DIR1:
              case TSDEV_CC_DIR2:
              case TSDEV_CC_DIR3:
                  panic("TSDEV_CC_DIR write not implemented\n");
              case TSDEV_CC_DRIR:
                  panic("TSDEV_CC_DRIR write not implemented\n");
              case TSDEV_CC_PRBEN:
                  panic("TSDEV_CC_PRBEN write not implemented\n");
              case TSDEV_CC_IIC0:
              case TSDEV_CC_IIC1:
              case TSDEV_CC_IIC2:
              case TSDEV_CC_IIC3:
                  panic("TSDEV_CC_IICx write not implemented\n");
              case TSDEV_CC_MPR0:
              case TSDEV_CC_MPR1:
              case TSDEV_CC_MPR2:
              case TSDEV_CC_MPR3:
                  panic("TSDEV_CC_MPRx write not implemented\n");
              default:
                  panic("default in cchip read reached, accessing 0x%x\n");
          }

      break;
      case sizeof(uint32_t):
      case sizeof(uint16_t):
      case sizeof(uint8_t):
      default:
        panic("invalid access size(?) for tsunami register!\n");
    }

    DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);

    return No_Fault;
}

void
TsunamiCChip::postDRIR(uint32_t interrupt)
{
    uint64_t bitvector = 0x1 << interrupt;
    drir |= bitvector;
    for(int i=0; i < Tsunami::Max_CPUs; i++) {
        dir[i] = dim[i] & drir;
        if (dim[i] & bitvector) {
                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ0, interrupt);
                DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
                        "interrupt %d\n",i, interrupt);
        }
    }
}

void
TsunamiCChip::clearDRIR(uint32_t interrupt)
{
    uint64_t bitvector = 0x1 << interrupt;
    if (drir & bitvector)
    {
        drir &= ~bitvector;
        for(int i=0; i < Tsunami::Max_CPUs; i++) {
            if (dir[i] & bitvector) {
                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ0, interrupt);
                DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
                    "interrupt %d\n",i, interrupt);

            }
            dir[i] = dim[i] & drir;
        }
    }
    else
        DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
}

void
TsunamiCChip::serialize(std::ostream &os)
{
    SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
    SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
    SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
    SERIALIZE_SCALAR(drir);
    SERIALIZE_SCALAR(misc);
    SERIALIZE_SCALAR(RTCInterrupting);
}

void
TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
{
    UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
    UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
    UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
    UNSERIALIZE_SCALAR(drir);
    UNSERIALIZE_SCALAR(misc);
    UNSERIALIZE_SCALAR(RTCInterrupting);
}

BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)

    SimObjectParam<Tsunami *> tsunami;
    SimObjectParam<MemoryController *> mmu;
    Param<Addr> addr;

END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)

BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)

    INIT_PARAM(tsunami, "Tsunami"),
    INIT_PARAM(mmu, "Memory Controller"),
    INIT_PARAM(addr, "Device Address")

END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)

CREATE_SIM_OBJECT(TsunamiCChip)
{
    return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu);
}

REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
<commit_msg>Changed device IRQ back to 1<commit_after>/* $Id$ */

/* @file
 * Emulation of the Tsunami CChip CSRs
 */

#include <deque>
#include <string>
#include <vector>

#include "base/trace.hh"
#include "cpu/exec_context.hh"
#include "dev/console.hh"
#include "dev/tsunami_cchip.hh"
#include "dev/tsunamireg.h"
#include "dev/tsunami.hh"
#include "cpu/intr_control.hh"
#include "mem/functional_mem/memory_control.hh"
#include "sim/builder.hh"
#include "sim/system.hh"

using namespace std;

TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
                           MemoryController *mmu)
    : FunctionalMemory(name), addr(a), tsunami(t)
{
    mmu->add_child(this, Range<Addr>(addr, addr + size));

    for(int i=0; i < Tsunami::Max_CPUs; i++) {
        dim[i] = 0;
        dir[i] = 0;
        dirInterrupting[i] = false;
    }

    drir = 0;
    misc = 0;
    RTCInterrupting = false;

    //Put back pointer in tsunami
    tsunami->cchip = this;
}

Fault
TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
{
    DPRINTF(Tsunami, "read  va=%#x size=%d\n",
            req->vaddr, req->size);

    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
    ExecContext *xc = req->xc;

    switch (req->size) {

      case sizeof(uint64_t):
          switch(daddr) {
              case TSDEV_CC_CSR:
                  *(uint64_t*)data = 0x0;
                  return No_Fault;
              case TSDEV_CC_MTR:
                  panic("TSDEV_CC_MTR not implemeted\n");
                   return No_Fault;
              case TSDEV_CC_MISC:
                *(uint64_t*)data = misc | (xc->cpu_id & 0x3);
                  return No_Fault;
              case TSDEV_CC_AAR0:
              case TSDEV_CC_AAR1:
              case TSDEV_CC_AAR2:
              case TSDEV_CC_AAR3:
                  panic("TSDEV_CC_AARx not implemeted\n");
                  return No_Fault;
              case TSDEV_CC_DIM0:
                  *(uint64_t*)data = dim[0];
                  return No_Fault;
              case TSDEV_CC_DIM1:
                  *(uint64_t*)data = dim[1];
                  return No_Fault;
              case TSDEV_CC_DIM2:
                  *(uint64_t*)data = dim[2];
                  return No_Fault;
              case TSDEV_CC_DIM3:
                  *(uint64_t*)data = dim[3];
                  return No_Fault;
              case TSDEV_CC_DIR0:
                  *(uint64_t*)data = dir[0];
                  return No_Fault;
              case TSDEV_CC_DIR1:
                  *(uint64_t*)data = dir[1];
                  return No_Fault;
              case TSDEV_CC_DIR2:
                  *(uint64_t*)data = dir[2];
                  return No_Fault;
              case TSDEV_CC_DIR3:
                  *(uint64_t*)data = dir[3];
                  return No_Fault;
              case TSDEV_CC_DRIR:
                  *(uint64_t*)data = drir;
                  return No_Fault;
              case TSDEV_CC_PRBEN:
                  panic("TSDEV_CC_PRBEN not implemented\n");
                  return No_Fault;
              case TSDEV_CC_IIC0:
              case TSDEV_CC_IIC1:
              case TSDEV_CC_IIC2:
              case TSDEV_CC_IIC3:
                  panic("TSDEV_CC_IICx not implemented\n");
                  return No_Fault;
              case TSDEV_CC_MPR0:
              case TSDEV_CC_MPR1:
              case TSDEV_CC_MPR2:
              case TSDEV_CC_MPR3:
                  panic("TSDEV_CC_MPRx not implemented\n");
                  return No_Fault;
              default:
                  panic("default in cchip read reached, accessing 0x%x\n");
           } // uint64_t

      break;
      case sizeof(uint32_t):
      case sizeof(uint16_t):
      case sizeof(uint8_t):
      default:
        panic("invalid access size(?) for tsunami register!\n");
    }
    DPRINTFN("Tsunami CChip ERROR: read  daddr=%#x size=%d\n", daddr, req->size);

    return No_Fault;
}

Fault
TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
{
    DPRINTF(Tsunami, "write - va=%#x size=%d \n",
            req->vaddr, req->size);

    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
    uint64_t olddim;

    switch (req->size) {

      case sizeof(uint64_t):
          switch(daddr) {
              case TSDEV_CC_CSR:
                  panic("TSDEV_CC_CSR write\n");
                  return No_Fault;
              case TSDEV_CC_MTR:
                  panic("TSDEV_CC_MTR write not implemented\n");
                   return No_Fault;
              case TSDEV_CC_MISC:
                //If it is the seventh bit, clear the RTC interrupt
                if ((*(uint64_t*) data) & (1<<4)) {
                    RTCInterrupting = false;
                    tsunami->intrctrl->clear(0, TheISA::INTLEVEL_IRQ2, 0);
                    DPRINTF(Tsunami, "clearing rtc interrupt\n");
                    misc &= ~(1<<4);
                } else panic("TSDEV_CC_MISC write not implemented\n");
                  return No_Fault;
              case TSDEV_CC_AAR0:
              case TSDEV_CC_AAR1:
              case TSDEV_CC_AAR2:
              case TSDEV_CC_AAR3:
                  panic("TSDEV_CC_AARx write not implemeted\n");
                  return No_Fault;
              case TSDEV_CC_DIM0:
              case TSDEV_CC_DIM1:
              case TSDEV_CC_DIM2:
              case TSDEV_CC_DIM3:
                  int number;
                  if(daddr == TSDEV_CC_DIM0)
                      number = 0;
                  else if(daddr == TSDEV_CC_DIM1)
                      number = 1;
                  else if(daddr == TSDEV_CC_DIM2)
                      number = 2;
                  else
                      number = 3;

                  olddim = dim[number];
                  dim[number] = *(uint64_t*)data;
                  dir[number] = dim[number] & drir;
                  uint64_t bitvector;
                  for(int x = 0; x < 64; x++)
                  {
                      bitvector = 1 << x;
                      // Figure out which bits have changed
                      if ((dim[number] & bitvector) != (olddim & bitvector))
                      {
                          // The bit is now set and it wasn't before (set)
                          if((dim[number] & bitvector) && (dir[number] & bitvector))
                          {
                              tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
                              DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
                          }
                          else if (!(dir[number] & bitvector))
                          {
                              // The bit was set and now its now clear and
                              // we were interrupting on that bit before
                              tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
                              DPRINTF(Tsunami, "dim write resulting in clear"
                                      "dir interrupt to cpu 0\n");

                          }

                      }
                  }
                  return No_Fault;
              case TSDEV_CC_DIR0:
              case TSDEV_CC_DIR1:
              case TSDEV_CC_DIR2:
              case TSDEV_CC_DIR3:
                  panic("TSDEV_CC_DIR write not implemented\n");
              case TSDEV_CC_DRIR:
                  panic("TSDEV_CC_DRIR write not implemented\n");
              case TSDEV_CC_PRBEN:
                  panic("TSDEV_CC_PRBEN write not implemented\n");
              case TSDEV_CC_IIC0:
              case TSDEV_CC_IIC1:
              case TSDEV_CC_IIC2:
              case TSDEV_CC_IIC3:
                  panic("TSDEV_CC_IICx write not implemented\n");
              case TSDEV_CC_MPR0:
              case TSDEV_CC_MPR1:
              case TSDEV_CC_MPR2:
              case TSDEV_CC_MPR3:
                  panic("TSDEV_CC_MPRx write not implemented\n");
              default:
                  panic("default in cchip read reached, accessing 0x%x\n");
          }

      break;
      case sizeof(uint32_t):
      case sizeof(uint16_t):
      case sizeof(uint8_t):
      default:
        panic("invalid access size(?) for tsunami register!\n");
    }

    DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);

    return No_Fault;
}

void
TsunamiCChip::postDRIR(uint32_t interrupt)
{
    uint64_t bitvector = 0x1 << interrupt;
    drir |= bitvector;
    for(int i=0; i < Tsunami::Max_CPUs; i++) {
        dir[i] = dim[i] & drir;
        if (dim[i] & bitvector) {
                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
                DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
                        "interrupt %d\n",i, interrupt);
        }
    }
}

void
TsunamiCChip::clearDRIR(uint32_t interrupt)
{
    uint64_t bitvector = 0x1 << interrupt;
    if (drir & bitvector)
    {
        drir &= ~bitvector;
        for(int i=0; i < Tsunami::Max_CPUs; i++) {
            if (dir[i] & bitvector) {
                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
                DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
                    "interrupt %d\n",i, interrupt);

            }
            dir[i] = dim[i] & drir;
        }
    }
    else
        DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
}

void
TsunamiCChip::serialize(std::ostream &os)
{
    SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
    SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
    SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
    SERIALIZE_SCALAR(drir);
    SERIALIZE_SCALAR(misc);
    SERIALIZE_SCALAR(RTCInterrupting);
}

void
TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
{
    UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
    UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
    UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
    UNSERIALIZE_SCALAR(drir);
    UNSERIALIZE_SCALAR(misc);
    UNSERIALIZE_SCALAR(RTCInterrupting);
}

BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)

    SimObjectParam<Tsunami *> tsunami;
    SimObjectParam<MemoryController *> mmu;
    Param<Addr> addr;

END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)

BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)

    INIT_PARAM(tsunami, "Tsunami"),
    INIT_PARAM(mmu, "Memory Controller"),
    INIT_PARAM(addr, "Device Address")

END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)

CREATE_SIM_OBJECT(TsunamiCChip)
{
    return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu);
}

REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
<|endoftext|>


<commit_before>#pragma once

#include <cstdlib>
#include <cstdio>

#ifdef __GNUC__
#define DUKE_LIKELY(x)   (__builtin_expect((x), 1))
#define DUKE_UNLIKELY(x) (__builtin_expect((x), 0))
#else
#define DUKE_LIKELY(x)   (x)
#define DUKE_UNLIKELY(x) (x)
#endif

#define TRACE_MSG(X) fprintf(stderr, \
                             "CHECK FAILED '"#X"' in %s() [%s:%d]\n", \
                             __func__, \
                             __FILE__, \
                             __LINE__)
#define CHECK(X) if(DUKE_UNLIKELY(!(X))) { TRACE_MSG(X); abort(); }
<commit_msg>Improve CHECK function<commit_after>#pragma once

#include <cstdlib>
#include <cstdio>
#include <sstream>

#ifdef __GNUC__
#define DUKE_LIKELY(x)   (__builtin_expect((x), 1))
#define DUKE_UNLIKELY(x) (__builtin_expect((x), 0))
#else
#define DUKE_LIKELY(x)   (x)
#define DUKE_UNLIKELY(x) (x)
#endif

#define TRACE_MSG(X) fprintf(stderr, \
                             "CHECK FAILED '"#X"' in %s() [%s:%d]\n", \
                             __func__, \
                             __FILE__, \
                             __LINE__)

struct Tracer {
	Tracer(const char* cond, const char* func, const char* file,
			const int line) {
		msg << "CHECK FAILED '" << cond << "' in " << func << "() [" << file << ":" << line << "] ";
	}
	std::ostream& getStream() {
		return msg;
	}
	~Tracer() {
		fprintf(stderr, "%s\n", msg.str().c_str());
		abort();
	}
private:
	std::ostringstream msg;
};

#define CHECK(X) if(DUKE_UNLIKELY(!(X))) Tracer(#X,__func__, __FILE__, __LINE__).getStream()
<|endoftext|>


<commit_before>#ifndef ENTT_META_RANGE_HPP
#define ENTT_META_RANGE_HPP

#include "internal.hpp"

namespace entt {

/**
 * @brief Iterable range to use to iterate all types of meta objects.
 * @tparam Type Type of meta objects iterated.
 */
template<typename Type>
class meta_range {
    struct range_iterator {
        using difference_type = std::ptrdiff_t;
        using value_type = Type;
        using pointer = void;
        using reference = value_type;
        using iterator_category = std::input_iterator_tag;
        using node_type = typename Type::node_type;

        range_iterator() ENTT_NOEXCEPT = default;

        range_iterator(node_type *head) ENTT_NOEXCEPT
            : it{head}
        {}

        range_iterator & operator++() ENTT_NOEXCEPT {
            return ++it, *this;
        }

        range_iterator operator++(int) ENTT_NOEXCEPT {
            range_iterator orig = *this;
            return ++(*this), orig;
        }

        [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
            return it.operator->();
        }

        [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
            return other.it == it;
        }

        [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
            return !(*this == other);
        }

    private:
        typename internal::meta_range<node_type>::iterator it{};
    };

public:
    /*! @brief Node type. */
    using node_type = typename Type::node_type;
    /*! @brief Input iterator type. */
    using iterator = range_iterator;

    /*! @brief Default constructor. */
    meta_range() ENTT_NOEXCEPT = default;

    /**
     * @brief Constructs a meta range from a given node.
     * @param head The underlying node with which to construct the range.
     */
    meta_range(node_type *head)
        : node{head}
    {}

    /**
     * @brief Returns an iterator to the beginning.
     * @return An iterator to the first meta object of the range.
     */
    [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
        return iterator{node};
    }

    /**
     * @brief Returns an iterator to the end.
     * @return An iterator to the element following the last meta object of the
     * range.
     */
    [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
        return iterator{};
    }

private:
    node_type *node{nullptr};
};

}

#endif
<commit_msg>meta_range: minor changes<commit_after>#ifndef ENTT_META_RANGE_HPP
#define ENTT_META_RANGE_HPP

#include <cstddef>
#include <iterator>
#include "internal.hpp"

namespace entt {

/**
 * @brief Iterable range to use to iterate all types of meta objects.
 * @tparam Type Type of meta objects iterated.
 */
template<typename Type>
class meta_range {
    struct range_iterator {
        using difference_type = std::ptrdiff_t;
        using value_type = Type;
        using pointer = void;
        using reference = value_type;
        using iterator_category = std::input_iterator_tag;
        using node_type = typename Type::node_type;

        range_iterator() ENTT_NOEXCEPT = default;

        range_iterator(node_type *head) ENTT_NOEXCEPT
            : it{head}
        {}

        range_iterator & operator++() ENTT_NOEXCEPT {
            return ++it, *this;
        }

        range_iterator operator++(int) ENTT_NOEXCEPT {
            range_iterator orig = *this;
            return ++(*this), orig;
        }

        [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
            return it.operator->();
        }

        [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
            return other.it == it;
        }

        [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
            return !(*this == other);
        }

    private:
        typename internal::meta_range<node_type>::iterator it{};
    };

public:
    /*! @brief Node type. */
    using node_type = typename Type::node_type;
    /*! @brief Input iterator type. */
    using iterator = range_iterator;

    /*! @brief Default constructor. */
    meta_range() ENTT_NOEXCEPT = default;

    /**
     * @brief Constructs a meta range from a given node.
     * @param head The underlying node with which to construct the range.
     */
    meta_range(node_type *head)
        : node{head}
    {}

    /**
     * @brief Returns an iterator to the beginning.
     * @return An iterator to the first meta object of the range.
     */
    [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
        return iterator{node};
    }

    /**
     * @brief Returns an iterator to the end.
     * @return An iterator to the element following the last meta object of the
     * range.
     */
    [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
        return iterator{};
    }

private:
    node_type *node{nullptr};
};

}

#endif
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Laura Schlimmer <laura@eventql.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 <iostream>
#include <unistd.h>
#include "eventql/eventql.h"
#include "eventql/util/application.h"
#include "eventql/util/io/inputstream.h"
#include "eventql/util/io/TerminalOutputStream.h"
#include "eventql/util/cli/flagparser.h"
#include "eventql/cli/benchmark.h"

int main(int argc, const char** argv) {
  cli::FlagParser flags;

  flags.defineFlag(
      "host",
      cli::FlagParser::T_STRING,
      false,
      "h",
      "localhost",
      "eventql server hostname",
      "<host>");

  flags.defineFlag(
      "port",
      cli::FlagParser::T_INTEGER,
      false,
      "p",
      "9175",
      "eventql server port",
      "<port>");

  flags.defineFlag(
      "database",
      cli::FlagParser::T_STRING,
      false,
      "d",
      NULL,
      "database",
      "<db>");

  flags.defineFlag(
      "user",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "username",
      "<user>");

  flags.defineFlag(
      "password",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "password",
      "<password>");

  flags.defineFlag(
      "auth_token",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "auth token",
      "<auth_token>");

  flags.defineFlag(
      "connections",
      cli::FlagParser::T_INTEGER,
      false,
      "c",
      "10",
      "number of connections",
      "<threads>");

  flags.defineFlag(
      "rate",
      cli::FlagParser::T_INTEGER,
      false,
      "r",
      "1",
      "number of requests per second",
      "<rate>");

  flags.defineFlag(
      "num",
      cli::FlagParser::T_INTEGER,
      false,
      "n",
      NULL,
      "total number of request (inifite if unset)",
      "<rate>");

  flags.defineFlag(
      "help",
      cli::FlagParser::T_SWITCH,
      false,
      "?",
      NULL,
      "help",
      "<help>");

  flags.defineFlag(
      "version",
      cli::FlagParser::T_SWITCH,
      false,
      "v",
      NULL,
      "print version",
      "<switch>");

  Application::init();
  auto stdout_os = TerminalOutputStream::fromStream(OutputStream::getStdout());

  try {
    flags.parseArgv(argc, argv);
  } catch (const std::exception& e) {
    std::cerr << StringUtil::format("ERROR: $0\n", e.what());
    return 1;
  }

  Vector<String> cmd_argv = flags.getArgv();
  bool print_help = flags.isSet("help");
  bool print_version = flags.isSet("version");
  if (print_version || print_help) {
    stdout_os->print(
        StringUtil::format(
            "EventQL $0 ($1)\n"
            "Copyright (c) 2016, DeepCortex GmbH. All rights reserved.\n\n",
            eventql::kVersionString,
            eventql::kBuildID));
  }

  if (print_version) {
    return 1;
  }

  if (print_help) {
    stdout_os->print(
        "Usage: $ evqlslap [OPTIONS]\n\n"
        "   -h, --host <hostname>     Set the EventQL server hostname\n"
        "   -p, --port <port>         Set the EventQL server port\n"
        "   -d, --database <db>       Select a database\n"
        "   --user <user>             Set the EventQL username\n"
        "   --password <password>     Set the password\n"
        "   --auth_token <token>      Set the EventQL auth token\n"
        "   -c, --connections <num>   Number of concurrent connections\n"
        "   -r, --rate <rate>         Maximum rate of requests in RPS\n"
        "   -n, --num <num>           Maximum total number of request (default is inifite)\n"
        "   -?, --help                Display the help text and exit\n"
        "   -v, --version             Display the version of this binary and exit\n");

    return 1;
  }

  std::vector<std::pair<std::string, std::string>> auth_data;
  if (flags.isSet("auth_token")) {
    auth_data.emplace_back("auth_token", flags.getString("auth_token"));
  }

  if (flags.isSet("user")) {
    auth_data.emplace_back("user", flags.getString("user"));
  }

  if (flags.isSet("password")) {
    auth_data.emplace_back("password", flags.getString("password"));
  }

  auto request_handler = []() {
    usleep(1000);
    return ReturnCode::success();
  };

  auto on_progress = [&stdout_os](eventql::cli::BenchmarkStats* stats) {
    try {
      stdout_os->eraseLine();
      stdout_os->print(StringUtil::format(
          "\rRunning... rate=$0r/s, avg_runtime=$1ms, total=$2, running=$3, "
          "errors=$4 ($5%)",
          stats->getRollingRPS(),
          stats->getRollingAverageRuntime() / double(kMicrosPerMilli),
          stats->getTotalRequestCount(),
          stats->getRunningRequestCount(),
          stats->getTotalErrorCount(),
          stats->getTotalErrorRate() * 100.0f));
    } catch (const std::exception& e) {
      /* fallthrough */
    }
  };

  eventql::cli::Benchmark benchmark(
      flags.getInt("connections"),
      flags.getInt("rate"),
      flags.isSet("num") ? flags.getInt("num") : -1);

  benchmark.setRequestHandler(request_handler);
  benchmark.setProgressCallback(on_progress);
  benchmark.setProgressRateLimit(kMicrosPerSecond / 10);

  auto rc = benchmark.connect(
      flags.getString("host"),
      flags.getInt("port"),
      auth_data);

  if (rc.isSuccess()) {
    rc = benchmark.run();
  }

  stdout_os->eraseLine();

  if (rc.isSuccess()) {
    std::cout << "success" << std::endl;
    return 0;
  } else {
    std::cerr << "ERROR: " << rc.getMessage() << std::endl;
    return 1;
  }

  return 0;
}

<commit_msg>add --batch, --mode, --payload, --table flags<commit_after>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Laura Schlimmer <laura@eventql.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 <iostream>
#include <unistd.h>
#include "eventql/eventql.h"
#include "eventql/util/application.h"
#include "eventql/util/io/inputstream.h"
#include "eventql/util/io/TerminalOutputStream.h"
#include "eventql/util/cli/flagparser.h"
#include "eventql/cli/benchmark.h"

int main(int argc, const char** argv) {
  cli::FlagParser flags;

  flags.defineFlag(
      "host",
      cli::FlagParser::T_STRING,
      false,
      "h",
      "localhost",
      "eventql server hostname",
      "<host>");

  flags.defineFlag(
      "port",
      cli::FlagParser::T_INTEGER,
      false,
      "p",
      "9175",
      "eventql server port",
      "<port>");

  flags.defineFlag(
      "connections",
      cli::FlagParser::T_INTEGER,
      false,
      "c",
      "10",
      "number of connections",
      "<threads>");

  flags.defineFlag(
      "rate",
      cli::FlagParser::T_INTEGER,
      false,
      "r",
      "1",
      "number of requests per second",
      "<rate>");

  flags.defineFlag(
      "batch",
      cli::FlagParser::T_INTEGER,
      false,
      "b",
      "1",
      "batch size",
      "<num>");

  flags.defineFlag(
      "num",
      cli::FlagParser::T_INTEGER,
      false,
      "n",
      NULL,
      "total number of request (inifite if unset)",
      "<rate>");

  flags.defineFlag(
      "mode",
      cli::FlagParser::T_STRING,
      false,
      "m",
      NULL,
      "mode",
      "<mode>");

  flags.defineFlag(
      "payload",
      cli::FlagParser::T_STRING,
      false,
      "x",
      NULL,
      "payload",
      "<payload>");

  flags.defineFlag(
      "database",
      cli::FlagParser::T_STRING,
      false,
      "d",
      NULL,
      "database",
      "<db>");

  flags.defineFlag(
      "table",
      cli::FlagParser::T_STRING,
      false,
      "t",
      NULL,
      "table",
      "<tbl>");

  flags.defineFlag(
      "user",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "username",
      "<user>");

  flags.defineFlag(
      "password",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "password",
      "<password>");

  flags.defineFlag(
      "auth_token",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "auth token",
      "<auth_token>");

  flags.defineFlag(
      "help",
      cli::FlagParser::T_SWITCH,
      false,
      "?",
      NULL,
      "help",
      "<help>");

  flags.defineFlag(
      "version",
      cli::FlagParser::T_SWITCH,
      false,
      "v",
      NULL,
      "print version",
      "<switch>");

  Application::init();
  auto stdout_os = TerminalOutputStream::fromStream(OutputStream::getStdout());

  try {
    flags.parseArgv(argc, argv);
  } catch (const std::exception& e) {
    std::cerr << StringUtil::format("ERROR: $0\n", e.what());
    return 1;
  }

  Vector<String> cmd_argv = flags.getArgv();
  bool print_help = flags.isSet("help");
  bool print_version = flags.isSet("version");
  if (print_version || print_help) {
    stdout_os->print(
        StringUtil::format(
            "EventQL $0 ($1)\n"
            "Copyright (c) 2016, DeepCortex GmbH. All rights reserved.\n\n",
            eventql::kVersionString,
            eventql::kBuildID));
  }

  if (print_version) {
    return 1;
  }

  if (print_help) {
    stdout_os->print(
        "Usage: $ evqlslap [OPTIONS]\n\n"
        "   -c, --connections <num>   Number of concurrent connections\n"
        "   -r, --rate <rate>         Maximum rate of requests in RPS\n"
        "   -n, --num <num>           Maximum total number of request (default is inifite)\n"
        "   -b, --batch <num>\n       Send operations in batches of N"
        "   -h, --host <hostname>     Set the EventQL server hostname\n"
        "   -p, --port <port>         Set the EventQL server port\n"
        "   -m, --mode <mode>         Select the benchmark mode (insert or query)\n"
        "   -x, --payload <data>      Set the payload\n"
        "   -d, --database <db>       Select a database\n"
        "   -t, --table <table>       Select a target table (INSERT only)\n"
        "   --user <user>             Set the EventQL username\n"
        "   --password <password>     Set the password\n"
        "   --auth_token <token>      Set the EventQL auth token\n"
        "   -?, --help                Display the help text and exit\n"
        "   -v, --version             Display the version of this binary and exit\n");

    return 1;
  }

  std::vector<std::pair<std::string, std::string>> auth_data;
  if (flags.isSet("auth_token")) {
    auth_data.emplace_back("auth_token", flags.getString("auth_token"));
  }

  if (flags.isSet("user")) {
    auth_data.emplace_back("user", flags.getString("user"));
  }

  if (flags.isSet("password")) {
    auth_data.emplace_back("password", flags.getString("password"));
  }

  auto request_handler = []() {
    usleep(1000);
    return ReturnCode::success();
  };

  auto on_progress = [&stdout_os](eventql::cli::BenchmarkStats* stats) {
    try {
      stdout_os->eraseLine();
      stdout_os->print(StringUtil::format(
          "\rRunning... rate=$0r/s, avg_runtime=$1ms, total=$2, running=$3, "
          "errors=$4 ($5%)",
          stats->getRollingRPS(),
          stats->getRollingAverageRuntime() / double(kMicrosPerMilli),
          stats->getTotalRequestCount(),
          stats->getRunningRequestCount(),
          stats->getTotalErrorCount(),
          stats->getTotalErrorRate() * 100.0f));
    } catch (const std::exception& e) {
      /* fallthrough */
    }
  };

  eventql::cli::Benchmark benchmark(
      flags.getInt("connections"),
      flags.getInt("rate"),
      flags.isSet("num") ? flags.getInt("num") : -1);

  benchmark.setRequestHandler(request_handler);
  benchmark.setProgressCallback(on_progress);
  benchmark.setProgressRateLimit(kMicrosPerSecond / 10);

  auto rc = benchmark.connect(
      flags.getString("host"),
      flags.getInt("port"),
      auth_data);

  if (rc.isSuccess()) {
    rc = benchmark.run();
  }

  stdout_os->eraseLine();

  if (rc.isSuccess()) {
    std::cout << "success" << std::endl;
    return 0;
  } else {
    std::cerr << "ERROR: " << rc.getMessage() << std::endl;
    return 1;
  }

  return 0;
}

<|endoftext|>


<commit_before>// Copyright 2010-2013 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/hash.h"
#include "base/map_util.h"
#include "flatzinc2/model.h"
#include "flatzinc2/sat_constraint.h"
#include "flatzinc2/solver.h"
#include "constraint_solver/constraint_solver.h"
#include "util/string_array.h"

DECLARE_bool(logging);
DECLARE_bool(verbose_logging);
DEFINE_bool(use_sat, true, "Use a sat solver for propagating on booleans.");

namespace operations_research {
IntExpr* FzSolver::GetExpression(const FzArgument& arg) {
  switch (arg.type) {
    case FzArgument::INT_VALUE: { return solver_.MakeIntConst(arg.Value()); }
    case FzArgument::INT_VAR_REF: { return Extract(arg.variables[0]); }
    default: {
      LOG(FATAL) << "Cannot extract " << arg.DebugString() << " as a variable";
      return nullptr;
    }
  }
}

std::vector<IntVar*> FzSolver::GetVariableArray(const FzArgument& arg) {
  std::vector<IntVar*> result;
  if (arg.type == FzArgument::INT_VAR_REF_ARRAY) {
    result.resize(arg.variables.size());
    for (int i = 0; i < arg.variables.size(); ++i) {
      result[i] = Extract(arg.variables[i])->Var();
    }
  } else if (arg.type == FzArgument::INT_LIST) {
    result.resize(arg.values.size());
    for (int i = 0; i < arg.values.size(); ++i) {
      result[i] = solver_.MakeIntConst(arg.values[i]);
    }
  } else {
    LOG(FATAL) << "Cannot extract " << arg.DebugString()
               << " as a variable array";
  }
  return result;
}

IntExpr* FzSolver::Extract(FzIntegerVariable* var) {
  IntExpr* result = FindPtrOrNull(extrated_map_, var);
  if (result != nullptr) {
    return result;
  }
  if (var->domain.values.size() == 1) {
    result = solver_.MakeIntConst(var->domain.values.back());
  } else if (var->domain.is_interval && var->domain.values.empty()) {
    result = solver_.MakeIntVar(kint32min, kint32max, var->name);
  } else if (var->domain.is_interval) {
    result = solver_.MakeIntVar(var->domain.values[0], var->domain.values[1],
                                var->name);
  } else {
    result = solver_.MakeIntVar(var->domain.values, var->name);
  }
  FZVLOG << "Extract " << var->DebugString() << " into "
         << result->DebugString() << FZENDL;
  extrated_map_[var] = result;
  return result;
}

void FzSolver::SetExtracted(FzIntegerVariable* var, IntExpr* expr) {
  CHECK(!ContainsKey(extrated_map_, var));
  extrated_map_[var] = expr;
}

// The format is fixed in the flatzinc specification.
std::string FzSolver::SolutionString(const FzOnSolutionOutput& output) {
  if (output.variable != nullptr) {
    return StringPrintf("%s = %" GG_LL_FORMAT "d;", output.name.c_str(),
                        Extract(output.variable)->Var()->Value());
  } else {
    const int bound_size = output.bounds.size();
    std::string result =
        StringPrintf("%s = array%dd(", output.name.c_str(), bound_size);
    for (int i = 0; i < bound_size; ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d..%" GG_LL_FORMAT "d, ",
                       output.bounds[i].min_value, output.bounds[i].max_value));
    }
    result.append("[");
    for (int i = 0; i < output.flat_variables.size(); ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d",
                       Extract(output.flat_variables[i])->Var()->Value()));
      if (i != output.flat_variables.size() - 1) {
        result.append(", ");
      }
    }
    result.append("]);");
    return result;
  }
  return "";
}

namespace {
struct ConstraintWithIo {
  FzConstraint* ct;
  int index;
  hash_set<FzIntegerVariable*> required;

  ConstraintWithIo(FzConstraint* cte, int i,
                   const hash_set<FzIntegerVariable*>& defined)
      : ct(cte), index(i) {
    // Collect required variables.
    for (const FzArgument& arg : ct->arguments) {
      for (FzIntegerVariable* const var : arg.variables) {
        if (ContainsKey(defined, var)) {
          required.insert(var);
        }
      }
    }
    // Remove the target_variable as it always appears in the constraint.
    if (ct->target_variable != nullptr) {
      required.erase(ct->target_variable);
    }
  }
};

int ComputeWeight(const ConstraintWithIo& ctio) {
  if (ctio.required.empty()) return 0;
  if (ctio.ct->target_variable != nullptr) return 1;
  return 2;
}

// Comparator to sort constraints based on numbers of required
// elements and index. Reverse sorting to put elements to remove at the end.
struct ConstraintWithIoComparator {
  bool operator()(ConstraintWithIo* a, ConstraintWithIo* b) const {
    const int a_weight = ComputeWeight(*a);
    const int b_weight = ComputeWeight(*b);
    return a_weight > b_weight ||
           (a_weight == b_weight && a_weight != 1 && a->index > b->index) ||
           (a_weight == b_weight && a_weight == 1 &&
            ContainsKey(a->required, b->ct->target_variable));
  }
};
}  // namespace

bool FzSolver::Extract() {
  // Create the sat solver.
  if (FLAGS_use_sat) {
    FZLOG << "  - Use sat" << FZENDL;
    sat_ = MakeSatPropagator(&solver_);
    solver_.AddConstraint(reinterpret_cast<Constraint*>(sat_));
  } else {
    sat_ = nullptr;
  }
  // Build statistics.
  statistics_.BuildStatistics();
  // Extract variables.
  hash_set<FzIntegerVariable*> defined_variables;
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint == nullptr && var->active) {
      Extract(var);
    } else {
      FZVLOG << "Skip " << var->DebugString() << FZENDL;
      if (var->defining_constraint != nullptr) {
        FZVLOG << "  - defined by " << var->defining_constraint->DebugString()
               << FZENDL;
      }
      defined_variables.insert(var);
    }
  }
  // Parse model to store info.
  for (FzConstraint* const ct : model_.constraints()) {
    if (ct->type == "all_different_int") {
      StoreAllDifferent(ct->Arg(0).variables);
    }
  }
  // Sort constraints such that defined variables are created before the
  // extraction of the constraints that use them.
  int index = 0;
  std::vector<ConstraintWithIo*> to_sort;
  std::vector<FzConstraint*> sorted;
  hash_map<const FzIntegerVariable*, std::vector<ConstraintWithIo*>>
      dependencies;
  for (FzConstraint* ct : model_.constraints()) {
    if (ct != nullptr && ct->active) {
      ConstraintWithIo* const ctio =
          new ConstraintWithIo(ct, index++, defined_variables);
      to_sort.push_back(ctio);
      for (FzIntegerVariable* const var : ctio->required) {
        dependencies[var].push_back(ctio);
      }
    }
  }
  // Sort a first time.
  std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
  // Topological sort.
  while (!to_sort.empty()) {
    if (!to_sort.back()->required.empty()) {
      // Sort again.
      std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
    }
    ConstraintWithIo* const ctio = to_sort.back();
    to_sort.pop_back();
    FZVLOG << "Pop " << ctio->ct->DebugString() << FZENDL;
    CHECK(ctio->required.empty());
    // TODO(user): Implement recovery mode.
    sorted.push_back(ctio->ct);
    FzIntegerVariable* const var = ctio->ct->target_variable;
    if (var != nullptr && ContainsKey(dependencies, var)) {
      for (ConstraintWithIo* const to_clean : dependencies[var]) {
        to_clean->required.erase(var);
      }
    }
    delete ctio;
  }
  for (FzConstraint* const ct : sorted) {
    ExtractConstraint(ct);
  }
  // Add domain constraints to created extressions.
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint != nullptr && var->active) {
      const FzDomain& domain = var->domain;
      IntExpr* const expr = Extract(var);
      if (expr->IsVar() && domain.is_interval && !domain.values.empty() &&
          (expr->Min() < domain.values[0] || expr->Max() > domain.values[1])) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetRange(domain.values[0], domain.values[1]);
      } else if (expr->IsVar() && !domain.is_interval) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetValues(domain.values);
      } else if (domain.is_interval && !domain.values.empty() &&
                 (expr->Min() < domain.values[0] ||
                  expr->Max() > domain.values[1])) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeBetweenCt(
            expr->Var(), domain.values[0], domain.values[1]));
      } else if (!domain.is_interval) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeMemberCt(expr->Var(), domain.values));
      }
    }
  }

  return true;
}

// ----- Alldiff info support -----

void FzSolver::StoreAllDifferent(const std::vector<FzIntegerVariable*>& diffs) {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  FZVLOG << "Store AllDifferent info for [" << JoinDebugStringPtr(diffs, ", ")
         << "]" << FZENDL;
  alldiffs_[local.front()].push_back(local);
}

namespace {
template <class T>
bool EqualVector(const std::vector<T>& v1, const std::vector<T>& v2) {
  if (v1.size() != v2.size()) return false;
  for (int i = 0; i < v1.size(); ++i) {
    if (v1[i] != v2[i]) return false;
  }
  return true;
}
}  // namespace

bool FzSolver::IsAllDifferent(
    const std::vector<FzIntegerVariable*>& diffs) const {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  const FzIntegerVariable* const start = local.front();
  if (!ContainsKey(alldiffs_, start)) return false;
  const std::vector<std::vector<FzIntegerVariable*>>& stored =
      FindOrDie(alldiffs_, start);
  for (const std::vector<FzIntegerVariable*>& one_diff : stored) {
    if (EqualVector(local, one_diff)) {
      return true;
    }
  }
  return false;
}
}  // namespace operations_research
<commit_msg>work on constraint sorting<commit_after>// Copyright 2010-2013 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/hash.h"
#include "base/map_util.h"
#include "flatzinc2/model.h"
#include "flatzinc2/sat_constraint.h"
#include "flatzinc2/solver.h"
#include "constraint_solver/constraint_solver.h"
#include "util/string_array.h"

DECLARE_bool(logging);
DECLARE_bool(verbose_logging);
DEFINE_bool(use_sat, true, "Use a sat solver for propagating on booleans.");

namespace operations_research {
IntExpr* FzSolver::GetExpression(const FzArgument& arg) {
  switch (arg.type) {
    case FzArgument::INT_VALUE: { return solver_.MakeIntConst(arg.Value()); }
    case FzArgument::INT_VAR_REF: { return Extract(arg.variables[0]); }
    default: {
      LOG(FATAL) << "Cannot extract " << arg.DebugString() << " as a variable";
      return nullptr;
    }
  }
}

std::vector<IntVar*> FzSolver::GetVariableArray(const FzArgument& arg) {
  std::vector<IntVar*> result;
  if (arg.type == FzArgument::INT_VAR_REF_ARRAY) {
    result.resize(arg.variables.size());
    for (int i = 0; i < arg.variables.size(); ++i) {
      result[i] = Extract(arg.variables[i])->Var();
    }
  } else if (arg.type == FzArgument::INT_LIST) {
    result.resize(arg.values.size());
    for (int i = 0; i < arg.values.size(); ++i) {
      result[i] = solver_.MakeIntConst(arg.values[i]);
    }
  } else {
    LOG(FATAL) << "Cannot extract " << arg.DebugString()
               << " as a variable array";
  }
  return result;
}

IntExpr* FzSolver::Extract(FzIntegerVariable* var) {
  IntExpr* result = FindPtrOrNull(extrated_map_, var);
  if (result != nullptr) {
    return result;
  }
  if (var->domain.values.size() == 1) {
    result = solver_.MakeIntConst(var->domain.values.back());
  } else if (var->domain.is_interval && var->domain.values.empty()) {
    result = solver_.MakeIntVar(kint32min, kint32max, var->name);
  } else if (var->domain.is_interval) {
    result = solver_.MakeIntVar(var->domain.values[0], var->domain.values[1],
                                var->name);
  } else {
    result = solver_.MakeIntVar(var->domain.values, var->name);
  }
  FZVLOG << "Extract " << var->DebugString() << " into "
         << result->DebugString() << FZENDL;
  extrated_map_[var] = result;
  return result;
}

void FzSolver::SetExtracted(FzIntegerVariable* var, IntExpr* expr) {
  CHECK(!ContainsKey(extrated_map_, var));
  extrated_map_[var] = expr;
}

// The format is fixed in the flatzinc specification.
std::string FzSolver::SolutionString(const FzOnSolutionOutput& output) {
  if (output.variable != nullptr) {
    return StringPrintf("%s = %" GG_LL_FORMAT "d;", output.name.c_str(),
                        Extract(output.variable)->Var()->Value());
  } else {
    const int bound_size = output.bounds.size();
    std::string result =
        StringPrintf("%s = array%dd(", output.name.c_str(), bound_size);
    for (int i = 0; i < bound_size; ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d..%" GG_LL_FORMAT "d, ",
                       output.bounds[i].min_value, output.bounds[i].max_value));
    }
    result.append("[");
    for (int i = 0; i < output.flat_variables.size(); ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d",
                       Extract(output.flat_variables[i])->Var()->Value()));
      if (i != output.flat_variables.size() - 1) {
        result.append(", ");
      }
    }
    result.append("]);");
    return result;
  }
  return "";
}

namespace {
struct ConstraintWithIo {
  FzConstraint* ct;
  int index;
  hash_set<FzIntegerVariable*> required;

  ConstraintWithIo(FzConstraint* cte, int i,
                   const hash_set<FzIntegerVariable*>& defined)
      : ct(cte), index(i) {
    // Collect required variables.
    for (const FzArgument& arg : ct->arguments) {
      for (FzIntegerVariable* const var : arg.variables) {
        if (var != cte->target_variable && ContainsKey(defined, var)) {
          required.insert(var);
        }
      }
    }
  }
};

int ComputeWeight(const ConstraintWithIo& ctio) {
  if (ctio.required.empty()) return 0;
  if (ctio.ct->target_variable != nullptr) return 1;
  return 2;
}

// Comparator to sort constraints based on numbers of required
// elements and index. Reverse sorting to put elements to remove at the end.
struct ConstraintWithIoComparator {
  bool operator()(ConstraintWithIo* a, ConstraintWithIo* b) const {
    const int a_weight = ComputeWeight(*a);
    const int b_weight = ComputeWeight(*b);
    return a_weight > b_weight ||
           (a_weight == b_weight && a_weight != 1 && a->index > b->index) ||
           (a_weight == b_weight && a_weight == 1 &&
            ContainsKey(a->required, b->ct->target_variable));
  }
};
}  // namespace

bool FzSolver::Extract() {
  // Create the sat solver.
  if (FLAGS_use_sat) {
    FZLOG << "  - Use sat" << FZENDL;
    sat_ = MakeSatPropagator(&solver_);
    solver_.AddConstraint(reinterpret_cast<Constraint*>(sat_));
  } else {
    sat_ = nullptr;
  }
  // Build statistics.
  statistics_.BuildStatistics();
  // Extract variables.
  hash_set<FzIntegerVariable*> defined_variables;
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint == nullptr && var->active) {
      Extract(var);
    } else {
      FZVLOG << "Skip " << var->DebugString() << FZENDL;
      if (var->defining_constraint != nullptr) {
        FZVLOG << "  - defined by " << var->defining_constraint->DebugString()
               << FZENDL;
      }
      defined_variables.insert(var);
    }
  }
  // Parse model to store info.
  for (FzConstraint* const ct : model_.constraints()) {
    if (ct->type == "all_different_int") {
      StoreAllDifferent(ct->Arg(0).variables);
    }
  }
  // Sort constraints such that defined variables are created before the
  // extraction of the constraints that use them.
  int index = 0;
  std::vector<ConstraintWithIo*> to_sort;
  std::vector<FzConstraint*> sorted;
  hash_map<const FzIntegerVariable*, std::vector<ConstraintWithIo*>>
      dependencies;
  for (FzConstraint* ct : model_.constraints()) {
    if (ct != nullptr && ct->active) {
      ConstraintWithIo* const ctio =
          new ConstraintWithIo(ct, index++, defined_variables);
      to_sort.push_back(ctio);
      for (FzIntegerVariable* const var : ctio->required) {
        dependencies[var].push_back(ctio);
      }
    }
  }
  // Sort a first time.
  std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
  // Topological sort.
  while (!to_sort.empty()) {
    if (!to_sort.back()->required.empty()) {
      // Sort again.
      std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
    }
    ConstraintWithIo* const ctio = to_sort.back();
    to_sort.pop_back();
    FZVLOG << "Pop " << ctio->ct->DebugString() << FZENDL;
    CHECK(ctio->required.empty());
    // TODO(user): Implement recovery mode.
    sorted.push_back(ctio->ct);
    FzIntegerVariable* const var = ctio->ct->target_variable;
    if (var != nullptr && ContainsKey(dependencies, var)) {
      for (ConstraintWithIo* const to_clean : dependencies[var]) {
        to_clean->required.erase(var);
      }
    }
    delete ctio;
  }
  for (FzConstraint* const ct : sorted) {
    ExtractConstraint(ct);
  }
  // Add domain constraints to created extressions.
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint != nullptr && var->active) {
      const FzDomain& domain = var->domain;
      IntExpr* const expr = Extract(var);
      if (expr->IsVar() && domain.is_interval && !domain.values.empty() &&
          (expr->Min() < domain.values[0] || expr->Max() > domain.values[1])) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetRange(domain.values[0], domain.values[1]);
      } else if (expr->IsVar() && !domain.is_interval) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetValues(domain.values);
      } else if (domain.is_interval && !domain.values.empty() &&
                 (expr->Min() < domain.values[0] ||
                  expr->Max() > domain.values[1])) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeBetweenCt(
            expr->Var(), domain.values[0], domain.values[1]));
      } else if (!domain.is_interval) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeMemberCt(expr->Var(), domain.values));
      }
    }
  }

  return true;
}

// ----- Alldiff info support -----

void FzSolver::StoreAllDifferent(const std::vector<FzIntegerVariable*>& diffs) {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  FZVLOG << "Store AllDifferent info for [" << JoinDebugStringPtr(diffs, ", ")
         << "]" << FZENDL;
  alldiffs_[local.front()].push_back(local);
}

namespace {
template <class T>
bool EqualVector(const std::vector<T>& v1, const std::vector<T>& v2) {
  if (v1.size() != v2.size()) return false;
  for (int i = 0; i < v1.size(); ++i) {
    if (v1[i] != v2[i]) return false;
  }
  return true;
}
}  // namespace

bool FzSolver::IsAllDifferent(
    const std::vector<FzIntegerVariable*>& diffs) const {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  const FzIntegerVariable* const start = local.front();
  if (!ContainsKey(alldiffs_, start)) return false;
  const std::vector<std::vector<FzIntegerVariable*>>& stored =
      FindOrDie(alldiffs_, start);
  for (const std::vector<FzIntegerVariable*>& one_diff : stored) {
    if (EqualVector(local, one_diff)) {
      return true;
    }
  }
  return false;
}
}  // namespace operations_research
<|endoftext|>