<commit_before>/* -*- indent-tabs-mode: nil -*- */

#include <chrono>
#include <csignal>
#include <cstring>
#include <event2/buffer.h>
#include <event2/thread.h>
#include <functional>
#include <gflags/gflags.h>
#include <iostream>
#include <memory>
#include <mutex>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <signal.h>
#include <string>
#include <unistd.h>

#include "config.h"
#include "client/async_log_client.h"
#include "fetcher/continuous_fetcher.h"
#include "fetcher/remote_peer.h"
#include "fetcher/peer_group.h"
#include "log/cluster_state_controller.h"
#include "log/ct_extensions.h"
#include "log/etcd_consistent_store.h"
#include "log/file_db.h"
#include "log/file_storage.h"
#include "log/leveldb_db.h"
#include "log/sqlite_db.h"
#include "log/strict_consistent_store.h"
#include "merkletree/merkle_verifier.h"
#include "monitoring/latency.h"
#include "monitoring/monitoring.h"
#include "monitoring/registry.h"
#include "server/handler.h"
#include "server/json_output.h"
#include "server/metrics.h"
#include "server/proxy.h"
#include "server/server.h"
#include "util/etcd.h"
#include "util/fake_etcd.h"
#include "util/libevent_wrapper.h"
#include "util/masterelection.h"
#include "util/periodic_closure.h"
#include "util/read_key.h"
#include "util/status.h"
#include "util/thread_pool.h"
#include "util/uuid.h"

DEFINE_string(server, "localhost", "Server host");
DEFINE_int32(port, 9999, "Server port");
// TODO(alcutter): Just specify a root dir with a single flag.
DEFINE_string(cert_dir, "", "Storage directory for certificates");
DEFINE_string(tree_dir, "", "Storage directory for trees");
DEFINE_string(meta_dir, "", "Storage directory for meta info");
DEFINE_string(sqlite_db, "",
              "SQLite database for certificate and tree storage");
DEFINE_string(leveldb_db, "",
              "LevelDB database for certificate and tree storage");
// TODO(ekasper): sanity-check these against the directory structure.
DEFINE_int32(cert_storage_depth, 0,
             "Subdirectory depth for certificates; if the directory is not "
             "empty, must match the existing depth.");
DEFINE_int32(tree_storage_depth, 0,
             "Subdirectory depth for tree signatures; if the directory is not "
             "empty, must match the existing depth");
DEFINE_int32(log_stats_frequency_seconds, 3600,
             "Interval for logging summary statistics. Approximate: the "
             "server will log statistics if in the beginning of its select "
             "loop, at least this period has elapsed since the last log time. "
             "Must be greater than 0.");
DEFINE_int32(target_poll_frequency_seconds, 10,
             "How often should the target log be polled for updates.");
DEFINE_string(etcd_host, "", "Hostname of the etcd server");
DEFINE_int32(etcd_port, 0, "Port of the etcd server.");
DEFINE_string(etcd_root, "/root", "Root of cluster entries in etcd.");
DEFINE_int32(num_http_server_threads, 16,
             "Number of threads for servicing the incoming HTTP requests.");
DEFINE_string(target_log_uri, "http://ct.googleapis.com/pilot",
              "URI of the log to mirror.");
DEFINE_string(
    target_public_key, "",
    "PEM-encoded server public key file of the log we're mirroring.");
DEFINE_int32(local_sth_update_frequency_seconds, 30,
             "Number of seconds between local checks for updated tree data.");

namespace libevent = cert_trans::libevent;

using cert_trans::AsyncLogClient;
using cert_trans::ClusterStateController;
using cert_trans::ConsistentStore;
using cert_trans::ContinuousFetcher;
using cert_trans::Counter;
using cert_trans::Gauge;
using cert_trans::EtcdClient;
using cert_trans::EtcdConsistentStore;
using cert_trans::FakeEtcdClient;
using cert_trans::FileStorage;
using cert_trans::HttpHandler;
using cert_trans::JsonOutput;
using cert_trans::Latency;
using cert_trans::LoggedCertificate;
using cert_trans::MasterElection;
using cert_trans::PeriodicClosure;
using cert_trans::Proxy;
using cert_trans::ReadPublicKey;
using cert_trans::RemotePeer;
using cert_trans::Server;
using cert_trans::ScopedLatency;
using cert_trans::StrictConsistentStore;
using cert_trans::ThreadPool;
using cert_trans::Update;
using cert_trans::UrlFetcher;
using ct::ClusterNodeState;
using ct::SignedTreeHead;
using google::RegisterFlagValidator;
using std::bind;
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::seconds;
using std::chrono::steady_clock;
using std::function;
using std::lock_guard;
using std::make_pair;
using std::make_shared;
using std::map;
using std::mutex;
using std::placeholders::_1;
using std::shared_ptr;
using std::string;
using std::thread;
using std::unique_ptr;
using util::StatusOr;
using util::SyncTask;
using util::Task;

namespace {

Gauge<>* latest_local_tree_size_gauge =
    Gauge<>::New("latest_local_tree_size",
                 "Size of latest locally available STH.");

// Basic sanity checks on flag values.
static bool ValidatePort(const char* flagname, int port) {
  if (port <= 0 || port > 65535) {
    std::cout << "Port value " << port << " is invalid. " << std::endl;
    return false;
  }
  return true;
}

static const bool port_dummy =
    RegisterFlagValidator(&FLAGS_port, &ValidatePort);

static bool ValidateRead(const char* flagname, const string& path) {
  if (access(path.c_str(), R_OK) != 0) {
    std::cout << "Cannot access " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static bool ValidateWrite(const char* flagname, const string& path) {
  if (path != "" && access(path.c_str(), W_OK) != 0) {
    std::cout << "Cannot modify " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static const bool pubkey_dummy =
    RegisterFlagValidator(&FLAGS_target_public_key, &ValidateRead);

static const bool cert_dir_dummy =
    RegisterFlagValidator(&FLAGS_cert_dir, &ValidateWrite);

static const bool tree_dir_dummy =
    RegisterFlagValidator(&FLAGS_tree_dir, &ValidateWrite);

static bool ValidateIsNonNegative(const char* flagname, int value) {
  if (value < 0) {
    std::cout << flagname << " must not be negative" << std::endl;
    return false;
  }
  return true;
}

static const bool c_st_dummy =
    RegisterFlagValidator(&FLAGS_cert_storage_depth, &ValidateIsNonNegative);
static const bool t_st_dummy =
    RegisterFlagValidator(&FLAGS_tree_storage_depth, &ValidateIsNonNegative);

static bool ValidateIsPositive(const char* flagname, int value) {
  if (value <= 0) {
    std::cout << flagname << " must be greater than 0" << std::endl;
    return false;
  }
  return true;
}

static const bool stats_dummy =
    RegisterFlagValidator(&FLAGS_log_stats_frequency_seconds,
                          &ValidateIsPositive);

static const bool follow_dummy =
    RegisterFlagValidator(&FLAGS_target_poll_frequency_seconds,
                          &ValidateIsPositive);
}  // namespace

void STHUpdater(
    Database<LoggedCertificate>* db,
    ClusterStateController<LoggedCertificate>* cluster_state_controller,
    mutex* queue_mutex, map<int64_t, ct::SignedTreeHead>* queue, Task* task) {
  CHECK_NOTNULL(db);
  CHECK_NOTNULL(cluster_state_controller);
  CHECK_NOTNULL(queue_mutex);
  CHECK_NOTNULL(queue);
  CHECK_NOTNULL(task);

  while (true) {
    if (task->CancelRequested()) {
      task->Return(util::Status::CANCELLED);
    }

    const int64_t local_size(db->TreeSize());

    {
      lock_guard<mutex> lock(*queue_mutex);
      while (!queue->empty() &&
             queue->begin()->second.tree_size() <= local_size) {
        LOG(INFO) << "Can serve new STH of size "
                  << queue->begin()->second.tree_size() << " locally";
        cluster_state_controller->NewTreeHead(queue->begin()->second);
        queue->erase(queue->begin());
      }
    }

    std::this_thread::sleep_for(
        seconds(FLAGS_local_sth_update_frequency_seconds));
  }
}

int main(int argc, char* argv[]) {
  // Ignore various signals whilst we start up.
  signal(SIGHUP, SIG_IGN);
  signal(SIGINT, SIG_IGN);
  signal(SIGTERM, SIG_IGN);

  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InitGoogleLogging(argv[0]);
  google::InstallFailureSignalHandler();

  Server<LoggedCertificate>::StaticInit();

  if (!FLAGS_sqlite_db.empty() + !FLAGS_leveldb_db.empty() +
          (!FLAGS_cert_dir.empty() | !FLAGS_tree_dir.empty()) !=
      1) {
    std::cerr << "Must only specify one database type.";
    exit(1);
  }

  if (FLAGS_sqlite_db.empty() && FLAGS_leveldb_db.empty()) {
    CHECK_NE(FLAGS_cert_dir, FLAGS_tree_dir)
        << "Certificate directory and tree directory must differ";
  }

  Database<LoggedCertificate>* db;

  if (!FLAGS_sqlite_db.empty()) {
    db = new SQLiteDB<LoggedCertificate>(FLAGS_sqlite_db);
  } else if (!FLAGS_leveldb_db.empty()) {
    db = new LevelDB<LoggedCertificate>(FLAGS_leveldb_db);
  } else {
    db = new FileDB<LoggedCertificate>(
        new FileStorage(FLAGS_cert_dir, FLAGS_cert_storage_depth),
        new FileStorage(FLAGS_tree_dir, FLAGS_tree_storage_depth),
        new FileStorage(FLAGS_meta_dir, 0));
  }

  const bool stand_alone_mode(FLAGS_etcd_host.empty());
  const shared_ptr<libevent::Base> event_base(make_shared<libevent::Base>());
  UrlFetcher url_fetcher(event_base.get());

  const std::unique_ptr<EtcdClient> etcd_client(
      stand_alone_mode
          ? new FakeEtcdClient(event_base.get())
          : new EtcdClient(&url_fetcher, FLAGS_etcd_host, FLAGS_etcd_port));

  Server<LoggedCertificate>::Options options;
  options.server = FLAGS_server;
  options.port = FLAGS_port;
  options.etcd_root = FLAGS_etcd_root;
  options.num_http_server_threads = FLAGS_num_http_server_threads;

  Server<LoggedCertificate> server(options, event_base, db, etcd_client.get(),
                                   &url_fetcher, nullptr, nullptr);
  server.Initialise(true /* is_mirror */);

  if (stand_alone_mode) {
    // Set up a simple single-node mirror environment for testing.
    //
    // Put a sensible single-node config into FakeEtcd. For a real clustered
    // log
    // we'd expect a ClusterConfig already to be present within etcd as part of
    // the provisioning of the log.
    //
    // TODO(alcutter): Note that we're currently broken wrt to restarting the
    // log server when there's data in the log.  It's a temporary thing though,
    // so fear ye not.
    ct::ClusterConfig config;
    config.set_minimum_serving_nodes(1);
    config.set_minimum_serving_fraction(1);
    LOG(INFO) << "Setting default single-node ClusterConfig:\n"
              << config.DebugString();
    server.consistent_store()->SetClusterConfig(config);

    // Since we're a single node cluster, we'll settle that we're the
    // master here, so that we can populate the initial STH
    // (StrictConsistentStore won't allow us to do so unless we're master.)
    server.election()->StartElection();
    server.election()->WaitToBecomeMaster();
  } else {
    CHECK(!FLAGS_server.empty());
  }

  CHECK(!FLAGS_target_public_key.empty());
  CHECK(!FLAGS_target_log_uri.empty());

  const StatusOr<EVP_PKEY*> pubkey(ReadPublicKey(FLAGS_target_public_key));
  CHECK(pubkey.ok()) << "Failed to read target log's public key file: "
                     << pubkey.status();

  ThreadPool pool(16);
  SyncTask fetcher_task(&pool);

  mutex queue_mutex;
  map<int64_t, ct::SignedTreeHead> queue;

  const function<void(const ct::SignedTreeHead&)> new_sth(
      [&queue_mutex, &queue](const ct::SignedTreeHead& sth) {
        lock_guard<mutex> lock(queue_mutex);
        const auto it(queue.find(sth.tree_size()));
        if (it != queue.end() && sth.timestamp() < it->second.timestamp()) {
          LOG(WARNING) << "Received older STH:\nHad:\n"
                       << it->second.DebugString() << "\nGot:\n"
                       << sth.DebugString();
          return;
        }
        queue.insert(make_pair(sth.tree_size(), sth));
      });

  const shared_ptr<RemotePeer> peer(make_shared<RemotePeer>(
      unique_ptr<AsyncLogClient>(
          new AsyncLogClient(&pool, &url_fetcher, FLAGS_target_log_uri)),
      unique_ptr<LogVerifier>(
          new LogVerifier(new LogSigVerifier(pubkey.ValueOrDie()),
                          new MerkleVerifier(new Sha256Hasher))),
      new_sth, fetcher_task.task()->AddChild(
                   [](Task* task) { LOG(INFO) << "RemotePeer exited."; })));
  const unique_ptr<ContinuousFetcher> fetcher(
      ContinuousFetcher::New(event_base.get(), &pool, db, false));
  fetcher->AddPeer("target", peer);

  thread sth_updater(&STHUpdater, db, server.cluster_state_controller(),
                     &queue_mutex, &queue,
                     fetcher_task.task()->AddChild([](Task* task) {
                       LOG(INFO) << "STHUpdater exited.";
                     }));

  server.Run();

  fetcher_task.task()->Return();
  fetcher_task.Wait();
  sth_updater.join();

  return 0;
}
<commit_msg>Export local tree size when mirroring.<commit_after>/* -*- indent-tabs-mode: nil -*- */

#include <chrono>
#include <csignal>
#include <cstring>
#include <event2/buffer.h>
#include <event2/thread.h>
#include <functional>
#include <gflags/gflags.h>
#include <iostream>
#include <memory>
#include <mutex>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <signal.h>
#include <string>
#include <unistd.h>

#include "config.h"
#include "client/async_log_client.h"
#include "fetcher/continuous_fetcher.h"
#include "fetcher/remote_peer.h"
#include "fetcher/peer_group.h"
#include "log/cluster_state_controller.h"
#include "log/ct_extensions.h"
#include "log/etcd_consistent_store.h"
#include "log/file_db.h"
#include "log/file_storage.h"
#include "log/leveldb_db.h"
#include "log/sqlite_db.h"
#include "log/strict_consistent_store.h"
#include "merkletree/merkle_verifier.h"
#include "monitoring/latency.h"
#include "monitoring/monitoring.h"
#include "monitoring/registry.h"
#include "server/handler.h"
#include "server/json_output.h"
#include "server/metrics.h"
#include "server/proxy.h"
#include "server/server.h"
#include "util/etcd.h"
#include "util/fake_etcd.h"
#include "util/libevent_wrapper.h"
#include "util/masterelection.h"
#include "util/periodic_closure.h"
#include "util/read_key.h"
#include "util/status.h"
#include "util/thread_pool.h"
#include "util/uuid.h"

DEFINE_string(server, "localhost", "Server host");
DEFINE_int32(port, 9999, "Server port");
// TODO(alcutter): Just specify a root dir with a single flag.
DEFINE_string(cert_dir, "", "Storage directory for certificates");
DEFINE_string(tree_dir, "", "Storage directory for trees");
DEFINE_string(meta_dir, "", "Storage directory for meta info");
DEFINE_string(sqlite_db, "",
              "SQLite database for certificate and tree storage");
DEFINE_string(leveldb_db, "",
              "LevelDB database for certificate and tree storage");
// TODO(ekasper): sanity-check these against the directory structure.
DEFINE_int32(cert_storage_depth, 0,
             "Subdirectory depth for certificates; if the directory is not "
             "empty, must match the existing depth.");
DEFINE_int32(tree_storage_depth, 0,
             "Subdirectory depth for tree signatures; if the directory is not "
             "empty, must match the existing depth");
DEFINE_int32(log_stats_frequency_seconds, 3600,
             "Interval for logging summary statistics. Approximate: the "
             "server will log statistics if in the beginning of its select "
             "loop, at least this period has elapsed since the last log time. "
             "Must be greater than 0.");
DEFINE_int32(target_poll_frequency_seconds, 10,
             "How often should the target log be polled for updates.");
DEFINE_string(etcd_host, "", "Hostname of the etcd server");
DEFINE_int32(etcd_port, 0, "Port of the etcd server.");
DEFINE_string(etcd_root, "/root", "Root of cluster entries in etcd.");
DEFINE_int32(num_http_server_threads, 16,
             "Number of threads for servicing the incoming HTTP requests.");
DEFINE_string(target_log_uri, "http://ct.googleapis.com/pilot",
              "URI of the log to mirror.");
DEFINE_string(
    target_public_key, "",
    "PEM-encoded server public key file of the log we're mirroring.");
DEFINE_int32(local_sth_update_frequency_seconds, 30,
             "Number of seconds between local checks for updated tree data.");

namespace libevent = cert_trans::libevent;

using cert_trans::AsyncLogClient;
using cert_trans::ClusterStateController;
using cert_trans::ConsistentStore;
using cert_trans::ContinuousFetcher;
using cert_trans::Counter;
using cert_trans::Gauge;
using cert_trans::EtcdClient;
using cert_trans::EtcdConsistentStore;
using cert_trans::FakeEtcdClient;
using cert_trans::FileStorage;
using cert_trans::HttpHandler;
using cert_trans::JsonOutput;
using cert_trans::Latency;
using cert_trans::LoggedCertificate;
using cert_trans::MasterElection;
using cert_trans::PeriodicClosure;
using cert_trans::Proxy;
using cert_trans::ReadPublicKey;
using cert_trans::RemotePeer;
using cert_trans::Server;
using cert_trans::ScopedLatency;
using cert_trans::StrictConsistentStore;
using cert_trans::ThreadPool;
using cert_trans::Update;
using cert_trans::UrlFetcher;
using ct::ClusterNodeState;
using ct::SignedTreeHead;
using google::RegisterFlagValidator;
using std::bind;
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::seconds;
using std::chrono::steady_clock;
using std::function;
using std::lock_guard;
using std::make_pair;
using std::make_shared;
using std::map;
using std::mutex;
using std::placeholders::_1;
using std::shared_ptr;
using std::string;
using std::thread;
using std::unique_ptr;
using util::StatusOr;
using util::SyncTask;
using util::Task;

namespace {

Gauge<>* latest_local_tree_size_gauge =
    Gauge<>::New("latest_local_tree_size",
                 "Size of latest locally available STH.");

// Basic sanity checks on flag values.
static bool ValidatePort(const char* flagname, int port) {
  if (port <= 0 || port > 65535) {
    std::cout << "Port value " << port << " is invalid. " << std::endl;
    return false;
  }
  return true;
}

static const bool port_dummy =
    RegisterFlagValidator(&FLAGS_port, &ValidatePort);

static bool ValidateRead(const char* flagname, const string& path) {
  if (access(path.c_str(), R_OK) != 0) {
    std::cout << "Cannot access " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static bool ValidateWrite(const char* flagname, const string& path) {
  if (path != "" && access(path.c_str(), W_OK) != 0) {
    std::cout << "Cannot modify " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static const bool pubkey_dummy =
    RegisterFlagValidator(&FLAGS_target_public_key, &ValidateRead);

static const bool cert_dir_dummy =
    RegisterFlagValidator(&FLAGS_cert_dir, &ValidateWrite);

static const bool tree_dir_dummy =
    RegisterFlagValidator(&FLAGS_tree_dir, &ValidateWrite);

static bool ValidateIsNonNegative(const char* flagname, int value) {
  if (value < 0) {
    std::cout << flagname << " must not be negative" << std::endl;
    return false;
  }
  return true;
}

static const bool c_st_dummy =
    RegisterFlagValidator(&FLAGS_cert_storage_depth, &ValidateIsNonNegative);
static const bool t_st_dummy =
    RegisterFlagValidator(&FLAGS_tree_storage_depth, &ValidateIsNonNegative);

static bool ValidateIsPositive(const char* flagname, int value) {
  if (value <= 0) {
    std::cout << flagname << " must be greater than 0" << std::endl;
    return false;
  }
  return true;
}

static const bool stats_dummy =
    RegisterFlagValidator(&FLAGS_log_stats_frequency_seconds,
                          &ValidateIsPositive);

static const bool follow_dummy =
    RegisterFlagValidator(&FLAGS_target_poll_frequency_seconds,
                          &ValidateIsPositive);
}  // namespace

void STHUpdater(
    Database<LoggedCertificate>* db,
    ClusterStateController<LoggedCertificate>* cluster_state_controller,
    mutex* queue_mutex, map<int64_t, ct::SignedTreeHead>* queue, Task* task) {
  CHECK_NOTNULL(db);
  CHECK_NOTNULL(cluster_state_controller);
  CHECK_NOTNULL(queue_mutex);
  CHECK_NOTNULL(queue);
  CHECK_NOTNULL(task);

  while (true) {
    if (task->CancelRequested()) {
      task->Return(util::Status::CANCELLED);
    }

    const int64_t local_size(db->TreeSize());
    latest_local_tree_size_gauge->Set(local_size);

    {
      lock_guard<mutex> lock(*queue_mutex);
      while (!queue->empty() &&
             queue->begin()->second.tree_size() <= local_size) {
        LOG(INFO) << "Can serve new STH of size "
                  << queue->begin()->second.tree_size() << " locally";
        cluster_state_controller->NewTreeHead(queue->begin()->second);
        queue->erase(queue->begin());
      }
    }

    std::this_thread::sleep_for(
        seconds(FLAGS_local_sth_update_frequency_seconds));
  }
}

int main(int argc, char* argv[]) {
  // Ignore various signals whilst we start up.
  signal(SIGHUP, SIG_IGN);
  signal(SIGINT, SIG_IGN);
  signal(SIGTERM, SIG_IGN);

  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InitGoogleLogging(argv[0]);
  google::InstallFailureSignalHandler();

  Server<LoggedCertificate>::StaticInit();

  if (!FLAGS_sqlite_db.empty() + !FLAGS_leveldb_db.empty() +
          (!FLAGS_cert_dir.empty() | !FLAGS_tree_dir.empty()) !=
      1) {
    std::cerr << "Must only specify one database type.";
    exit(1);
  }

  if (FLAGS_sqlite_db.empty() && FLAGS_leveldb_db.empty()) {
    CHECK_NE(FLAGS_cert_dir, FLAGS_tree_dir)
        << "Certificate directory and tree directory must differ";
  }

  Database<LoggedCertificate>* db;

  if (!FLAGS_sqlite_db.empty()) {
    db = new SQLiteDB<LoggedCertificate>(FLAGS_sqlite_db);
  } else if (!FLAGS_leveldb_db.empty()) {
    db = new LevelDB<LoggedCertificate>(FLAGS_leveldb_db);
  } else {
    db = new FileDB<LoggedCertificate>(
        new FileStorage(FLAGS_cert_dir, FLAGS_cert_storage_depth),
        new FileStorage(FLAGS_tree_dir, FLAGS_tree_storage_depth),
        new FileStorage(FLAGS_meta_dir, 0));
  }

  const bool stand_alone_mode(FLAGS_etcd_host.empty());
  const shared_ptr<libevent::Base> event_base(make_shared<libevent::Base>());
  UrlFetcher url_fetcher(event_base.get());

  const std::unique_ptr<EtcdClient> etcd_client(
      stand_alone_mode
          ? new FakeEtcdClient(event_base.get())
          : new EtcdClient(&url_fetcher, FLAGS_etcd_host, FLAGS_etcd_port));

  Server<LoggedCertificate>::Options options;
  options.server = FLAGS_server;
  options.port = FLAGS_port;
  options.etcd_root = FLAGS_etcd_root;
  options.num_http_server_threads = FLAGS_num_http_server_threads;

  Server<LoggedCertificate> server(options, event_base, db, etcd_client.get(),
                                   &url_fetcher, nullptr, nullptr);
  server.Initialise(true /* is_mirror */);

  if (stand_alone_mode) {
    // Set up a simple single-node mirror environment for testing.
    //
    // Put a sensible single-node config into FakeEtcd. For a real clustered
    // log
    // we'd expect a ClusterConfig already to be present within etcd as part of
    // the provisioning of the log.
    //
    // TODO(alcutter): Note that we're currently broken wrt to restarting the
    // log server when there's data in the log.  It's a temporary thing though,
    // so fear ye not.
    ct::ClusterConfig config;
    config.set_minimum_serving_nodes(1);
    config.set_minimum_serving_fraction(1);
    LOG(INFO) << "Setting default single-node ClusterConfig:\n"
              << config.DebugString();
    server.consistent_store()->SetClusterConfig(config);

    // Since we're a single node cluster, we'll settle that we're the
    // master here, so that we can populate the initial STH
    // (StrictConsistentStore won't allow us to do so unless we're master.)
    server.election()->StartElection();
    server.election()->WaitToBecomeMaster();
  } else {
    CHECK(!FLAGS_server.empty());
  }

  CHECK(!FLAGS_target_public_key.empty());
  CHECK(!FLAGS_target_log_uri.empty());

  const StatusOr<EVP_PKEY*> pubkey(ReadPublicKey(FLAGS_target_public_key));
  CHECK(pubkey.ok()) << "Failed to read target log's public key file: "
                     << pubkey.status();

  ThreadPool pool(16);
  SyncTask fetcher_task(&pool);

  mutex queue_mutex;
  map<int64_t, ct::SignedTreeHead> queue;

  const function<void(const ct::SignedTreeHead&)> new_sth(
      [&queue_mutex, &queue](const ct::SignedTreeHead& sth) {
        lock_guard<mutex> lock(queue_mutex);
        const auto it(queue.find(sth.tree_size()));
        if (it != queue.end() && sth.timestamp() < it->second.timestamp()) {
          LOG(WARNING) << "Received older STH:\nHad:\n"
                       << it->second.DebugString() << "\nGot:\n"
                       << sth.DebugString();
          return;
        }
        queue.insert(make_pair(sth.tree_size(), sth));
      });

  const shared_ptr<RemotePeer> peer(make_shared<RemotePeer>(
      unique_ptr<AsyncLogClient>(
          new AsyncLogClient(&pool, &url_fetcher, FLAGS_target_log_uri)),
      unique_ptr<LogVerifier>(
          new LogVerifier(new LogSigVerifier(pubkey.ValueOrDie()),
                          new MerkleVerifier(new Sha256Hasher))),
      new_sth, fetcher_task.task()->AddChild(
                   [](Task* task) { LOG(INFO) << "RemotePeer exited."; })));
  const unique_ptr<ContinuousFetcher> fetcher(
      ContinuousFetcher::New(event_base.get(), &pool, db, false));
  fetcher->AddPeer("target", peer);

  thread sth_updater(&STHUpdater, db, server.cluster_state_controller(),
                     &queue_mutex, &queue,
                     fetcher_task.task()->AddChild([](Task* task) {
                       LOG(INFO) << "STHUpdater exited.";
                     }));

  server.Run();

  fetcher_task.task()->Return();
  fetcher_task.Wait();
  sth_updater.join();

  return 0;
}
<|endoftext|>


<commit_before>#include <nan.h>
extern "C" {
#include <expat.h>
}

using namespace v8;
using namespace node;

class Parser : public ObjectWrap {
public:
  static void Initialize(Handle<Object> target)
  {
    NanScope();
    Local<FunctionTemplate> t = FunctionTemplate::New(New);

    t->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(t, "parse", Parse);
    NODE_SET_PROTOTYPE_METHOD(t, "setEncoding", SetEncoding);
    NODE_SET_PROTOTYPE_METHOD(t, "setUnknownEncoding", SetUnknownEncoding);
    NODE_SET_PROTOTYPE_METHOD(t, "getError", GetError);
    NODE_SET_PROTOTYPE_METHOD(t, "stop", Stop);
    NODE_SET_PROTOTYPE_METHOD(t, "resume", Resume);
    NODE_SET_PROTOTYPE_METHOD(t, "reset", Reset);
    NODE_SET_PROTOTYPE_METHOD(t, "getCurrentLineNumber", GetCurrentLineNumber);
    NODE_SET_PROTOTYPE_METHOD(t, "getCurrentColumnNumber", GetCurrentColumnNumber);
    NODE_SET_PROTOTYPE_METHOD(t, "getCurrentByteIndex", GetCurrentByteIndex);

    target->Set(NanNew<String>("Parser"), t->GetFunction());
  }

protected:
  /*** Constructor ***/

  static NAN_METHOD(New)
  {
    NanScope();
    XML_Char *encoding = NULL;
    if (args.Length() == 1 && args[0]->IsString())
      {
        encoding = new XML_Char[32];
        NanRawString(args[0], Nan::ASCII, NULL, encoding, 32, 0);
      }

    Parser *parser = new Parser(encoding);
    if (encoding)
      delete[] encoding;
    parser->Wrap(args.This());
    NanReturnValue(args.This());
  }

  Parser(const XML_Char *encoding)
    : ObjectWrap()
  {
    parser = XML_ParserCreate(encoding);
    assert(parser != NULL);

    attachHandlers();
  }

  ~Parser()
  {
    XML_ParserFree(parser);
  }

  void attachHandlers()
  {
    XML_SetUserData(parser, this);
    XML_SetElementHandler(parser, StartElement, EndElement);
    XML_SetCharacterDataHandler(parser, Text);
    XML_SetCdataSectionHandler(parser, StartCdata, EndCdata);
    XML_SetProcessingInstructionHandler(parser, ProcessingInstruction);
    XML_SetCommentHandler(parser, Comment);
    XML_SetXmlDeclHandler(parser, XmlDecl);
    XML_SetEntityDeclHandler(parser, EntityDecl);
    XML_SetUnknownEncodingHandler(parser, UnknownEncoding, this);
  }

  /*** parse() ***/

  static NAN_METHOD(Parse)
  {
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    NanScope();
    Local<String> str;
    int isFinal = 0;

    /* Argument 2: isFinal :: Bool */
    if (args.Length() >= 2)
      {
        isFinal = args[1]->IsTrue();
      }

    /* Argument 1: buf :: String or Buffer */
    if (args.Length() >= 1 && args[0]->IsString())
      {
        str = args[0]->ToString();
        NanReturnValue(parser->parseString(**str, isFinal) ? True() : False());
      }
    else if (args.Length() >= 1 && args[0]->IsObject())
      {
        Local<Object> obj = args[0]->ToObject();
        if (Buffer::HasInstance(obj))
        {
          NanReturnValue(parser->parseBuffer(obj, isFinal) ? True() : False());
        }
        else
        {
          NanThrowTypeError("Parse buffer must be String or Buffer");
          NanReturnUndefined();
        }
      }
    else {
      NanThrowTypeError("Parse buffer must be String or Buffer");
      NanReturnUndefined();
    }
  }

  /** Parse a v8 String by first writing it to the expat parser's
      buffer */
  bool parseString(String &str, int isFinal)
  {
    int len = str.Utf8Length();
    if (len == 0)
      return true;

    void *buf = XML_GetBuffer(parser, len);
    assert(buf != NULL);
    assert(str.WriteUtf8(static_cast<char *>(buf), len) == len);

    return XML_ParseBuffer(parser, len, isFinal) != XML_STATUS_ERROR;
  }

  /** Parse a node.js Buffer directly */
  bool parseBuffer(Local<Object> buffer, int isFinal)
  {
    return XML_Parse(parser, Buffer::Data(buffer), Buffer::Length(buffer), isFinal) != XML_STATUS_ERROR;
  }

  /*** setEncoding() ***/

  static NAN_METHOD(SetEncoding)
  {
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    NanScope();

    if (args.Length() == 1 && args[0]->IsString())
      {
        XML_Char *encoding = new XML_Char[32];
        NanRawString(args[0], Nan::ASCII, NULL, encoding, 32, 0);

        int status = parser->setEncoding(encoding);

        delete[] encoding;

        NanReturnValue(status ? True() : False());
      }
    else
      NanReturnValue(False());
  }

  int setEncoding(XML_Char *encoding)
  {
    return XML_SetEncoding(parser, encoding) != 0;
  }

  /*** getError() ***/

  static NAN_METHOD(GetError)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    const XML_LChar *error = parser->getError();
    if (error)
      NanReturnValue(String::New(error));
    else
      NanReturnValue(Null());
  }

  /*** stop() ***/

  static NAN_METHOD(Stop)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    int status = parser->stop();

    NanReturnValue(status ? True() : False());
  }

  int stop()
  {
    return XML_StopParser(parser, XML_TRUE) != 0;
  }

  /*** resume() ***/

  static NAN_METHOD(Resume)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    int status = parser->resume();

    NanReturnValue(status ? True() : False());
  }

  int resume()
  {
    return XML_ResumeParser(parser) != 0;
  }

  static NAN_METHOD(Reset)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    XML_Char *encoding = NULL;
    if (args.Length() == 1 && args[0]->IsString())
      {
        encoding = new XML_Char[32];
        NanRawString(args[0], Nan::ASCII, NULL, encoding, 32, 0);
      }

    int status = parser->reset(encoding);
    if (status)
      parser->attachHandlers();
    NanReturnValue(status ? True() : False());
  }

  int reset(XML_Char *encoding)
  {
      return XML_ParserReset(parser, encoding) != 0;
  }
  const XML_LChar *getError()
  {
    enum XML_Error code;
    code = XML_GetErrorCode(parser);
    return XML_ErrorString(code);
  }

  static NAN_METHOD(GetCurrentLineNumber)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    NanReturnValue(Integer::NewFromUnsigned(parser->getCurrentLineNumber()));
  }

  uint32_t getCurrentLineNumber()
  {
    return XML_GetCurrentLineNumber(parser);
  }

  static NAN_METHOD(GetCurrentColumnNumber)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    NanReturnValue(Integer::NewFromUnsigned(parser->getCurrentColumnNumber()));
  }

  uint32_t getCurrentColumnNumber()
  {
    return XML_GetCurrentColumnNumber(parser);
  }

  static NAN_METHOD(GetCurrentByteIndex)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    NanReturnValue(Integer::New(parser->getCurrentByteIndex()));
  }

  int32_t getCurrentByteIndex()
  {
    return XML_GetCurrentByteIndex(parser);
  }

private:
  /* expat instance */
  XML_Parser parser;

  /* no default ctor */
  Parser();

  /*** SAX callbacks ***/
  /* Should a local HandleScope be used in those callbacks? */

  static void StartElement(void *userData,
                           const XML_Char *name, const XML_Char **atts)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Collect atts into JS object */
    Local<Object> attr = Object::New();
    for(const XML_Char **atts1 = atts; *atts1; atts1 += 2)
      attr->Set(String::New(atts1[0]), String::New(atts1[1]));

    /* Trigger event */
    Handle<Value> argv[3] = { NanNew<String>("startElement"),
                              String::New(name),
                              attr };
    parser->Emit(3, argv);
  }

  static void EndElement(void *userData,
                         const XML_Char *name)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[2] = { NanNew<String>("endElement"), String::New(name) };
    parser->Emit(2, argv);
  }

  static void StartCdata(void *userData)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[1] = { NanNew<String>("startCdata") };
    parser->Emit(1, argv);
  }

  static void EndCdata(void *userData)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[1] = { NanNew<String>("endCdata") };
    parser->Emit(1, argv);
  }

  static void Text(void *userData,
                   const XML_Char *s, int len)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[2] = { NanNew<String>("text"),
                              String::New(s, len) };
    parser->Emit(2, argv);
  }

  static void ProcessingInstruction(void *userData,
                                    const XML_Char *target, const XML_Char *data)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[3] = { NanNew<String>("processingInstruction"),
                              String::New(target),
                              String::New(data) };
    parser->Emit(3, argv);
  }

  static void Comment(void *userData,
                      const XML_Char *data)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[2] = { NanNew<String>("comment"), String::New(data) };
    parser->Emit(2, argv);
  }

  static void XmlDecl(void *userData,
                      const XML_Char *version, const XML_Char *encoding,
                      int standalone)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Local<Value> argv[4] = { NanNew<String>("xmlDecl"),
                              version ? NanNew<Value>(String::NewSymbol(version))
                                      : NanNew<Value>(NanNull()),
                              encoding ? NanNew<Value>(String::NewSymbol(encoding))
                                      : NanNew<Value>(NanNull()),
                              standalone ? NanNew<Value>(NanTrue()) : NanNew<Value>(NanFalse()) };
    parser->Emit(4, argv);
  }

  static void EntityDecl(void *userData, const XML_Char *entityName, int is_parameter_entity,
                         const XML_Char *value, int value_length, const XML_Char *base,
                         const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Local<Value> argv[8] = { NanNew<String>("entityDecl"),
                              entityName ? NanNew<Value>(String::NewSymbol(entityName))
                                    : NanNew<Value>(NanNull()),
                              is_parameter_entity ? NanNew<Value>(NanTrue()) : NanNew<Value>(NanFalse()),
                              value ? NanNew<Value>(String::NewSymbol(value, value_length))
                                    : NanNew<Value>(NanNull()),
                              base ? NanNew<Value>(String::NewSymbol(base))
                                    : NanNew<Value>(NanNull()),
                              systemId ? NanNew<Value>(String::NewSymbol(systemId))
                                    : NanNew<Value>(NanNull()),
                              publicId ? NanNew<Value>(String::NewSymbol(publicId))
                                    : NanNew<Value>(NanNull()),
                              notationName ? NanNew<Value>(String::NewSymbol(notationName))
                                    : NanNew<Value>(NanNull())
    };
    parser->Emit(8, argv);
  }

  XML_Encoding *xmlEncodingInfo;

  static int UnknownEncoding(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(encodingHandlerData);

    /* Trigger event */
    parser->xmlEncodingInfo = info;
    Handle<Value> argv[2] = { NanNew<String>("unknownEncoding"),
                              name ? NanNew<Value>(String::New(name))
                                   : NanNew<Value>(NanNull())
    };
    parser->Emit(2, argv);

    /* Did no event handler invoke setUnknownEncoding()? */
    if (parser->xmlEncodingInfo) {
      parser->xmlEncodingInfo = NULL;
      return XML_STATUS_ERROR;
    } else {
      return XML_STATUS_OK;
    }
  }

  /**
   * Fills xmlEncodingInfo
   */
  static NAN_METHOD(SetUnknownEncoding)
  {
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    NanScope();

    if (!parser->xmlEncodingInfo)
      NanThrowError("setUnknownEncoding() must be synchronously invoked from an unknownEncoding event handler");

    if (args.Length() >= 1 && args[0]->IsArray()) {
      Local<Array> map = args[0].As<Array>();
      /* Copy map */
      for(int i = 0; i < 256; i++) {
        Local<Value> m = map->Get(Integer::New(i));
        if (m->IsInt32())
          parser->xmlEncodingInfo->map[i] = m->Int32Value();
        else
          NanThrowTypeError("UnknownEncoding map must consist of 256 ints");
      }
    } else
      NanThrowTypeError("SetUnknownEncoding expects a map array");

    parser->xmlEncodingInfo = NULL;
    NanReturnUndefined();
  }

  void Emit(int argc, Handle<Value> argv[])
  {
    NanScope();

    Handle<Object> handle = NanObjectWrapHandle(this);
    Local<Function> emit = handle->Get(NanNew<String>("emit")).As<Function>();
    emit->Call(handle, argc, argv);
  }
};

extern "C" {
  static void init (Handle<Object> target)
  {
    Parser::Initialize(target);
  }
  //Changed the name cause I couldn't load the module with - in their names
  NODE_MODULE(node_expat, init);
};

<commit_msg>node 0.11.13 / nan 1.2.0 compatible<commit_after>#include <nan.h>
extern "C" {
#include <expat.h>
}

using namespace v8;
using namespace node;

class Parser : public ObjectWrap {
public:
  static void Initialize(Handle<Object> target)
  {
    NanScope();
    Local<FunctionTemplate> t = NanNew<FunctionTemplate>(New);

    t->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(t, "parse", Parse);
    NODE_SET_PROTOTYPE_METHOD(t, "setEncoding", SetEncoding);
    NODE_SET_PROTOTYPE_METHOD(t, "setUnknownEncoding", SetUnknownEncoding);
    NODE_SET_PROTOTYPE_METHOD(t, "getError", GetError);
    NODE_SET_PROTOTYPE_METHOD(t, "stop", Stop);
    NODE_SET_PROTOTYPE_METHOD(t, "resume", Resume);
    NODE_SET_PROTOTYPE_METHOD(t, "reset", Reset);
    NODE_SET_PROTOTYPE_METHOD(t, "getCurrentLineNumber", GetCurrentLineNumber);
    NODE_SET_PROTOTYPE_METHOD(t, "getCurrentColumnNumber", GetCurrentColumnNumber);
    NODE_SET_PROTOTYPE_METHOD(t, "getCurrentByteIndex", GetCurrentByteIndex);

    target->Set(NanNew("Parser"), t->GetFunction());
  }

protected:
  /*** Constructor ***/

  static NAN_METHOD(New)
  {
    NanScope();
    XML_Char *encoding = NULL;
    if (args.Length() == 1 && args[0]->IsString())
      {
        encoding = new XML_Char[32];
        NanRawString(args[0], Nan::ASCII, NULL, encoding, 32, 0);
      }

    Parser *parser = new Parser(encoding);
    if (encoding)
      delete[] encoding;
    parser->Wrap(args.This());
    NanReturnValue(args.This());
  }

  Parser(const XML_Char *encoding)
    : ObjectWrap()
  {
    parser = XML_ParserCreate(encoding);
    assert(parser != NULL);

    attachHandlers();
  }

  ~Parser()
  {
    XML_ParserFree(parser);
  }

  void attachHandlers()
  {
    XML_SetUserData(parser, this);
    XML_SetElementHandler(parser, StartElement, EndElement);
    XML_SetCharacterDataHandler(parser, Text);
    XML_SetCdataSectionHandler(parser, StartCdata, EndCdata);
    XML_SetProcessingInstructionHandler(parser, ProcessingInstruction);
    XML_SetCommentHandler(parser, Comment);
    XML_SetXmlDeclHandler(parser, XmlDecl);
    XML_SetEntityDeclHandler(parser, EntityDecl);
    XML_SetUnknownEncodingHandler(parser, UnknownEncoding, this);
  }

  /*** parse() ***/

  static NAN_METHOD(Parse)
  {
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    NanScope();
    Local<String> str;
    int isFinal = 0;

    /* Argument 2: isFinal :: Bool */
    if (args.Length() >= 2)
      {
        isFinal = args[1]->IsTrue();
      }

    /* Argument 1: buf :: String or Buffer */
    if (args.Length() >= 1 && args[0]->IsString())
      {
        str = args[0]->ToString();
        NanReturnValue(parser->parseString(**str, isFinal) ? NanTrue() : NanFalse());
      }
    else if (args.Length() >= 1 && args[0]->IsObject())
      {
        Local<Object> obj = args[0]->ToObject();
        if (Buffer::HasInstance(obj))
        {
          NanReturnValue(parser->parseBuffer(obj, isFinal) ? NanTrue() : NanFalse());
        }
        else
        {
          NanThrowTypeError("Parse buffer must be String or Buffer");
          NanReturnUndefined();
        }
      }
    else {
      NanThrowTypeError("Parse buffer must be String or Buffer");
      NanReturnUndefined();
    }
  }

  /** Parse a v8 String by first writing it to the expat parser's
      buffer */
  bool parseString(String &str, int isFinal)
  {
    int len = str.Utf8Length();
    if (len == 0)
      return true;

    void *buf = XML_GetBuffer(parser, len);
    assert(buf != NULL);
    assert(str.WriteUtf8(static_cast<char *>(buf), len) == len);

    return XML_ParseBuffer(parser, len, isFinal) != XML_STATUS_ERROR;
  }

  /** Parse a node.js Buffer directly */
  bool parseBuffer(Local<Object> buffer, int isFinal)
  {
    return XML_Parse(parser, Buffer::Data(buffer), Buffer::Length(buffer), isFinal) != XML_STATUS_ERROR;
  }

  /*** setEncoding() ***/

  static NAN_METHOD(SetEncoding)
  {
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    NanScope();

    if (args.Length() == 1 && args[0]->IsString())
      {
        XML_Char *encoding = new XML_Char[32];
        NanRawString(args[0], Nan::ASCII, NULL, encoding, 32, 0);

        int status = parser->setEncoding(encoding);

        delete[] encoding;

        NanReturnValue(status ? NanTrue() : NanFalse());
      }
    else
      NanReturnValue(NanFalse());
  }

  int setEncoding(XML_Char *encoding)
  {
    return XML_SetEncoding(parser, encoding) != 0;
  }

  /*** getError() ***/

  static NAN_METHOD(GetError)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    const XML_LChar *error = parser->getError();
    if (error)
      NanReturnValue(NanNew(error));
    else
      NanReturnValue(NanNull());
  }

  /*** stop() ***/

  static NAN_METHOD(Stop)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    int status = parser->stop();

    NanReturnValue(status ? NanTrue() : NanFalse());
  }

  int stop()
  {
    return XML_StopParser(parser, XML_TRUE) != 0;
  }

  /*** resume() ***/

  static NAN_METHOD(Resume)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    int status = parser->resume();

    NanReturnValue(status ? NanTrue() : NanFalse());
  }

  int resume()
  {
    return XML_ResumeParser(parser) != 0;
  }

  static NAN_METHOD(Reset)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    XML_Char *encoding = NULL;
    if (args.Length() == 1 && args[0]->IsString())
      {
        encoding = new XML_Char[32];
        NanRawString(args[0], Nan::ASCII, NULL, encoding, 32, 0);
      }

    int status = parser->reset(encoding);
    if (status)
      parser->attachHandlers();
    NanReturnValue(status ? NanTrue() : NanFalse());
  }

  int reset(XML_Char *encoding)
  {
      return XML_ParserReset(parser, encoding) != 0;
  }
  const XML_LChar *getError()
  {
    enum XML_Error code;
    code = XML_GetErrorCode(parser);
    return XML_ErrorString(code);
  }

  static NAN_METHOD(GetCurrentLineNumber)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    NanReturnValue(NanNew(parser->getCurrentLineNumber()));
  }

  uint32_t getCurrentLineNumber()
  {
    return XML_GetCurrentLineNumber(parser);
  }

  static NAN_METHOD(GetCurrentColumnNumber)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    NanReturnValue(NanNew(parser->getCurrentColumnNumber()));
  }

  uint32_t getCurrentColumnNumber()
  {
    return XML_GetCurrentColumnNumber(parser);
  }

  static NAN_METHOD(GetCurrentByteIndex)
  {
    NanScope();
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());

    NanReturnValue(NanNew(parser->getCurrentByteIndex()));
  }

  int32_t getCurrentByteIndex()
  {
    return XML_GetCurrentByteIndex(parser);
  }

private:
  /* expat instance */
  XML_Parser parser;

  /* no default ctor */
  Parser();

  /*** SAX callbacks ***/
  /* Should a local HandleScope be used in those callbacks? */

  static void StartElement(void *userData,
                           const XML_Char *name, const XML_Char **atts)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Collect atts into JS object */
    Local<Object> attr = NanNew<Object>();
    for(const XML_Char **atts1 = atts; *atts1; atts1 += 2)
      attr->Set(NanNew(atts1[0]), NanNew(atts1[1]));

    /* Trigger event */
    Handle<Value> argv[3] = { NanNew("startElement"),
                              NanNew(name),
                              attr };
    parser->Emit(3, argv);
  }

  static void EndElement(void *userData,
                         const XML_Char *name)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[2] = { NanNew("endElement"), NanNew(name) };
    parser->Emit(2, argv);
  }

  static void StartCdata(void *userData)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[1] = { NanNew("startCdata") };
    parser->Emit(1, argv);
  }

  static void EndCdata(void *userData)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[1] = { NanNew("endCdata") };
    parser->Emit(1, argv);
  }

  static void Text(void *userData,
                   const XML_Char *s, int len)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[2] = { NanNew("text"),
                              NanNew(s, len) };
    parser->Emit(2, argv);
  }

  static void ProcessingInstruction(void *userData,
                                    const XML_Char *target, const XML_Char *data)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[3] = { NanNew("processingInstruction"),
                              NanNew(target),
                              NanNew(data) };
    parser->Emit(3, argv);
  }

  static void Comment(void *userData,
                      const XML_Char *data)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Handle<Value> argv[2] = { NanNew("comment"), NanNew(data) };
    parser->Emit(2, argv);
  }

  static void XmlDecl(void *userData,
                      const XML_Char *version, const XML_Char *encoding,
                      int standalone)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Local<Value> argv[4];

                    argv[0] = NanNew("xmlDecl");
    if (version)    argv[1] = NanNew(version);
    else            argv[1] = NanNull();
    if (encoding)   argv[2] = NanNew(encoding);
    else            argv[2] = NanNull();
    if (standalone) argv[3] = NanTrue();
    else            argv[3] = NanFalse();

    parser->Emit(4, argv);
  }

  static void EntityDecl(void *userData, const XML_Char *entityName, int is_parameter_entity,
                         const XML_Char *value, int value_length, const XML_Char *base,
                         const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(userData);

    /* Trigger event */
    Local<Value> argv[8];

                             argv[0] = NanNew("entityDecl");
    if (entityName)          argv[1] = NanNew(entityName);
    else                     argv[1] = NanNull();
    if (is_parameter_entity) argv[2] = NanTrue();
    else                     argv[2] = NanFalse();
    if (value)               argv[3] = NanNew(value, value_length);
    else                     argv[3] = NanNull();
    if (base)                argv[4] = NanNew(base);
    else                     argv[4] = NanNull();
    if (systemId)            argv[5] = NanNew(systemId);
    else                     argv[5] = NanNull();
    if (publicId)            argv[6] = NanNew(publicId);
    else                     argv[6] = NanNull();
    if (notationName)        argv[7] = NanNew(notationName);
    else                     argv[7] = NanNull();

    parser->Emit(8, argv);
  }

  XML_Encoding *xmlEncodingInfo;

  static int UnknownEncoding(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info)
  {
    NanScope();
    Parser *parser = reinterpret_cast<Parser *>(encodingHandlerData);

    /* Trigger event */
    parser->xmlEncodingInfo = info;
    Local<Value> argv[2];

              argv[0] = NanNew("unknownEncoding");
    if (name) argv[1] = NanNew(name);
    else      argv[1] = NanNull();

    parser->Emit(2, argv);

    /* Did no event handler invoke setUnknownEncoding()? */
    if (parser->xmlEncodingInfo) {
      parser->xmlEncodingInfo = NULL;
      return XML_STATUS_ERROR;
    } else {
      return XML_STATUS_OK;
    }
  }

  /**
   * Fills xmlEncodingInfo
   */
  static NAN_METHOD(SetUnknownEncoding)
  {
    Parser *parser = ObjectWrap::Unwrap<Parser>(args.This());
    NanScope();

    if (!parser->xmlEncodingInfo)
      NanThrowError("setUnknownEncoding() must be synchronously invoked from an unknownEncoding event handler");

    if (args.Length() >= 1 && args[0]->IsArray()) {
      Local<Array> map = args[0].As<Array>();
      /* Copy map */
      for(int i = 0; i < 256; i++) {
        Local<Value> m = map->Get(NanNew(i));
        if (m->IsInt32())
          parser->xmlEncodingInfo->map[i] = m->Int32Value();
        else
          NanThrowTypeError("UnknownEncoding map must consist of 256 ints");
      }
    } else
      NanThrowTypeError("SetUnknownEncoding expects a map array");

    parser->xmlEncodingInfo = NULL;
    NanReturnUndefined();
  }

  void Emit(int argc, Handle<Value> argv[])
  {
    NanScope();

    Handle<Object> handle = NanObjectWrapHandle(this);
    Local<Function> emit = handle->Get(NanNew("emit")).As<Function>();
    emit->Call(handle, argc, argv);
  }
};

extern "C" {
  static void init (Handle<Object> target)
  {
    Parser::Initialize(target);
  }
  //Changed the name cause I couldn't load the module with - in their names
  NODE_MODULE(node_expat, init);
};

<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2014, 2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mavlink_orb_subscription.cpp
 * uORB subscription implementation.
 *
 * @author Anton Babushkin <anton.babushkin@me.com>
 * @author Lorenz Meier <lorenz@px4.io>
 */

#include "mavlink_orb_subscription.h"

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <px4_defines.h>
#include <uORB/uORB.h>

MavlinkOrbSubscription::MavlinkOrbSubscription(const orb_id_t topic, int instance) :
	next(nullptr),
	_topic(topic),
	_fd(-1),
	_instance(instance),
	_published(false),
	_subscribe_from_beginning(false),
	_last_pub_check(0)
{
}

MavlinkOrbSubscription::~MavlinkOrbSubscription()
{
	if (_fd >= 0) {
		orb_unsubscribe(_fd);
	}
}

orb_id_t
MavlinkOrbSubscription::get_topic() const
{
	return _topic;
}

int
MavlinkOrbSubscription::get_instance() const
{
	return _instance;
}

bool
MavlinkOrbSubscription::update(uint64_t *time, void *data)
{

	// TODO this is NOT atomic operation, we can get data newer than time
	// if topic was published between orb_stat and orb_copy calls.

	uint64_t time_topic;

	if (orb_stat(_fd, &time_topic)) {
		/* error getting last topic publication time */
		time_topic = 0;
	}

	if (update(data)) {
		/* data copied successfully */

		if (time_topic == 0 || (time_topic != *time)) {
			*time = time_topic;
			return true;

		} else {
			return false;
		}
	}

	return false;
}

bool
MavlinkOrbSubscription::update(void *data)
{
	if (!is_published()) {
		return false;
	}

	if (orb_copy(_topic, _fd, data)) {
		if (data != nullptr) {
			/* error copying topic data */
			memset(data, 0, _topic->o_size);
		}

		return false;
	}

	return true;
}

bool
MavlinkOrbSubscription::update_if_changed(void *data)
{
	bool prevpub = _published;

	if (!is_published()) {
		return false;
	}

	bool updated;

	if (orb_check(_fd, &updated)) {
		return false;
	}

	// If we didn't update and this topic did not change
	// its publication status then nothing really changed
	if (!updated && prevpub == _published) {
		return false;
	}

	return update(data);
}

bool
MavlinkOrbSubscription::is_published()
{
	// If we marked it as published no need to check again
	if (_published) {
		return true;
	}

	// Telemetry can sustain an initial published check at 10 Hz
	hrt_abstime now = hrt_absolute_time();

	if (now - _last_pub_check < 100000) {
		return false;
	}

	// We are checking now
	_last_pub_check = now;

#if defined(__PX4_QURT) || defined(__PX4_POSIX_EAGLE) || defined(__PX4_POSIX_EXCELSIOR)

	// Snapdragon has currently no support for orb_exists, therefore
	// we're not using it.
	if (_fd < 0) {
		_fd = orb_subscribe_multi(_topic, _instance);
	}

#else

	// We don't want to subscribe to anything that does not exist
	// in order to save memory and file descriptors.
	// However, for some topics like vehicle_command_ack, we want to subscribe
	// from the beginning in order not to miss the first publish respective advertise.
	if (!_subscribe_from_beginning && orb_exists(_topic, _instance)) {
		return false;
	}

	if (_fd < 0) {
		_fd = orb_subscribe_multi(_topic, _instance);
	}

#endif

	bool updated;
	orb_check(_fd, &updated);

	if (updated) {
		_published = true;
	}

	// topic may have been last published before we subscribed
	uint64_t time_topic = 0;

	if (!_published && orb_stat(_fd, &time_topic) == PX4_OK) {
		if (time_topic != 0) {
			_published = true;
		}
	}

	return _published;
}

void
MavlinkOrbSubscription::subscribe_from_beginning(bool from_beginning)
{
	_subscribe_from_beginning = from_beginning;
}
<commit_msg>updated to remove a compilation flag check as  orb_exists()  is already supported<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2014, 2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mavlink_orb_subscription.cpp
 * uORB subscription implementation.
 *
 * @author Anton Babushkin <anton.babushkin@me.com>
 * @author Lorenz Meier <lorenz@px4.io>
 */

#include "mavlink_orb_subscription.h"

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <px4_defines.h>
#include <uORB/uORB.h>

MavlinkOrbSubscription::MavlinkOrbSubscription(const orb_id_t topic, int instance) :
	next(nullptr),
	_topic(topic),
	_fd(-1),
	_instance(instance),
	_published(false),
	_subscribe_from_beginning(false),
	_last_pub_check(0)
{
}

MavlinkOrbSubscription::~MavlinkOrbSubscription()
{
	if (_fd >= 0) {
		orb_unsubscribe(_fd);
	}
}

orb_id_t
MavlinkOrbSubscription::get_topic() const
{
	return _topic;
}

int
MavlinkOrbSubscription::get_instance() const
{
	return _instance;
}

bool
MavlinkOrbSubscription::update(uint64_t *time, void *data)
{

	// TODO this is NOT atomic operation, we can get data newer than time
	// if topic was published between orb_stat and orb_copy calls.

	uint64_t time_topic;

	if (orb_stat(_fd, &time_topic)) {
		/* error getting last topic publication time */
		time_topic = 0;
	}

	if (update(data)) {
		/* data copied successfully */

		if (time_topic == 0 || (time_topic != *time)) {
			*time = time_topic;
			return true;

		} else {
			return false;
		}
	}

	return false;
}

bool
MavlinkOrbSubscription::update(void *data)
{
	if (!is_published()) {
		return false;
	}

	if (orb_copy(_topic, _fd, data)) {
		if (data != nullptr) {
			/* error copying topic data */
			memset(data, 0, _topic->o_size);
		}

		return false;
	}

	return true;
}

bool
MavlinkOrbSubscription::update_if_changed(void *data)
{
	bool prevpub = _published;

	if (!is_published()) {
		return false;
	}

	bool updated;

	if (orb_check(_fd, &updated)) {
		return false;
	}

	// If we didn't update and this topic did not change
	// its publication status then nothing really changed
	if (!updated && prevpub == _published) {
		return false;
	}

	return update(data);
}

bool
MavlinkOrbSubscription::is_published()
{
	// If we marked it as published no need to check again
	if (_published) {
		return true;
	}

	// Telemetry can sustain an initial published check at 10 Hz
	hrt_abstime now = hrt_absolute_time();

	if (now - _last_pub_check < 100000) {
		return false;
	}

	// We are checking now
	_last_pub_check = now;

	// We don't want to subscribe to anything that does not exist
	// in order to save memory and file descriptors.
	// However, for some topics like vehicle_command_ack, we want to subscribe
	// from the beginning in order not to miss the first publish respective advertise.
	if (!_subscribe_from_beginning && orb_exists(_topic, _instance)) {
		return false;
	}

	if (_fd < 0) {
		_fd = orb_subscribe_multi(_topic, _instance);
	}

	bool updated;
	orb_check(_fd, &updated);

	if (updated) {
		_published = true;
	}

	// topic may have been last published before we subscribed
	uint64_t time_topic = 0;

	if (!_published && orb_stat(_fd, &time_topic) == PX4_OK) {
		if (time_topic != 0) {
			_published = true;
		}
	}

	return _published;
}

void
MavlinkOrbSubscription::subscribe_from_beginning(bool from_beginning)
{
	_subscribe_from_beginning = from_beginning;
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2019)

#ifndef DUNE_GDT_TEST_STATIONARY_EOCSTUDIES_DIFFUSION_IPDG_HH
#define DUNE_GDT_TEST_STATIONARY_EOCSTUDIES_DIFFUSION_IPDG_HH

#include <dune/xt/la/container.hh>
#include <dune/xt/grid/boundaryinfo/interfaces.hh>
#include <dune/xt/grid/filters/intersection.hh>
#include <dune/xt/grid/layers.hh>
#include <dune/xt/functions/interfaces/grid-function.hh>

#include <dune/gdt/functionals/vector-based.hh>
#include <dune/gdt/local/functionals/integrals.hh>
#include <dune/gdt/local/bilinear-forms/integrals.hh>
#include <dune/gdt/local/integrands/elliptic-ipdg.hh>
#include <dune/gdt/local/integrands/elliptic.hh>
#include <dune/gdt/local/integrands/product.hh>
#include <dune/gdt/local/integrands/conversion.hh>
#include <dune/gdt/norms.hh>
#include <dune/gdt/operators/constant.hh>
#include <dune/gdt/operators/lincomb.hh>
#include <dune/gdt/operators/matrix-based.hh>
#include <dune/gdt/operators/oswald-interpolation.hh>
#include <dune/gdt/spaces/l2/discontinuous-lagrange.hh>
#include <dune/gdt/spaces/l2/finite-volume.hh>
#include <dune/gdt/spaces/h1/continuous-lagrange.hh>

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Test {

/**
 * \todo Add treatment of nonzero Dirichlet boundary values
 * \todo Add treatment of Neumann boundary values
 */
template <class G,
          LocalEllipticIpdgIntegrands::Method ipdg_method = LocalEllipticIpdgIntegrands::Method::swipdg,
          XT::LA::Backends la = XT::LA::Backends::istl_sparse>
class StationaryDiffusionIpdgEocStudy
  : public StationaryEocStudy<typename XT::Grid::Layer<G, XT::Grid::Layers::leaf, XT::Grid::Backends::view>::type,
                              1,
                              la>
{
protected:
  using BaseType =
      StationaryEocStudy<typename XT::Grid::Layer<G, XT::Grid::Layers::leaf, XT::Grid::Backends::view>::type, 1, la>;

  using BaseType::d;
  using typename BaseType::DF;
  using typename BaseType::E;
  using typename BaseType::GP;
  using typename BaseType::GV;
  using typename BaseType::I;
  using typename BaseType::M;
  using typename BaseType::O;
  using typename BaseType::S;
  using typename BaseType::V;

  using FF = XT::Functions::GridFunctionInterface<E>;
  using FT = XT::Functions::GridFunctionInterface<E, d, d>;

public:
  StationaryDiffusionIpdgEocStudy()
    : BaseType()
    , space_type_("")
  {}

protected:
  virtual const XT::Grid::BoundaryInfo<I>& boundary_info() const = 0;

  virtual const FF& diffusion_factor() const = 0;

  virtual const FT& diffusion_tensor() const = 0;

  virtual const FF& force() const = 0;

  virtual std::vector<std::string> norms() const override
  {
    auto nrms = BaseType::norms();
    nrms.push_back("eta_NC");
    return nrms;
  }

  virtual std::map<std::string, std::map<std::string, double>>
  compute(const size_t refinement_level,
          const std::vector<std::string>& actual_norms,
          const std::vector<std::pair<std::string, std::string>>& actual_estimates,
          const std::vector<std::string>& actual_quantities) override
  {
    auto& self = *this;
    // compute the quantities/norms/estimates we known about and remove them from the todos
    // store the data in current_data_, BaseType::compute will return that
    auto remaining_norms = actual_norms;
    auto remaining_estimates = actual_estimates;
    auto remaining_quantities = actual_quantities;
    for (auto norm_it = remaining_norms.begin(); norm_it != remaining_norms.end(); /*Do not increment here ...*/) {
      const auto norm_id = *norm_it;
      if (norm_id == "eta_NC") {
        norm_it = remaining_norms.erase(norm_it); // ... but rather here ...
        if (self.current_refinement_ != refinement_level)
          self.discretization_info(refinement_level);
        DUNE_THROW_IF(!self.current_space_, InvalidStateException, "");
        // compute current solution
        const auto& current_space = *self.current_space_;
        Timer timer;
        const auto solution = make_discrete_function(current_space, self.solve(current_space));
        // only set time if this did not happen in solve()
        if (self.current_data_["quantity"].count("time to solution (s)") == 0)
          self.current_data_["quantity"]["time to solution (s)"] = timer.elapsed();
        // compute estimate
        const auto h1_interpolation = apply_oswald_interpolation(solution, current_space, boundary_info());
        self.current_data_["norm"][norm_id] = elliptic_norm(
            current_space.grid_view(), diffusion_factor(), diffusion_tensor(), solution - h1_interpolation);
      } else
        ++norm_it; // ... or finally here.
    } // norms
    // let the Base compute the rest
    return BaseType::compute(refinement_level, remaining_norms, remaining_estimates, remaining_quantities);
  } // ... compute(...)

  virtual std::unique_ptr<S> make_space(const GP& current_grid) override
  {
    if (space_type_ == "fv")
      return std::make_unique<FiniteVolumeSpace<GV>>(current_grid.leaf_view());
    else if (space_type_.size() >= 4 && space_type_.substr(0, 4) == "dg_p") {
      const auto order = XT::Common::from_string<int>(space_type_.substr(4));
      return std::make_unique<DiscontinuousLagrangeSpace<GV>>(current_grid.leaf_view(), order);
    } else if (space_type_.size() >= 4 && space_type_.substr(0, 4) == "cg_p") {
      const auto order = XT::Common::from_string<int>(space_type_.substr(4));
      return std::make_unique<ContinuousLagrangeSpace<GV>>(current_grid.leaf_view(), order);
    } else {
      DUNE_THROW(XT::Common::Exceptions::wrong_input_given, "space_type_ = " << space_type_);
      return nullptr;
    }
  } // ... make_space(...)

  virtual std::unique_ptr<O> make_residual_operator(const S& space) override
  {
    // define lhs operator (has to be a pointer to allow the residual operator to manage the memory in the end)
    auto lhs_op = std::make_unique<MatrixOperator<M, GV>>(make_matrix_operator<M>(
        space,
        (space_type_.size() >= 2 && space_type_.substr(0, 2) == "cg") ? Stencil::element
                                                                      : Stencil::element_and_intersection));
    lhs_op->append(
        LocalElementIntegralBilinearForm<E>(LocalEllipticIntegrand<E>(diffusion_factor(), diffusion_tensor())));
    lhs_op->append(LocalIntersectionIntegralBilinearForm<I>(LocalEllipticIpdgIntegrands::Inner<I, double, ipdg_method>(
                       diffusion_factor(), diffusion_tensor())),
                   {},
                   XT::Grid::ApplyOn::InnerIntersectionsOnce<GV>());
    lhs_op->append(
        LocalIntersectionIntegralBilinearForm<I>(
            LocalEllipticIpdgIntegrands::DirichletBoundaryLhs<I, double, ipdg_method>(diffusion_factor(),
                                                                                diffusion_tensor())),
        {},
        XT::Grid::ApplyOn::CustomBoundaryIntersections<GV>(boundary_info(), new XT::Grid::DirichletBoundary()));
    // define rhs functional
    auto rhs_func = make_vector_functional<V>(space);
    rhs_func.append(LocalElementIntegralFunctional<E>(
        local_binary_to_unary_element_integrand(LocalElementProductIntegrand<E>(), force())));
    // ... add Dirichlet here
    // (if we add something here, the oswald interpolation in compute() needs to be adapted accordingly!)
    // ... add Neumann here
    // assemble everything in one grid walk
    lhs_op->append(rhs_func);
    lhs_op->assemble(DXTC_TEST_CONFIG_GET("setup.use_tbb", true));
    // build residual operator
    auto residual_op = std::make_unique<ConstLincombOperator<M, GV>>(space, space);
    residual_op->add(lhs_op.release(), 1.);
    residual_op->add(new ConstantOperator<M, GV>(space, space, new V(std::move(rhs_func.vector()))), -1);
    return residual_op;
  } // ... make_residual_operator(...)

  std::string space_type_;
}; // class StationaryDiffusionIpdgEocStudy

} // namespace Test
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_TEST_STATIONARY_EOCSTUDIES_DIFFUSION_IPDG_HH
<commit_msg>[test.stationary...diddusion-ipdg] add eta_DF<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2019)

#ifndef DUNE_GDT_TEST_STATIONARY_EOCSTUDIES_DIFFUSION_IPDG_HH
#define DUNE_GDT_TEST_STATIONARY_EOCSTUDIES_DIFFUSION_IPDG_HH

#include <atomic>

#include <dune/xt/la/container.hh>
#include <dune/xt/la/matrix-inverter.hh>
#include <dune/xt/grid/boundaryinfo/interfaces.hh>
#include <dune/xt/grid/filters/intersection.hh>
#include <dune/xt/grid/layers.hh>
#include <dune/xt/functions/interfaces/grid-function.hh>

#include <dune/gdt/functionals/vector-based.hh>
#include <dune/gdt/local/functionals/integrals.hh>
#include <dune/gdt/local/bilinear-forms/integrals.hh>
#include <dune/gdt/local/integrands/elliptic-ipdg.hh>
#include <dune/gdt/local/integrands/elliptic.hh>
#include <dune/gdt/local/integrands/product.hh>
#include <dune/gdt/local/integrands/conversion.hh>
#include <dune/gdt/norms.hh>
#include <dune/gdt/operators/constant.hh>
#include <dune/gdt/operators/ipdg-flux-reconstruction.hh>
#include <dune/gdt/operators/lincomb.hh>
#include <dune/gdt/operators/matrix-based.hh>
#include <dune/gdt/operators/oswald-interpolation.hh>
#include <dune/gdt/spaces/l2/discontinuous-lagrange.hh>
#include <dune/gdt/spaces/l2/finite-volume.hh>
#include <dune/gdt/spaces/h1/continuous-lagrange.hh>
#include <dune/gdt/spaces/hdiv/raviart-thomas.hh>

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Test {

/**
 * \todo Add treatment of nonzero Dirichlet boundary values
 * \todo Add treatment of Neumann boundary values
 */
template <class G,
          LocalEllipticIpdgIntegrands::Method ipdg_method = LocalEllipticIpdgIntegrands::Method::swipdg,
          XT::LA::Backends la = XT::LA::Backends::istl_sparse>
class StationaryDiffusionIpdgEocStudy
  : public StationaryEocStudy<typename XT::Grid::Layer<G, XT::Grid::Layers::leaf, XT::Grid::Backends::view>::type,
                              1,
                              la>
{
protected:
  using BaseType =
      StationaryEocStudy<typename XT::Grid::Layer<G, XT::Grid::Layers::leaf, XT::Grid::Backends::view>::type, 1, la>;

  using BaseType::d;
  using typename BaseType::DF;
  using typename BaseType::E;
  using typename BaseType::GP;
  using typename BaseType::GV;
  using typename BaseType::I;
  using typename BaseType::M;
  using typename BaseType::O;
  using typename BaseType::S;
  using typename BaseType::V;

  using FF = XT::Functions::GridFunctionInterface<E>;
  using FT = XT::Functions::GridFunctionInterface<E, d, d>;

public:
  StationaryDiffusionIpdgEocStudy()
    : BaseType()
    , space_type_("")
  {}

protected:
  virtual const XT::Grid::BoundaryInfo<I>& boundary_info() const = 0;

  virtual const FF& diffusion_factor() const = 0;

  virtual const FT& diffusion_tensor() const = 0;

  virtual const FF& force() const = 0;

  virtual std::vector<std::string> norms() const override
  {
    auto nrms = BaseType::norms();
    nrms.push_back("eta_NC");
    nrms.push_back("eta_DF");
    return nrms;
  }

  virtual std::map<std::string, std::map<std::string, double>>
  compute(const size_t refinement_level,
          const std::vector<std::string>& actual_norms,
          const std::vector<std::pair<std::string, std::string>>& actual_estimates,
          const std::vector<std::string>& actual_quantities) override
  {
    auto& self = *this;
    // compute the quantities/norms/estimates we known about and remove them from the todos
    // store the data in current_data_, BaseType::compute will return that
    auto remaining_norms = actual_norms;
    auto remaining_estimates = actual_estimates;
    auto remaining_quantities = actual_quantities;
    if (self.current_refinement_ != refinement_level)
      self.discretization_info(refinement_level);
    DUNE_THROW_IF(!self.current_space_, InvalidStateException, "");
    // compute current solution
    const auto& current_space = *self.current_space_;
    // visualize
    if (DXTC_TEST_CONFIG_GET("setup.visualize", false)) {
      const std::string prefix = XT::Common::Test::get_unique_test_name() + "_problem_";
      const std::string postfix = "_ref_" + XT::Common::to_string(refinement_level);
      self.diffusion_factor().visualize(current_space.grid_view(), prefix + "diffusion_factor" + postfix);
      self.diffusion_tensor().visualize(current_space.grid_view(), prefix + "diffusion_tensor" + postfix);
      self.force().visualize(current_space.grid_view(), prefix + "force" + postfix);
      //      self.dirichlet().visualize(current_space.grid_view(), prefix + "dirichlet" + postfix);
      //      self.neumann().visualize(current_space.grid_view(), prefix + "neumann" + postfix);
    }
    Timer timer;
    const auto solution = make_discrete_function(current_space, self.solve(current_space));
    // only set time if this did not happen in solve()
    if (self.current_data_["quantity"].count("time to solution (s)") == 0)
      self.current_data_["quantity"]["time to solution (s)"] = timer.elapsed();
    for (auto norm_it = remaining_norms.begin(); norm_it != remaining_norms.end(); /*Do not increment here ...*/) {
      const auto norm_id = *norm_it;
      if (norm_id == "eta_NC") {
        norm_it = remaining_norms.erase(norm_it); // ... but rather here ...
        // compute estimate
        auto oswald_interpolation_operator = make_oswald_interpolation_operator<M>(
            current_space.grid_view(), current_space, current_space, boundary_info());
        oswald_interpolation_operator.assemble(/*parallel=*/true);
        const auto h1_interpolation = oswald_interpolation_operator.apply(solution);
        self.current_data_["norm"][norm_id] = elliptic_norm(
            current_space.grid_view(), diffusion_factor(), diffusion_tensor(), solution - h1_interpolation);
      } else if (norm_id == "eta_DF") {
        norm_it = remaining_norms.erase(norm_it); // ... or here ...
        // compute estimate
        auto rt_space = make_raviart_thomas_space(current_space.grid_view(), current_space.max_polorder() - 1);
        auto reconstruction_op = make_ipdg_flux_reconstruction_operator<M, ipdg_method>(
            current_space.grid_view(), current_space, rt_space, diffusion_factor(), diffusion_tensor());
        auto flux_reconstruction = reconstruction_op.apply(solution);
        flux_reconstruction.visualize("flux_" + XT::Common::to_string(refinement_level));
        double eta_DF_2 = 0.;
        std::mutex eta_DF_2_mutex;
        auto walker = XT::Grid::make_walker(current_space.grid_view());
        walker.append([]() {},
                      [&](const auto& element) {
                        auto local_df = diffusion_factor().local_function();
                        local_df->bind(element);
                        auto local_dt = diffusion_tensor().local_function();
                        local_dt->bind(element);
                        auto local_solution = solution.local_function();
                        local_solution->bind(element);
                        auto local_reconstruction = flux_reconstruction.local_function();
                        local_reconstruction->bind(element);
                        auto result = LocalElementIntegralFunctional<E, d>(
                                          [&](const auto& basis, const auto& /*param*/) {
                                            return std::max(local_df->order() + local_dt->order()
                                                                + std::max(local_solution->order() - 1, 0),
                                                            basis.order());
                                          },
                                          [&](const auto& basis, const auto& xx, auto& result, const auto& /*param*/) {
                                            const auto df = local_df->evaluate(xx);
                                            const auto dt = local_dt->evaluate(xx);
                                            const auto diff = dt * df;
                                            const auto diff_inv = XT::LA::invert_matrix(diff);
                                            const auto solution_grad = local_solution->jacobian(xx)[0];
                                            const auto flux_rec = basis.evaluate_set(xx)[0];
                                            auto difference = diff * solution_grad + flux_rec;
                                            result[0] = (diff_inv * difference) * difference;
                                          },
                                          {},
                                          /*over_integrate=*/3)
                                          .apply(*local_reconstruction)[0];
                        std::lock_guard<std::mutex> lock(eta_DF_2_mutex);
                        eta_DF_2 += result;
                      },
                      []() {});
        walker.walk(/*parallel=*/true);
        self.current_data_["norm"][norm_id] = std::sqrt(eta_DF_2);
      } else
        ++norm_it; // ... or finally here.
    } // norms
    // let the Base compute the rest
    return BaseType::compute(refinement_level, remaining_norms, remaining_estimates, remaining_quantities);
  } // ... compute(...)

  virtual std::unique_ptr<S> make_space(const GP& current_grid) override
  {
    if (space_type_ == "fv")
      return std::make_unique<FiniteVolumeSpace<GV>>(current_grid.leaf_view());
    else if (space_type_.size() >= 4 && space_type_.substr(0, 4) == "dg_p") {
      const auto order = XT::Common::from_string<int>(space_type_.substr(4));
      return std::make_unique<DiscontinuousLagrangeSpace<GV>>(current_grid.leaf_view(), order);
    } else if (space_type_.size() >= 4 && space_type_.substr(0, 4) == "cg_p") {
      const auto order = XT::Common::from_string<int>(space_type_.substr(4));
      return std::make_unique<ContinuousLagrangeSpace<GV>>(current_grid.leaf_view(), order);
    } else {
      DUNE_THROW(XT::Common::Exceptions::wrong_input_given, "space_type_ = " << space_type_);
      return nullptr;
    }
  } // ... make_space(...)

  virtual std::unique_ptr<O> make_residual_operator(const S& space) override
  {
    // define lhs operator (has to be a pointer to allow the residual operator to manage the memory in the end)
    auto lhs_op = std::make_unique<MatrixOperator<M, GV>>(make_matrix_operator<M>(
        space,
        (space_type_.size() >= 2 && space_type_.substr(0, 2) == "cg") ? Stencil::element
                                                                      : Stencil::element_and_intersection));
    lhs_op->append(
        LocalElementIntegralBilinearForm<E>(LocalEllipticIntegrand<E>(diffusion_factor(), diffusion_tensor())));
    lhs_op->append(LocalIntersectionIntegralBilinearForm<I>(LocalEllipticIpdgIntegrands::Inner<I, double, ipdg_method>(
                       diffusion_factor(), diffusion_tensor())),
                   {},
                   XT::Grid::ApplyOn::InnerIntersectionsOnce<GV>());
    lhs_op->append(
        LocalIntersectionIntegralBilinearForm<I>(
            LocalEllipticIpdgIntegrands::DirichletBoundaryLhs<I, double, ipdg_method>(diffusion_factor(),
                                                                                diffusion_tensor())),
        {},
        XT::Grid::ApplyOn::CustomBoundaryIntersections<GV>(boundary_info(), new XT::Grid::DirichletBoundary()));
    // define rhs functional
    auto rhs_func = make_vector_functional<V>(space);
    rhs_func.append(LocalElementIntegralFunctional<E>(
        local_binary_to_unary_element_integrand(LocalElementProductIntegrand<E>(), force())));
    // ... add Dirichlet here
    // (if we add something here, the oswald interpolation in compute() needs to be adapted accordingly!)
    // ... add Neumann here
    // assemble everything in one grid walk
    lhs_op->append(rhs_func);
    lhs_op->assemble(DXTC_TEST_CONFIG_GET("setup.use_tbb", true));
    // build residual operator
    auto residual_op = std::make_unique<ConstLincombOperator<M, GV>>(space, space);
    residual_op->add(lhs_op.release(), 1.);
    residual_op->add(new ConstantOperator<M, GV>(space, space, new V(std::move(rhs_func.vector()))), -1);
    return residual_op;
  } // ... make_residual_operator(...)

  std::string space_type_;
}; // class StationaryDiffusionIpdgEocStudy

} // namespace Test
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_TEST_STATIONARY_EOCSTUDIES_DIFFUSION_IPDG_HH
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "designerxmleditorwidget.h"
#include "formwindoweditor.h"
#include "designerconstants.h"

#include <QDesignerFormWindowInterface>
#include <QDebug>

namespace Designer {
namespace Internal {

DesignerXmlEditorWidget::DesignerXmlEditorWidget(QDesignerFormWindowInterface *form,
                                                 QWidget *parent) :
    TextEditor::PlainTextEditorWidget(new FormWindowFile(form, this), parent),
    m_designerEditor(new FormWindowEditor(this))
{
    setReadOnly(true);
    configure(baseTextDocument()->mimeType());
}

TextEditor::BaseTextEditor *DesignerXmlEditorWidget::createEditor()
{
    if (Designer::Constants::Internal::debug)
        qDebug() << "DesignerXmlEditor::createEditableInterface()";
    return m_designerEditor;
}

FormWindowEditor *DesignerXmlEditorWidget::designerEditor() const
{
    return m_designerEditor;
}

Internal::FormWindowFile *DesignerXmlEditorWidget::formWindowFile() const
{
    return qobject_cast<FormWindowFile *>(baseTextDocument());
}

} // namespace Internal
} // namespace Designer

<commit_msg>Designer: Fix crash<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "designerxmleditorwidget.h"
#include "formwindoweditor.h"
#include "designerconstants.h"

#include <QDesignerFormWindowInterface>
#include <QDebug>

namespace Designer {
namespace Internal {

DesignerXmlEditorWidget::DesignerXmlEditorWidget(QDesignerFormWindowInterface *form,
                                                 QWidget *parent) :
    TextEditor::PlainTextEditorWidget(new FormWindowFile(form), parent),
    m_designerEditor(new FormWindowEditor(this))
{
    setReadOnly(true);
    configure(baseTextDocument()->mimeType());
}

TextEditor::BaseTextEditor *DesignerXmlEditorWidget::createEditor()
{
    if (Designer::Constants::Internal::debug)
        qDebug() << "DesignerXmlEditor::createEditableInterface()";
    return m_designerEditor;
}

FormWindowEditor *DesignerXmlEditorWidget::designerEditor() const
{
    return m_designerEditor;
}

Internal::FormWindowFile *DesignerXmlEditorWidget::formWindowFile() const
{
    return qobject_cast<FormWindowFile *>(baseTextDocument());
}

} // namespace Internal
} // namespace Designer

<|endoftext|>