<commit_before>#include "log/leveldb_db.h"

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <stdint.h>
#include <map>
#include <string>

#include "monitoring/latency.h"
#include "monitoring/monitoring.h"
#include "proto/ct.pb.h"
#include "proto/serializer.h"
#include "util/util.h"

using cert_trans::serialization::DeserializeResult;
using std::chrono::milliseconds;
using std::lock_guard;
using std::make_pair;
using std::min;
using std::mutex;
using std::string;
using std::unique_lock;
using std::unique_ptr;

DEFINE_int32(leveldb_max_open_files, 0,
             "number of open files that can be used by leveldb");
DEFINE_int32(leveldb_bloom_filter_bits_per_key, 0,
             "number of open files that can be used by leveldb");

namespace cert_trans {
namespace {

static Latency<milliseconds, string> latency_by_op_ms(
    "leveldb_latency_by_operation_ms", "operation",
    "Database latency in ms broken out by operation.");

const char kMetaNodeIdKey[] = "metadata";
const char kEntryPrefix[] = "entry-";
const char kTreeHeadPrefix[] = "sth-";
const char kMetaPrefix[] = "meta-";

#ifdef HAVE_LEVELDB_FILTER_POLICY_H
unique_ptr<const leveldb::FilterPolicy> BuildFilterPolicy() {
  unique_ptr<const leveldb::FilterPolicy> retval;

  if (FLAGS_leveldb_bloom_filter_bits_per_key > 0) {
    retval.reset(CHECK_NOTNULL(leveldb::NewBloomFilterPolicy(
        FLAGS_leveldb_bloom_filter_bits_per_key)));
  }

  return retval;
}
#endif

// WARNING: Do NOT change the type of "index" from int64_t, or you'll
// break existing databases!
string IndexToKey(int64_t index) {
  const char nibble[] = "0123456789abcdef";
  string index_str(sizeof(index) * 2, nibble[0]);
  for (int i = sizeof(index) * 2; i > 0 && index > 0; --i) {
    index_str[i - 1] = nibble[index & 0xf];
    index = index >> 4;
  }

  return kEntryPrefix + index_str;
}

int64_t KeyToIndex(leveldb::Slice key) {
  CHECK(key.starts_with(kEntryPrefix));
  key.remove_prefix(strlen(kEntryPrefix));
  const string index_str(util::BinaryString(key.ToString()));

  int64_t index(0);
  CHECK_EQ(index_str.size(), sizeof(index));
  for (size_t i = 0; i < sizeof(index); ++i) {
    index = (index << 8) | static_cast<unsigned char>(index_str[i]);
  }

  return index;
}

}  // namespace

class LevelDB::Iterator : public Database::Iterator {
 public:
  Iterator(const LevelDB* db, int64_t start_index)
      : it_(CHECK_NOTNULL(db)->db_->NewIterator(leveldb::ReadOptions())) {
    CHECK(it_);
    it_->Seek(IndexToKey(start_index));
  }

  bool GetNextEntry(LoggedEntry* entry) override {
    if (!it_->Valid() || !it_->key().starts_with(kEntryPrefix)) {
      return false;
    }

    const int64_t seq(KeyToIndex(it_->key()));
    CHECK(entry->ParseFromArray(it_->value().data(), it_->value().size()))
        << "failed to parse entry for key " << it_->key().ToString();
    CHECK(entry->has_sequence_number())
        << "no sequence number for entry with expected sequence number "
        << seq;
    CHECK_EQ(entry->sequence_number(), seq) << "unexpected sequence_number";

    it_->Next();

    return true;
  }

 private:
  const unique_ptr<leveldb::Iterator> it_;
};

const size_t LevelDB::kTimestampBytesIndexed = 6;

LevelDB::LevelDB(const string& dbfile)
    :
#ifdef HAVE_LEVELDB_FILTER_POLICY_H
      filter_policy_(BuildFilterPolicy()),
#endif
      contiguous_size_(0),
      latest_tree_timestamp_(0) {
  LOG(INFO) << "Opening " << dbfile;
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("open"));
  leveldb::Options options;
  options.create_if_missing = true;
  if (FLAGS_leveldb_max_open_files > 0) {
    options.max_open_files = FLAGS_leveldb_max_open_files;
  }
#ifdef HAVE_LEVELDB_FILTER_POLICY_H
  options.filter_policy = filter_policy_.get();
#else
  CHECK_EQ(FLAGS_leveldb_bloom_filter_bits_per_key, 0)
      << "this version of leveldb does not have bloom filter support";
#endif
  leveldb::DB* db;
  leveldb::Status status(leveldb::DB::Open(options, dbfile, &db));
  CHECK(status.ok()) << status.ToString();
  db_.reset(db);

  BuildIndex();
}

Database::WriteResult LevelDB::CreateSequencedEntry_(
    const LoggedEntry& logged) {
  CHECK(logged.has_sequence_number());
  CHECK_GE(logged.sequence_number(), 0);
  ScopedLatency latency(
      latency_by_op_ms.GetScopedLatency("create_sequenced_entry"));

  unique_lock<mutex> lock(lock_);

  string data;
  CHECK(logged.SerializeToString(&data));

  const string key(IndexToKey(logged.sequence_number()));

  string existing_data;
  leveldb::Status status(
      db_->Get(leveldb::ReadOptions(), key, &existing_data));
  if (status.IsNotFound()) {
    status = db_->Put(leveldb::WriteOptions(), key, data);
    CHECK(status.ok()) << "Failed to write sequenced entry (seq: "
                       << logged.sequence_number()
                       << "): " << status.ToString();
  } else {
    if (existing_data == data) {
      return this->OK;
    }
    return this->SEQUENCE_NUMBER_ALREADY_IN_USE;
  }

  InsertEntryMapping(logged.sequence_number(), logged.Hash());

  return this->OK;
}

Database::LookupResult LevelDB::LookupByHash(const string& hash,
                                             LoggedEntry* result) const {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("lookup_by_hash"));

  unique_lock<mutex> lock(lock_);

  auto i(id_by_hash_.find(hash));
  if (i == id_by_hash_.end()) {
    return this->NOT_FOUND;
  }

  string cert_data;
  const leveldb::Status status(
      db_->Get(leveldb::ReadOptions(), IndexToKey(i->second), &cert_data));
  if (status.IsNotFound()) {
    return this->NOT_FOUND;
  }
  CHECK(status.ok()) << "Failed to get entry by hash(" << util::HexString(hash)
                     << "): " << status.ToString();

  if (result) {
    CHECK(result->ParseFromString(cert_data));
    CHECK_EQ(result->Hash(), hash);
  }

  return this->LOOKUP_OK;
}

Database::LookupResult LevelDB::LookupByIndex(int64_t sequence_number,
                                              LoggedEntry* result) const {
  CHECK_GE(sequence_number, 0);
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("lookup_by_index"));

  string cert_data;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  IndexToKey(sequence_number), &cert_data));
  if (status.IsNotFound()) {
    return this->NOT_FOUND;
  }
  CHECK(status.ok()) << "Failed to get entry for sequence number "
                     << sequence_number;

  if (result) {
    CHECK(result->ParseFromString(cert_data));
    CHECK_EQ(result->sequence_number(), sequence_number);
  }

  return this->LOOKUP_OK;
}

unique_ptr<Database::Iterator> LevelDB::ScanEntries(
    int64_t start_index) const {
  return unique_ptr<Iterator>(new Iterator(this, start_index));
}

Database::WriteResult LevelDB::WriteTreeHead_(const ct::SignedTreeHead& sth) {
  CHECK_GE(sth.tree_size(), 0);
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("write_tree_head"));

  // 6 bytes are good enough for some 9000 years.
  string timestamp_key =
      Serializer::SerializeUint(sth.timestamp(),
                                LevelDB::kTimestampBytesIndexed);
  string data;
  CHECK(sth.SerializeToString(&data));

  unique_lock<mutex> lock(lock_);
  string existing_data;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  kTreeHeadPrefix + timestamp_key,
                                  &existing_data));
  if (status.ok()) {
    if (existing_data == data) {
      return this->OK;
    }
    return this->DUPLICATE_TREE_HEAD_TIMESTAMP;
  }

  leveldb::WriteOptions opts;
  opts.sync = true;
  status = db_->Put(opts, kTreeHeadPrefix + timestamp_key, data);
  CHECK(status.ok()) << "Failed to write tree head (" << timestamp_key
                     << "): " << status.ToString();

  if (sth.timestamp() > latest_tree_timestamp_) {
    latest_tree_timestamp_ = sth.timestamp();
    latest_timestamp_key_ = timestamp_key;
  }

  lock.unlock();
  callbacks_.Call(sth);

  return this->OK;
}

Database::LookupResult LevelDB::LatestTreeHead(
    ct::SignedTreeHead* result) const {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("latest_tree_head"));
  lock_guard<mutex> lock(lock_);

  return LatestTreeHeadNoLock(result);
}

int64_t LevelDB::TreeSize() const {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("tree_size"));
  lock_guard<mutex> lock(lock_);

  return contiguous_size_;
}

void LevelDB::AddNotifySTHCallback(
    const Database::NotifySTHCallback* callback) {
  unique_lock<mutex> lock(lock_);

  callbacks_.Add(callback);

  ct::SignedTreeHead sth;
  if (LatestTreeHeadNoLock(&sth) == this->LOOKUP_OK) {
    lock.unlock();
    (*callback)(sth);
  }
}

void LevelDB::RemoveNotifySTHCallback(
    const Database::NotifySTHCallback* callback) {
  lock_guard<mutex> lock(lock_);

  callbacks_.Remove(callback);
}

void LevelDB::InitializeNode(const string& node_id) {
  CHECK(!node_id.empty());
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("initialize_node"));
  unique_lock<mutex> lock(lock_);
  string existing_id;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  string(kMetaPrefix) + kMetaNodeIdKey,
                                  &existing_id));
  if (!status.IsNotFound()) {
    LOG(FATAL) << "Attempting to initialize DB beloging to node with node_id: "
               << existing_id;
  }
  status = db_->Put(leveldb::WriteOptions(),
                    string(kMetaPrefix) + kMetaNodeIdKey, node_id);
  CHECK(status.ok()) << "Failed to store NodeId: " << status.ToString();
}

Database::LookupResult LevelDB::NodeId(string* node_id) {
  CHECK_NOTNULL(node_id);
  leveldb::Status status =
      db_->Get(leveldb::ReadOptions(), string(kMetaPrefix) + kMetaNodeIdKey,
               node_id);

  if (status.ok()) {
    return this->LOOKUP_OK;
  }
  if (status.IsNotFound()) {
    return this->NOT_FOUND;
  }
  LOG(FATAL) << "Node ID lookup failed: " << status.ToString();
}

void LevelDB::BuildIndex() {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("build_index"));
  // Technically, this should only be called from the constructor, so
  // this should not be necessarily, but just to be sure...
  lock_guard<mutex> lock(lock_);

  leveldb::ReadOptions options;
  options.fill_cache = false;
  unique_ptr<leveldb::Iterator> it(db_->NewIterator(options));
  CHECK(it);
  it->Seek(kEntryPrefix);

  for (; it->Valid() && it->key().starts_with(kEntryPrefix); it->Next()) {
    const int64_t seq(KeyToIndex(it->key()));
    LoggedEntry logged;
    CHECK(logged.ParseFromString(it->value().ToString()))
        << "Failed to parse entry with sequence number " << seq;
    CHECK(logged.has_sequence_number())
        << "No sequence number for entry with sequence number " << seq;
    CHECK_EQ(logged.sequence_number(), seq)
        << "Entry has unexpected sequence_number: " << seq;

    InsertEntryMapping(logged.sequence_number(), logged.Hash());
  }

  // Now read the STH entries.
  it->Seek(kTreeHeadPrefix);
  for (; it->Valid() && it->key().starts_with(kTreeHeadPrefix); it->Next()) {
    leveldb::Slice key_slice(it->key());
    key_slice.remove_prefix(strlen(kTreeHeadPrefix));
    latest_timestamp_key_ = key_slice.ToString();
    CHECK_EQ(DeserializeResult::OK,
             Deserializer::DeserializeUint<uint64_t>(
                 latest_timestamp_key_, LevelDB::kTimestampBytesIndexed,
                 &latest_tree_timestamp_));
  }
}

Database::LookupResult LevelDB::LatestTreeHeadNoLock(
    ct::SignedTreeHead* result) const {
  if (latest_tree_timestamp_ == 0) {
    return this->NOT_FOUND;
  }

  string tree_data;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  kTreeHeadPrefix + latest_timestamp_key_,
                                  &tree_data));
  CHECK(status.ok()) << "Failed to read latest tree head: "
                     << status.ToString();

  CHECK(result->ParseFromString(tree_data));
  CHECK_EQ(result->timestamp(), latest_tree_timestamp_);

  return this->LOOKUP_OK;
}

// This must be called with "lock_" held.
void LevelDB::InsertEntryMapping(int64_t sequence_number, const string& hash) {
  if (!id_by_hash_.insert(make_pair(hash, sequence_number)).second) {
    // This is a duplicate hash under a new sequence number.
    // Make sure we track the entry with the lowest sequence number:
    id_by_hash_[hash] = min(id_by_hash_[hash], sequence_number);
  }
  if (sequence_number == contiguous_size_) {
    ++contiguous_size_;
    for (auto i = sparse_entries_.find(contiguous_size_);
         i != sparse_entries_.end() && *i == contiguous_size_;) {
      ++contiguous_size_;
      i = sparse_entries_.erase(i);
    }
  } else {
    // It's not contiguous, put it with the other sparse entries.
    CHECK(sparse_entries_.insert(sequence_number).second)
        << "sequence number " << sequence_number << " already assigned.";
  }
}

}  // namespace cert_trans
<commit_msg>Fixes typo in leveldb_db.cc log message<commit_after>#include "log/leveldb_db.h"

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <stdint.h>
#include <map>
#include <string>

#include "monitoring/latency.h"
#include "monitoring/monitoring.h"
#include "proto/ct.pb.h"
#include "proto/serializer.h"
#include "util/util.h"

using cert_trans::serialization::DeserializeResult;
using std::chrono::milliseconds;
using std::lock_guard;
using std::make_pair;
using std::min;
using std::mutex;
using std::string;
using std::unique_lock;
using std::unique_ptr;

DEFINE_int32(leveldb_max_open_files, 0,
             "number of open files that can be used by leveldb");
DEFINE_int32(leveldb_bloom_filter_bits_per_key, 0,
             "number of open files that can be used by leveldb");

namespace cert_trans {
namespace {

static Latency<milliseconds, string> latency_by_op_ms(
    "leveldb_latency_by_operation_ms", "operation",
    "Database latency in ms broken out by operation.");

const char kMetaNodeIdKey[] = "metadata";
const char kEntryPrefix[] = "entry-";
const char kTreeHeadPrefix[] = "sth-";
const char kMetaPrefix[] = "meta-";

#ifdef HAVE_LEVELDB_FILTER_POLICY_H
unique_ptr<const leveldb::FilterPolicy> BuildFilterPolicy() {
  unique_ptr<const leveldb::FilterPolicy> retval;

  if (FLAGS_leveldb_bloom_filter_bits_per_key > 0) {
    retval.reset(CHECK_NOTNULL(leveldb::NewBloomFilterPolicy(
        FLAGS_leveldb_bloom_filter_bits_per_key)));
  }

  return retval;
}
#endif

// WARNING: Do NOT change the type of "index" from int64_t, or you'll
// break existing databases!
string IndexToKey(int64_t index) {
  const char nibble[] = "0123456789abcdef";
  string index_str(sizeof(index) * 2, nibble[0]);
  for (int i = sizeof(index) * 2; i > 0 && index > 0; --i) {
    index_str[i - 1] = nibble[index & 0xf];
    index = index >> 4;
  }

  return kEntryPrefix + index_str;
}

int64_t KeyToIndex(leveldb::Slice key) {
  CHECK(key.starts_with(kEntryPrefix));
  key.remove_prefix(strlen(kEntryPrefix));
  const string index_str(util::BinaryString(key.ToString()));

  int64_t index(0);
  CHECK_EQ(index_str.size(), sizeof(index));
  for (size_t i = 0; i < sizeof(index); ++i) {
    index = (index << 8) | static_cast<unsigned char>(index_str[i]);
  }

  return index;
}

}  // namespace

class LevelDB::Iterator : public Database::Iterator {
 public:
  Iterator(const LevelDB* db, int64_t start_index)
      : it_(CHECK_NOTNULL(db)->db_->NewIterator(leveldb::ReadOptions())) {
    CHECK(it_);
    it_->Seek(IndexToKey(start_index));
  }

  bool GetNextEntry(LoggedEntry* entry) override {
    if (!it_->Valid() || !it_->key().starts_with(kEntryPrefix)) {
      return false;
    }

    const int64_t seq(KeyToIndex(it_->key()));
    CHECK(entry->ParseFromArray(it_->value().data(), it_->value().size()))
        << "failed to parse entry for key " << it_->key().ToString();
    CHECK(entry->has_sequence_number())
        << "no sequence number for entry with expected sequence number "
        << seq;
    CHECK_EQ(entry->sequence_number(), seq) << "unexpected sequence_number";

    it_->Next();

    return true;
  }

 private:
  const unique_ptr<leveldb::Iterator> it_;
};

const size_t LevelDB::kTimestampBytesIndexed = 6;

LevelDB::LevelDB(const string& dbfile)
    :
#ifdef HAVE_LEVELDB_FILTER_POLICY_H
      filter_policy_(BuildFilterPolicy()),
#endif
      contiguous_size_(0),
      latest_tree_timestamp_(0) {
  LOG(INFO) << "Opening " << dbfile;
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("open"));
  leveldb::Options options;
  options.create_if_missing = true;
  if (FLAGS_leveldb_max_open_files > 0) {
    options.max_open_files = FLAGS_leveldb_max_open_files;
  }
#ifdef HAVE_LEVELDB_FILTER_POLICY_H
  options.filter_policy = filter_policy_.get();
#else
  CHECK_EQ(FLAGS_leveldb_bloom_filter_bits_per_key, 0)
      << "this version of leveldb does not have bloom filter support";
#endif
  leveldb::DB* db;
  leveldb::Status status(leveldb::DB::Open(options, dbfile, &db));
  CHECK(status.ok()) << status.ToString();
  db_.reset(db);

  BuildIndex();
}

Database::WriteResult LevelDB::CreateSequencedEntry_(
    const LoggedEntry& logged) {
  CHECK(logged.has_sequence_number());
  CHECK_GE(logged.sequence_number(), 0);
  ScopedLatency latency(
      latency_by_op_ms.GetScopedLatency("create_sequenced_entry"));

  unique_lock<mutex> lock(lock_);

  string data;
  CHECK(logged.SerializeToString(&data));

  const string key(IndexToKey(logged.sequence_number()));

  string existing_data;
  leveldb::Status status(
      db_->Get(leveldb::ReadOptions(), key, &existing_data));
  if (status.IsNotFound()) {
    status = db_->Put(leveldb::WriteOptions(), key, data);
    CHECK(status.ok()) << "Failed to write sequenced entry (seq: "
                       << logged.sequence_number()
                       << "): " << status.ToString();
  } else {
    if (existing_data == data) {
      return this->OK;
    }
    return this->SEQUENCE_NUMBER_ALREADY_IN_USE;
  }

  InsertEntryMapping(logged.sequence_number(), logged.Hash());

  return this->OK;
}

Database::LookupResult LevelDB::LookupByHash(const string& hash,
                                             LoggedEntry* result) const {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("lookup_by_hash"));

  unique_lock<mutex> lock(lock_);

  auto i(id_by_hash_.find(hash));
  if (i == id_by_hash_.end()) {
    return this->NOT_FOUND;
  }

  string cert_data;
  const leveldb::Status status(
      db_->Get(leveldb::ReadOptions(), IndexToKey(i->second), &cert_data));
  if (status.IsNotFound()) {
    return this->NOT_FOUND;
  }
  CHECK(status.ok()) << "Failed to get entry by hash(" << util::HexString(hash)
                     << "): " << status.ToString();

  if (result) {
    CHECK(result->ParseFromString(cert_data));
    CHECK_EQ(result->Hash(), hash);
  }

  return this->LOOKUP_OK;
}

Database::LookupResult LevelDB::LookupByIndex(int64_t sequence_number,
                                              LoggedEntry* result) const {
  CHECK_GE(sequence_number, 0);
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("lookup_by_index"));

  string cert_data;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  IndexToKey(sequence_number), &cert_data));
  if (status.IsNotFound()) {
    return this->NOT_FOUND;
  }
  CHECK(status.ok()) << "Failed to get entry for sequence number "
                     << sequence_number;

  if (result) {
    CHECK(result->ParseFromString(cert_data));
    CHECK_EQ(result->sequence_number(), sequence_number);
  }

  return this->LOOKUP_OK;
}

unique_ptr<Database::Iterator> LevelDB::ScanEntries(
    int64_t start_index) const {
  return unique_ptr<Iterator>(new Iterator(this, start_index));
}

Database::WriteResult LevelDB::WriteTreeHead_(const ct::SignedTreeHead& sth) {
  CHECK_GE(sth.tree_size(), 0);
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("write_tree_head"));

  // 6 bytes are good enough for some 9000 years.
  string timestamp_key =
      Serializer::SerializeUint(sth.timestamp(),
                                LevelDB::kTimestampBytesIndexed);
  string data;
  CHECK(sth.SerializeToString(&data));

  unique_lock<mutex> lock(lock_);
  string existing_data;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  kTreeHeadPrefix + timestamp_key,
                                  &existing_data));
  if (status.ok()) {
    if (existing_data == data) {
      return this->OK;
    }
    return this->DUPLICATE_TREE_HEAD_TIMESTAMP;
  }

  leveldb::WriteOptions opts;
  opts.sync = true;
  status = db_->Put(opts, kTreeHeadPrefix + timestamp_key, data);
  CHECK(status.ok()) << "Failed to write tree head (" << timestamp_key
                     << "): " << status.ToString();

  if (sth.timestamp() > latest_tree_timestamp_) {
    latest_tree_timestamp_ = sth.timestamp();
    latest_timestamp_key_ = timestamp_key;
  }

  lock.unlock();
  callbacks_.Call(sth);

  return this->OK;
}

Database::LookupResult LevelDB::LatestTreeHead(
    ct::SignedTreeHead* result) const {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("latest_tree_head"));
  lock_guard<mutex> lock(lock_);

  return LatestTreeHeadNoLock(result);
}

int64_t LevelDB::TreeSize() const {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("tree_size"));
  lock_guard<mutex> lock(lock_);

  return contiguous_size_;
}

void LevelDB::AddNotifySTHCallback(
    const Database::NotifySTHCallback* callback) {
  unique_lock<mutex> lock(lock_);

  callbacks_.Add(callback);

  ct::SignedTreeHead sth;
  if (LatestTreeHeadNoLock(&sth) == this->LOOKUP_OK) {
    lock.unlock();
    (*callback)(sth);
  }
}

void LevelDB::RemoveNotifySTHCallback(
    const Database::NotifySTHCallback* callback) {
  lock_guard<mutex> lock(lock_);

  callbacks_.Remove(callback);
}

void LevelDB::InitializeNode(const string& node_id) {
  CHECK(!node_id.empty());
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("initialize_node"));
  unique_lock<mutex> lock(lock_);
  string existing_id;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  string(kMetaPrefix) + kMetaNodeIdKey,
                                  &existing_id));
  if (!status.IsNotFound()) {
    LOG(FATAL) << "Attempting to initialize DB belonging to node with node_id: "
               << existing_id;
  }
  status = db_->Put(leveldb::WriteOptions(),
                    string(kMetaPrefix) + kMetaNodeIdKey, node_id);
  CHECK(status.ok()) << "Failed to store NodeId: " << status.ToString();
}

Database::LookupResult LevelDB::NodeId(string* node_id) {
  CHECK_NOTNULL(node_id);
  leveldb::Status status =
      db_->Get(leveldb::ReadOptions(), string(kMetaPrefix) + kMetaNodeIdKey,
               node_id);

  if (status.ok()) {
    return this->LOOKUP_OK;
  }
  if (status.IsNotFound()) {
    return this->NOT_FOUND;
  }
  LOG(FATAL) << "Node ID lookup failed: " << status.ToString();
}

void LevelDB::BuildIndex() {
  ScopedLatency latency(latency_by_op_ms.GetScopedLatency("build_index"));
  // Technically, this should only be called from the constructor, so
  // this should not be necessarily, but just to be sure...
  lock_guard<mutex> lock(lock_);

  leveldb::ReadOptions options;
  options.fill_cache = false;
  unique_ptr<leveldb::Iterator> it(db_->NewIterator(options));
  CHECK(it);
  it->Seek(kEntryPrefix);

  for (; it->Valid() && it->key().starts_with(kEntryPrefix); it->Next()) {
    const int64_t seq(KeyToIndex(it->key()));
    LoggedEntry logged;
    CHECK(logged.ParseFromString(it->value().ToString()))
        << "Failed to parse entry with sequence number " << seq;
    CHECK(logged.has_sequence_number())
        << "No sequence number for entry with sequence number " << seq;
    CHECK_EQ(logged.sequence_number(), seq)
        << "Entry has unexpected sequence_number: " << seq;

    InsertEntryMapping(logged.sequence_number(), logged.Hash());
  }

  // Now read the STH entries.
  it->Seek(kTreeHeadPrefix);
  for (; it->Valid() && it->key().starts_with(kTreeHeadPrefix); it->Next()) {
    leveldb::Slice key_slice(it->key());
    key_slice.remove_prefix(strlen(kTreeHeadPrefix));
    latest_timestamp_key_ = key_slice.ToString();
    CHECK_EQ(DeserializeResult::OK,
             Deserializer::DeserializeUint<uint64_t>(
                 latest_timestamp_key_, LevelDB::kTimestampBytesIndexed,
                 &latest_tree_timestamp_));
  }
}

Database::LookupResult LevelDB::LatestTreeHeadNoLock(
    ct::SignedTreeHead* result) const {
  if (latest_tree_timestamp_ == 0) {
    return this->NOT_FOUND;
  }

  string tree_data;
  leveldb::Status status(db_->Get(leveldb::ReadOptions(),
                                  kTreeHeadPrefix + latest_timestamp_key_,
                                  &tree_data));
  CHECK(status.ok()) << "Failed to read latest tree head: "
                     << status.ToString();

  CHECK(result->ParseFromString(tree_data));
  CHECK_EQ(result->timestamp(), latest_tree_timestamp_);

  return this->LOOKUP_OK;
}

// This must be called with "lock_" held.
void LevelDB::InsertEntryMapping(int64_t sequence_number, const string& hash) {
  if (!id_by_hash_.insert(make_pair(hash, sequence_number)).second) {
    // This is a duplicate hash under a new sequence number.
    // Make sure we track the entry with the lowest sequence number:
    id_by_hash_[hash] = min(id_by_hash_[hash], sequence_number);
  }
  if (sequence_number == contiguous_size_) {
    ++contiguous_size_;
    for (auto i = sparse_entries_.find(contiguous_size_);
         i != sparse_entries_.end() && *i == contiguous_size_;) {
      ++contiguous_size_;
      i = sparse_entries_.erase(i);
    }
  } else {
    // It's not contiguous, put it with the other sparse entries.
    CHECK(sparse_entries_.insert(sequence_number).second)
        << "sequence number " << sequence_number << " already assigned.";
  }
}

}  // namespace cert_trans
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/notifications/desktop_notification_service.h"

#include "base/task.h"
#include "base/waitable_event.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/test/testing_profile.h"
#include "grit/generated_resources.h"
#include "testing/gtest/include/gtest/gtest.h"

class DesktopNotificationServiceTest : public RenderViewHostTestHarness {
 public:
  DesktopNotificationServiceTest()
      : event_(false, false),
        ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  }

  void LetIOThreadWait() {
    event_.Wait();
  }

  base::WaitableEvent event_;
  ScopedRunnableMethodFactory<DesktopNotificationServiceTest> method_factory_;
};

TEST_F(DesktopNotificationServiceTest, DefaultContentSettingSentToCache) {
  // The current message loop was already initalized by the superclass.
  ChromeThread ui_thread(ChromeThread::UI, MessageLoop::current());

  // Create IO thread, start its message loop.
  ChromeThread io_thread(ChromeThread::IO);
  io_thread.Start();
  ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
      method_factory_.NewRunnableMethod(
          &DesktopNotificationServiceTest::LetIOThreadWait));

  // Creates the service, calls InitPrefs() on it which loads data from the
  // profile into the cache and then puts the cache in io thread mode.
  DesktopNotificationService* service =
      profile()->GetDesktopNotificationService();
  NotificationsPrefsCache* cache = service->prefs_cache();

  // The default pref registered in DesktopNotificationService is "ask",
  // and that's what sent to the cache.
  EXPECT_EQ(CONTENT_SETTING_ASK, cache->CachedDefaultContentSetting());

  // Change the default content setting. This will post a task on the IO thread
  // to update the cache.
  service->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);

  // The updated pref shouldn't be sent to the cache immediately.
  EXPECT_EQ(CONTENT_SETTING_ASK, cache->CachedDefaultContentSetting());

  // Run IO thread tasks.
  event_.Signal();
  io_thread.Stop();

  // Now that IO thread events have been processed, it should be there.
  EXPECT_EQ(CONTENT_SETTING_BLOCK, cache->CachedDefaultContentSetting());
}

<commit_msg>Attempted build fix: Run IO blocking task actually on IO thread.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/notifications/desktop_notification_service.h"

#include "base/task.h"
#include "base/waitable_event.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/test/testing_profile.h"
#include "grit/generated_resources.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class WaitTask : public Task {
 public:
  WaitTask(base::WaitableEvent* event)
      : event_(event) {
  }
  virtual void Run() {
    event_->Wait();
  }

 private:
  base::WaitableEvent* event_;
};

class DesktopNotificationServiceTest : public RenderViewHostTestHarness {
 public:
  DesktopNotificationServiceTest()
      : event_(false, false) {
  }
  base::WaitableEvent event_;
};

TEST_F(DesktopNotificationServiceTest, DefaultContentSettingSentToCache) {
  // The current message loop was already initalized by the superclass.
  ChromeThread ui_thread(ChromeThread::UI, MessageLoop::current());

  // Create IO thread, start its message loop.
  ChromeThread io_thread(ChromeThread::IO);
  io_thread.Start();
  ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, new WaitTask(&event_));

  // Creates the service, calls InitPrefs() on it which loads data from the
  // profile into the cache and then puts the cache in io thread mode.
  DesktopNotificationService* service =
      profile()->GetDesktopNotificationService();
  NotificationsPrefsCache* cache = service->prefs_cache();

  // The default pref registered in DesktopNotificationService is "ask",
  // and that's what sent to the cache.
  EXPECT_EQ(CONTENT_SETTING_ASK, cache->CachedDefaultContentSetting());

  // Change the default content setting. This will post a task on the IO thread
  // to update the cache.
  service->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);

  // The updated pref shouldn't be sent to the cache immediately.
  EXPECT_EQ(CONTENT_SETTING_ASK, cache->CachedDefaultContentSetting());

  // Run IO thread tasks.
  event_.Signal();
  io_thread.Stop();

  // Now that IO thread events have been processed, it should be there.
  EXPECT_EQ(CONTENT_SETTING_BLOCK, cache->CachedDefaultContentSetting());
}

}  // namespace
<|endoftext|>


<commit_before>#include "musicmydownloadrecordobject.h"

MusicMyDownloadRecordObject::MusicMyDownloadRecordObject(QObject *parent) :
    MusicAbstractXml(parent)
{

}

void MusicMyDownloadRecordObject::writeDownloadConfig(const MusicDownloadRecord &record)
{
    if( !writeConfig( MusicObject::getAppDir() + DOWNLOADINFO ) )
    {
        return;
    }
    ///////////////////////////////////////////////////////
    createProcessingInstruction();
    QDomElement musicPlayer = createRoot("QMusicPlayer");
    QDomElement download = writeDom(musicPlayer, "download");

    for(int i=0; i<record.m_names.count(); ++i)
    {
        writeDomElementMutilText(download, "value", QStringList()<<"name"<<"size",
                                 QList<QVariant>()<<record.m_names[i]<<record.m_sizes[i],
                                 record.m_paths[i]);
    }
    //Write to file
    QTextStream out(m_file);
    m_ddom->save(out,4);
}

void MusicMyDownloadRecordObject::readDownloadConfig(MusicDownloadRecord &record)
{
    QDomNodeList nodelist = m_ddom->elementsByTagName("value");
    QStringList names;
    QStringList paths;
    QStringList size;
    for(int i=0; i<nodelist.count(); ++i)
    {
        names << nodelist.at(i).toElement().attribute("name");
        paths << nodelist.at(i).toElement().text();
        size << nodelist.at(i).toElement().attribute("size");
    }
    record.m_names = names;
    record.m_paths = paths;
    record.m_sizes = size;
}
<commit_msg>clean code for mydwonload[452154]<commit_after>#include "musicmydownloadrecordobject.h"

MusicMyDownloadRecordObject::MusicMyDownloadRecordObject(QObject *parent)
    : MusicAbstractXml(parent)
{

}

void MusicMyDownloadRecordObject::writeDownloadConfig(const MusicDownloadRecord &record)
{
    if( !writeConfig( MusicObject::getAppDir() + DOWNLOADINFO ) )
    {
        return;
    }
    ///////////////////////////////////////////////////////
    createProcessingInstruction();
    QDomElement musicPlayer = createRoot("QMusicPlayer");
    QDomElement download = writeDom(musicPlayer, "download");

    for(int i=0; i<record.m_names.count(); ++i)
    {
        writeDomElementMutilText(download, "value", QStringList()<<"name"<<"size",
                                 QList<QVariant>()<<record.m_names[i]<<record.m_sizes[i],
                                 record.m_paths[i]);
    }
    //Write to file
    QTextStream out(m_file);
    m_ddom->save(out, 4);
}

void MusicMyDownloadRecordObject::readDownloadConfig(MusicDownloadRecord &record)
{
    QDomNodeList nodelist = m_ddom->elementsByTagName("value");
    QStringList names, paths, size;
    for(int i=0; i<nodelist.count(); ++i)
    {
        names << nodelist.at(i).toElement().attribute("name");
        paths << nodelist.at(i).toElement().text();
        size << nodelist.at(i).toElement().attribute("size");
    }
    record.m_names = names;
    record.m_paths = paths;
    record.m_sizes = size;
}
<|endoftext|>


<commit_before>#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

#include "input-driver-test.h"

int InputDriverTest::RegisterXI2(int major, int minor)
{
    int event_start;
    int error_start;

    if (!XQueryExtension(Display(), "XInputExtension", &xi2_opcode,
                         &event_start, &error_start))
        ADD_FAILURE() << "XQueryExtension returned FALSE";

    int major_return = major;
    int minor_return = minor;
    if (XIQueryVersion(Display(), &major_return, &minor_return) != Success)
        ADD_FAILURE() << "XIQueryVersion failed";
    if (major_return != major)
       ADD_FAILURE() << "XIQueryVersion returned invalid major";

    return minor_return;
}

void InputDriverTest::StartServer() {
    server.SetOption("-noreset", "");
    server.Start();
    xorg::testing::Test::SetDisplayString(server.GetDisplayString());

    ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());

    RegisterXI2();
}

void InputDriverTest::SetUpConfigAndLog(const std::string& param) {
    std::stringstream s;
    s << "/tmp/Xorg-" << param << ".log";
    server.SetOption("-logfile", s.str());

    s.str(std::string());
    s << "/tmp/" << param << ".conf";
    config.SetPath(s.str());

    config.AddDefaultScreenWithDriver();
    config.AddInputSection(param, "--device--", "Option \"CorePointer\" \"on\"\n");
    config.WriteConfig();
    server.SetOption("-config", config.GetPath());
}

void InputDriverTest::SetUpEventListener() {
    failed = false;

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Append(this);
}

void InputDriverTest::SetUp() {
    SetUp("");
}

void InputDriverTest::SetUp(const std::string &param) {
    SetUpEventListener();
    SetUpConfigAndLog(param);
    StartServer();
}

void InputDriverTest::TearDown() {
    if (server.Pid() != -1) {
        if (!server.Terminate(3000))
            server.Kill(3000);
        EXPECT_EQ(server.GetState(), xorg::testing::Process::FINISHED_SUCCESS) << "Unclean server shutdown";
    }

    if (!Failed()) {
        config.RemoveConfig();
        server.RemoveLogFile();
    }

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Release(this);
}

void InputDriverTest::OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
    failed = test_part_result.failed();
}

bool InputDriverTest::Failed() {
    return failed;
}
<commit_msg>common/input-driver-test: warn if we find a BUG warning in the log<commit_after>#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

#include "input-driver-test.h"

int InputDriverTest::RegisterXI2(int major, int minor)
{
    int event_start;
    int error_start;

    if (!XQueryExtension(Display(), "XInputExtension", &xi2_opcode,
                         &event_start, &error_start))
        ADD_FAILURE() << "XQueryExtension returned FALSE";

    int major_return = major;
    int minor_return = minor;
    if (XIQueryVersion(Display(), &major_return, &minor_return) != Success)
        ADD_FAILURE() << "XIQueryVersion failed";
    if (major_return != major)
       ADD_FAILURE() << "XIQueryVersion returned invalid major";

    return minor_return;
}

void InputDriverTest::StartServer() {
    server.SetOption("-noreset", "");
    server.Start();
    xorg::testing::Test::SetDisplayString(server.GetDisplayString());

    ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());

    RegisterXI2();
}

void InputDriverTest::SetUpConfigAndLog(const std::string& param) {
    std::stringstream s;
    s << "/tmp/Xorg-" << param << ".log";
    server.SetOption("-logfile", s.str());

    s.str(std::string());
    s << "/tmp/" << param << ".conf";
    config.SetPath(s.str());

    config.AddDefaultScreenWithDriver();
    config.AddInputSection(param, "--device--", "Option \"CorePointer\" \"on\"\n");
    config.WriteConfig();
    server.SetOption("-config", config.GetPath());
}

void InputDriverTest::SetUpEventListener() {
    failed = false;

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Append(this);
}

void InputDriverTest::SetUp() {
    SetUp("");
}

void InputDriverTest::SetUp(const std::string &param) {
    SetUpEventListener();
    SetUpConfigAndLog(param);
    StartServer();
}

void InputDriverTest::TearDown() {
    if (server.Pid() != -1) {
        if (!server.Terminate(3000))
            server.Kill(3000);
        EXPECT_EQ(server.GetState(), xorg::testing::Process::FINISHED_SUCCESS) << "Unclean server shutdown";

        std::ifstream logfile(server.GetLogFilePath().c_str());
        std::string line;
        std::string bug_warn("BUG");
        if (logfile.is_open()) {
            while(getline(logfile, line)) {
                size_t found = line.find(bug_warn);
                bool error = (found != std::string::npos);
                EXPECT_FALSE(error) << "BUG warning found in log" << std::endl << line << std::endl;
            }
        }
    }

    if (!Failed()) {
        config.RemoveConfig();
        server.RemoveLogFile();
    }

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Release(this);
}

void InputDriverTest::OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
    failed = test_part_result.failed();
}

bool InputDriverTest::Failed() {
    return failed;
}
<|endoftext|>


<commit_before>// @(#)root/tree:$Name:  $:$Id: TFriendElement.cxx,v 1.1 2001/04/09 07:52:33 brun Exp $
// Author: Rene Brun   11/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFriendElement                                                       //
//                                                                      //
// A TFriendElement TF describes a TTree object TF in a file.           //
// When a TFriendElement TF is added to the the list of friends of an   //
// existing TTree T, any variable from TF can be referenced in a query  //
// to T.                                                                //
//                                                                      //
// To add a TFriendElement to an existing TTree T, do:                  //
//       T.AddFriend("friendTreename","friendTreeFilke");               //
//                                                                      //
//  see TTree::AddFriend for more information                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTree.h"
#include "TFriendElement.h"
#include "TFile.h"

ClassImp(TFriendElement)

//______________________________________________________________________________
TFriendElement::TFriendElement(): TNamed()
{
//*-*-*-*-*-*Default constructor for a friend element*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        =======================================

   fFile       = 0;
   fTree       = 0;
   fParentTree = 0;
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, const char *filename)
    :TNamed(treename,filename)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// if treename is of the form "a=b", an alias called "a" is created for treename = "b"
// by default the alias name is the name of the tree.

   fFile       = 0;
   fTree       = 0;
   fParentTree = tree;
   fTreeName   = treename;
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::~TFriendElement()
{

   DisConnect();
}

//_______________________________________________________________________
TTree *TFriendElement::Connect()
{
// Connect file and Tree

   GetFile();
   return GetTree();
}

//_______________________________________________________________________
TTree *TFriendElement::DisConnect()
{
// DisConnect file and Tree

   if (fTree) delete fTree;
   TDirectory *dir = fParentTree->GetDirectory();
   if (dir && fFile != dir->GetFile()) delete fFile;
   fFile = 0;
   fTree = 0;
   return 0;
}

//_______________________________________________________________________
TFile *TFriendElement::GetFile()
{
// return pointer to TFile containing this friend Tree

   if (fFile) return fFile;
   if (strlen(GetTitle())) fFile = new TFile(GetTitle());
   else {
      TDirectory *dir = fParentTree->GetDirectory();
      if (dir) fFile = dir->GetFile();
   }
   if (fFile && fFile->IsZombie()) {
      delete fFile;
      fFile = 0;
   }
   return fFile;
}

//_______________________________________________________________________
TTree *TFriendElement::GetTree()
{
// return pointer to friend Tree

   if (fTree) return fTree;
   if (!GetFile()) return 0;
   fTree = (TTree*)fFile->Get(GetTreeName());
   TDirectory *dir = fParentTree->GetDirectory();
   if (dir && dir != gDirectory) dir->cd();
   return fTree;
}

//_______________________________________________________________________
void TFriendElement::ls(Option_t *option) const
{
// List this friend element
//

   printf(" friend Tree: %s in file: %s\n",GetName(),GetTitle());
}
<commit_msg>Initialize fParentTree to the current Tree in the default constructor. This is necessary when reading a Tree with a list of friends.<commit_after>// @(#)root/tree:$Name:  $:$Id: TFriendElement.cxx,v 1.2 2001/04/10 16:34:51 brun Exp $
// Author: Rene Brun   11/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFriendElement                                                       //
//                                                                      //
// A TFriendElement TF describes a TTree object TF in a file.           //
// When a TFriendElement TF is added to the the list of friends of an   //
// existing TTree T, any variable from TF can be referenced in a query  //
// to T.                                                                //
//                                                                      //
// To add a TFriendElement to an existing TTree T, do:                  //
//       T.AddFriend("friendTreename","friendTreeFilke");               //
//                                                                      //
//  see TTree::AddFriend for more information                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTree.h"
#include "TFriendElement.h"
#include "TFile.h"

R__EXTERN TTree *gTree;

ClassImp(TFriendElement)

//______________________________________________________________________________
TFriendElement::TFriendElement(): TNamed()
{
//*-*-*-*-*-*Default constructor for a friend element*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        =======================================

   fFile       = 0;
   fTree       = 0;
   fParentTree = gTree;
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, const char *filename)
    :TNamed(treename,filename)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// if treename is of the form "a=b", an alias called "a" is created for treename = "b"
// by default the alias name is the name of the tree.

   fFile       = 0;
   fTree       = 0;
   fParentTree = tree;
   fTreeName   = treename;
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::~TFriendElement()
{

   DisConnect();
}

//_______________________________________________________________________
TTree *TFriendElement::Connect()
{
// Connect file and Tree

   GetFile();
   return GetTree();
}

//_______________________________________________________________________
TTree *TFriendElement::DisConnect()
{
// DisConnect file and Tree

   if (fTree) delete fTree;
   TDirectory *dir = fParentTree->GetDirectory();
   if (dir && fFile != dir->GetFile()) delete fFile;
   fFile = 0;
   fTree = 0;
   return 0;
}

//_______________________________________________________________________
TFile *TFriendElement::GetFile()
{
// return pointer to TFile containing this friend Tree

   if (fFile) return fFile;
   if (strlen(GetTitle())) fFile = new TFile(GetTitle());
   else {
      TDirectory *dir = fParentTree->GetDirectory();
      if (dir) fFile = dir->GetFile();
   }
   if (fFile && fFile->IsZombie()) {
      delete fFile;
      fFile = 0;
   }
   return fFile;
}

//_______________________________________________________________________
TTree *TFriendElement::GetTree()
{
// return pointer to friend Tree

   if (fTree) return fTree;
   if (!GetFile()) return 0;
   fTree = (TTree*)fFile->Get(GetTreeName());
   TDirectory *dir = fParentTree->GetDirectory();
   if (dir && dir != gDirectory) dir->cd();
   return fTree;
}

//_______________________________________________________________________
void TFriendElement::ls(Option_t *option) const
{
// List this friend element
//

   printf(" friend Tree: %s in file: %s\n",GetName(),GetTitle());
}
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 *
 * This module forks a watchdog process that listens on
 * a pipe and prints a stackstrace into syslog, when cvmfs
 * fails.
 *
 * Also, it handles getting and setting the maximum number of file descriptors.
 */

#include "cvmfs_config.h"
#include "monitor.h"

#include <signal.h>
#include <sys/resource.h>
#include <execinfo.h>
#ifdef __APPLE__
  #include <sys/ucontext.h>
#else
  #include <ucontext.h>
#endif
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <pthread.h>
#include <time.h>

#include <string>

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cassert>

#include "platform.h"
#include "util.h"
#include "logging.h"
#include "smalloc.h"

using namespace std;  // NOLINT

namespace monitor {

const unsigned kMinOpenFiles = 8192;  /**< minmum threshold for the maximum
                                       number of open files */
const unsigned kMaxBacktrace = 64;  /**< reported stracktrace depth */
const unsigned kSignalHandlerStacksize = 2*1024*1024;  /**< 2 MB */

string *cache_dir_ = NULL;
string *process_name_ = NULL;
bool spawned_ = false;
unsigned max_open_files_;
int pipe_wd_[2];
platform_spinlock lock_handler_;
stack_t sighandler_stack_;

/**
 * Signal handler for signals that indicate a cvmfs crash.
 * Sends debug information to watchdog.
 */
static void SendTrace(int signal,
                      siginfo_t *siginfo __attribute__((unused)),
                      void *context)
{
  int send_errno = errno;
  if (platform_spinlock_trylock(&lock_handler_) != 0) {
    // Concurrent call, wait for the first one to exit the process
    while (true) {}
  }

  char cflow = 'S';
  if (write(pipe_wd_[1], &cflow, 1) != 1)
    _exit(1);

  // write the occured signal
  if (write(pipe_wd_[1], &signal, sizeof(signal)) != sizeof(signal))
    _exit(1);

  // write the last error number
  if (write(pipe_wd_[1], &send_errno, sizeof(send_errno)) != sizeof(send_errno))
    _exit(1);

  // write the PID
  pid_t pid = getpid();
  if (write(pipe_wd_[1], &pid, sizeof(pid_t)) != sizeof(pid_t))
    _exit(1);

  // write the exe path
  const char   *exe_path        = platform_getexepath();
  const size_t  exe_path_length = strlen(exe_path) + 1; // null termination
  if (write(pipe_wd_[1], &exe_path_length, sizeof(size_t)) != sizeof(size_t))
    _exit(1);
  if (write(pipe_wd_[1], exe_path, exe_path_length) != (int)exe_path_length)
    _exit(1);

  cflow = 'Q';
  (void)write(pipe_wd_[1], &cflow, 1);

  // do not die before the stack trace was generated
  // kill -9 <pid> will finish this
  while(true) {}

  _exit(1);
}

/**
 * Log a string to syslog and into $cachedir/stacktrace.
 * We expect ideally nothing to be logged, so that file is created on demand.
 */
static void LogEmergency(string msg) {
  char ctime_buffer[32];

  FILE *fp = fopen((*cache_dir_ + "/stacktrace." + *process_name_).c_str(),
                   "a");
  if (fp) {
    time_t now = time(NULL);
    msg += "\nTimestamp: " + string(ctime_r(&now, ctime_buffer));
    if (fwrite(&msg[0], 1, msg.length(), fp) != msg.length())
      msg += " (failed to report into log file in cache directory)";
    fclose(fp);
  } else {
    msg += " (failed to open log file in cache directory)";
  }
  LogCvmfs(kLogMonitor, kLogSyslog, "%s", msg.c_str());
}

/**
 * Uses an external shell and gdb to create a full stack trace of the dying
 * cvmfs client. The same shell is used to force-quit the client afterwards.
 */
static string GenerateStackTraceAndKill(const string &exe_path, const pid_t pid) {
  int retval;

  int fd_stdin;
  int fd_stdout;
  int fd_stderr;
  retval = Shell(&fd_stdin, &fd_stdout, &fd_stderr);
  assert(retval);

  // Let the shell execute the stacktrace extraction script
  const string bt_cmd = "/etc/cvmfs/gdb-stacktrace.sh " + exe_path + " " +
                     StringifyInt(pid) + "\n";
  WritePipe(fd_stdin, bt_cmd.data(), bt_cmd.length());

  // give the dying cvmfs client the finishing stroke
  string result = "";
  if (kill(pid, SIGKILL) != 0) {
    result += "Failed to kill cvmfs client!\n\n";
  }

  // close the standard in to close the shell
  close(fd_stdin);

  // read the stack trace from the stdout of our shell
  const int bytes_at_a_time = 2;
  char *read_buffer = NULL;
  int buffer_size = 0;
  int buffer_offset = 0;
  int chars_io;
  while (1) {
    if (buffer_offset + bytes_at_a_time > buffer_size) {
      buffer_size = bytes_at_a_time + buffer_size * 2;
      read_buffer = (char*)realloc(read_buffer, buffer_size);
      assert (read_buffer);
    }

    chars_io = read(fd_stdout,
                    read_buffer + buffer_offset,
                    bytes_at_a_time);
    if (chars_io <= 0) break;
    buffer_offset += chars_io;
  }

  // close the pipes to the shell
  close(fd_stderr);
  close(fd_stdout);

  // good bye...
  if (chars_io < 0) {
    result += "failed to read stack traces";
    return result;
  } else {
    return result + read_buffer;
  }
}

/**
 * Generates useful information from the backtrace log in the pipe.
 */
static string ReportStacktrace() {
  string debug = "--\n";

  int recv_signal;
  if (read(pipe_wd_[0], &recv_signal, sizeof(recv_signal)) <
      int(sizeof(recv_signal)))
  {
    return "failure while reading signal number";
  }
  debug += "Signal: " + StringifyInt(recv_signal);

  int recv_errno;
  if (read(pipe_wd_[0], &recv_errno, sizeof(recv_errno)) <
      int(sizeof(recv_errno)))
  {
    return "failure while reading errno";
  }
  debug += ", errno: " + StringifyInt(errno);

  debug += ", version: " + string(VERSION);

  pid_t pid;
  if (read(pipe_wd_[0], &pid, sizeof(pid_t)) < int(sizeof(pid_t))) {
    return "failure while reading PID";
  }
  debug += ", PID: " + StringifyInt(pid) + "\n";

  size_t exe_path_length;
  if (read(pipe_wd_[0], &exe_path_length, sizeof(size_t)) < int(sizeof(size_t))) {
    return "failure while reading length of exe path";
  }

  char exe_path[kMaxPathLength];
  if (read(pipe_wd_[0], exe_path, exe_path_length) < int(exe_path_length)) {
    return "failure while reading executable path";
  }
  std::string s_exe_path(exe_path);
  debug += "Executable path: " + s_exe_path + "\n";

  debug += GenerateStackTraceAndKill(s_exe_path, pid);

  return debug;
}

/**
 * Listens on the pipe and logs the stacktrace or quits silently.
 */
static void Watchdog() {
  char cflow;
  int num_read;

  while ((num_read = read(pipe_wd_[0], &cflow, 1)) > 0) {
    if (cflow == 'S') {
      const string debug = ReportStacktrace();
      LogEmergency(debug);
    } else if (cflow == 'Q') {
      break;
    } else {
      LogEmergency("unexpected error");
      break;
    }
  }
  if (num_read <= 0) LogEmergency("unexpected termination");

  close(pipe_wd_[0]);
}

bool Init(const string &cache_dir, const std::string &process_name,
          const bool check_max_open_files)
{
  monitor::cache_dir_ = new string(cache_dir);
  monitor::process_name_ = new string(process_name);
  if (platform_spinlock_init(&lock_handler_, 0) != 0) return false;

  /* check number of open files */
  if (check_max_open_files) {
    unsigned int soft_limit = 0;
    int hard_limit = 0;

    struct rlimit rpl;
    memset(&rpl, 0, sizeof(rpl));
    getrlimit(RLIMIT_NOFILE, &rpl);
    soft_limit = rpl.rlim_cur;

#ifdef __APPLE__
    hard_limit = sysconf(_SC_OPEN_MAX);
    if (hard_limit < 0) {
      LogCvmfs(kLogMonitor, kLogStdout, "Warning: could not retrieve "
               "hard limit for the number of open files");
    }
#else
    hard_limit = rpl.rlim_max;
#endif

    if (soft_limit < kMinOpenFiles) {
      LogCvmfs(kLogMonitor, kLogSyslog | kLogDebug,
               "Warning: current limits for number of open files are "
               "(%lu/%lu)\n"
               "CernVM-FS is likely to run out of file descriptors, "
               "set ulimit -n to at least %lu",
               soft_limit, hard_limit, kMinOpenFiles);
    }
    max_open_files_ = soft_limit;
  } else {
    max_open_files_ = 0;
  }

  // Dummy call to backtrace to load library
  void *unused = NULL;
  backtrace(&unused, 1);
  if (!unused) return false;

  return true;
}

void Fini() {
  // Reset signal handlers
  if (spawned_) {
    signal(SIGQUIT, SIG_DFL);
    signal(SIGILL, SIG_DFL);
    signal(SIGABRT, SIG_DFL);
    signal(SIGFPE, SIG_DFL);
    signal(SIGSEGV, SIG_DFL);
    signal(SIGBUS, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
    signal(SIGXFSZ, SIG_DFL);
    free(sighandler_stack_.ss_sp);
    sighandler_stack_.ss_size = 0;
  }

  delete process_name_;
  delete cache_dir_;
  process_name_ = NULL;
  cache_dir_ = NULL;
  if (spawned_) {
    char quit = 'Q';
    (void)write(pipe_wd_[1], &quit, 1);
    close(pipe_wd_[1]);
  }
  platform_spinlock_destroy(&lock_handler_);
}

/**
 * Fork watchdog.
 */
void Spawn() {
  MakePipe(pipe_wd_);

  pid_t pid;
  int statloc;
  switch (pid = fork()) {
    case -1: abort();
    case 0:
      // Double fork to avoid zombie
      switch (fork()) {
        case -1: exit(1);
        case 0: {
          close(pipe_wd_[1]);
          Daemonize();
          Watchdog();
          exit(0);
        }
        default:
          exit(0);
      }
    default:
      close(pipe_wd_[0]);
      if (waitpid(pid, &statloc, 0) != pid) abort();
      if (!WIFEXITED(statloc) || WEXITSTATUS(statloc)) abort();
  }

  // Extra stack for signal handlers
  int stack_size = kSignalHandlerStacksize;  // 2 MB
  sighandler_stack_.ss_sp = smalloc(stack_size);
  sighandler_stack_.ss_size = stack_size;
  sighandler_stack_.ss_flags = 0;
  if (sigaltstack(&sighandler_stack_, NULL) != 0)
    abort();

  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_sigaction = SendTrace;
  sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
  sigfillset(&sa.sa_mask);

  if (sigaction(SIGQUIT, &sa, NULL) ||
      sigaction(SIGILL, &sa, NULL) ||
      sigaction(SIGABRT, &sa, NULL) ||
      sigaction(SIGFPE, &sa, NULL) ||
      sigaction(SIGSEGV, &sa, NULL) ||
      sigaction(SIGBUS, &sa, NULL) ||
      sigaction(SIGPIPE, &sa, NULL) ||
      sigaction(SIGXFSZ, &sa, NULL))
  {
    abort();
  }
  spawned_ = true;
}

unsigned GetMaxOpenFiles() {
  return max_open_files_;
}

}  // namespace monitor
<commit_msg>call kill at the right moment<commit_after>/**
 * This file is part of the CernVM File System.
 *
 * This module forks a watchdog process that listens on
 * a pipe and prints a stackstrace into syslog, when cvmfs
 * fails.
 *
 * Also, it handles getting and setting the maximum number of file descriptors.
 */

#include "cvmfs_config.h"
#include "monitor.h"

#include <signal.h>
#include <sys/resource.h>
#include <execinfo.h>
#ifdef __APPLE__
  #include <sys/ucontext.h>
#else
  #include <ucontext.h>
#endif
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <pthread.h>
#include <time.h>

#include <string>

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cassert>

#include "platform.h"
#include "util.h"
#include "logging.h"
#include "smalloc.h"

using namespace std;  // NOLINT

namespace monitor {

const unsigned kMinOpenFiles = 8192;  /**< minmum threshold for the maximum
                                       number of open files */
const unsigned kMaxBacktrace = 64;  /**< reported stracktrace depth */
const unsigned kSignalHandlerStacksize = 2*1024*1024;  /**< 2 MB */

string *cache_dir_ = NULL;
string *process_name_ = NULL;
bool spawned_ = false;
unsigned max_open_files_;
int pipe_wd_[2];
platform_spinlock lock_handler_;
stack_t sighandler_stack_;

/**
 * Signal handler for signals that indicate a cvmfs crash.
 * Sends debug information to watchdog.
 */
static void SendTrace(int signal,
                      siginfo_t *siginfo __attribute__((unused)),
                      void *context)
{
  int send_errno = errno;
  if (platform_spinlock_trylock(&lock_handler_) != 0) {
    // Concurrent call, wait for the first one to exit the process
    while (true) {}
  }

  char cflow = 'S';
  if (write(pipe_wd_[1], &cflow, 1) != 1)
    _exit(1);

  // write the occured signal
  if (write(pipe_wd_[1], &signal, sizeof(signal)) != sizeof(signal))
    _exit(1);

  // write the last error number
  if (write(pipe_wd_[1], &send_errno, sizeof(send_errno)) != sizeof(send_errno))
    _exit(1);

  // write the PID
  pid_t pid = getpid();
  if (write(pipe_wd_[1], &pid, sizeof(pid_t)) != sizeof(pid_t))
    _exit(1);

  // write the exe path
  const char   *exe_path        = platform_getexepath();
  const size_t  exe_path_length = strlen(exe_path) + 1; // null termination
  if (write(pipe_wd_[1], &exe_path_length, sizeof(size_t)) != sizeof(size_t))
    _exit(1);
  if (write(pipe_wd_[1], exe_path, exe_path_length) != (int)exe_path_length)
    _exit(1);

  cflow = 'Q';
  (void)write(pipe_wd_[1], &cflow, 1);

  // do not die before the stack trace was generated
  // kill -9 <pid> will finish this
  while(true) {}

  _exit(1);
}

/**
 * Log a string to syslog and into $cachedir/stacktrace.
 * We expect ideally nothing to be logged, so that file is created on demand.
 */
static void LogEmergency(string msg) {
  char ctime_buffer[32];

  FILE *fp = fopen((*cache_dir_ + "/stacktrace." + *process_name_).c_str(),
                   "a");
  if (fp) {
    time_t now = time(NULL);
    msg += "\nTimestamp: " + string(ctime_r(&now, ctime_buffer));
    if (fwrite(&msg[0], 1, msg.length(), fp) != msg.length())
      msg += " (failed to report into log file in cache directory)";
    fclose(fp);
  } else {
    msg += " (failed to open log file in cache directory)";
  }
  LogCvmfs(kLogMonitor, kLogSyslog, "%s", msg.c_str());
}

/**
 * Uses an external shell and gdb to create a full stack trace of the dying
 * cvmfs client. The same shell is used to force-quit the client afterwards.
 */
static string GenerateStackTraceAndKill(const string &exe_path, const pid_t pid) {
  int retval;

  int fd_stdin;
  int fd_stdout;
  int fd_stderr;
  retval = Shell(&fd_stdin, &fd_stdout, &fd_stderr);
  assert(retval);

  // Let the shell execute the stacktrace extraction script
  const string bt_cmd = "/etc/cvmfs/gdb-stacktrace.sh " + exe_path + " " +
                     StringifyInt(pid) + "\n";
  WritePipe(fd_stdin, bt_cmd.data(), bt_cmd.length());

  // close the standard in to close the shell
  close(fd_stdin);

  // read the stack trace from the stdout of our shell
  const int bytes_at_a_time = 2;
  char *read_buffer = NULL;
  int buffer_size = 0;
  int buffer_offset = 0;
  int chars_io;
  while (1) {
    if (buffer_offset + bytes_at_a_time > buffer_size) {
      buffer_size = bytes_at_a_time + buffer_size * 2;
      read_buffer = (char*)realloc(read_buffer, buffer_size);
      assert (read_buffer);
    }

    chars_io = read(fd_stdout,
                    read_buffer + buffer_offset,
                    bytes_at_a_time);
    if (chars_io <= 0) break;
    buffer_offset += chars_io;
  }

  // close the pipes to the shell
  close(fd_stderr);
  close(fd_stdout);

  // give the dying cvmfs client the finishing stroke
  string result = "";
  if (kill(pid, SIGKILL) != 0) {
    result += "Failed to kill cvmfs client!\n\n";
  }

  // good bye...
  if (chars_io < 0) {
    result += "failed to read stack traces";
    return result;
  } else {
    return result + std::string(read_buffer);
  }
}

/**
 * Generates useful information from the backtrace log in the pipe.
 */
static string ReportStacktrace() {
  string debug = "--\n";

  int recv_signal;
  if (read(pipe_wd_[0], &recv_signal, sizeof(recv_signal)) <
      int(sizeof(recv_signal)))
  {
    return "failure while reading signal number";
  }
  debug += "Signal: " + StringifyInt(recv_signal);

  int recv_errno;
  if (read(pipe_wd_[0], &recv_errno, sizeof(recv_errno)) <
      int(sizeof(recv_errno)))
  {
    return "failure while reading errno";
  }
  debug += ", errno: " + StringifyInt(errno);

  debug += ", version: " + string(VERSION);

  pid_t pid;
  if (read(pipe_wd_[0], &pid, sizeof(pid_t)) < int(sizeof(pid_t))) {
    return "failure while reading PID";
  }
  debug += ", PID: " + StringifyInt(pid) + "\n";

  size_t exe_path_length;
  if (read(pipe_wd_[0], &exe_path_length, sizeof(size_t)) < int(sizeof(size_t))) {
    return "failure while reading length of exe path";
  }

  char exe_path[kMaxPathLength];
  if (read(pipe_wd_[0], exe_path, exe_path_length) < int(exe_path_length)) {
    return "failure while reading executable path";
  }
  std::string s_exe_path(exe_path);
  debug += "Executable path: " + s_exe_path + "\n";

  debug += GenerateStackTraceAndKill(s_exe_path, pid);

  return debug;
}

/**
 * Listens on the pipe and logs the stacktrace or quits silently.
 */
static void Watchdog() {
  char cflow;
  int num_read;

  while ((num_read = read(pipe_wd_[0], &cflow, 1)) > 0) {
    if (cflow == 'S') {
      const string debug = ReportStacktrace();
      LogEmergency(debug);
    } else if (cflow == 'Q') {
      break;
    } else {
      LogEmergency("unexpected error");
      break;
    }
  }
  if (num_read <= 0) LogEmergency("unexpected termination");

  close(pipe_wd_[0]);
}

bool Init(const string &cache_dir, const std::string &process_name,
          const bool check_max_open_files)
{
  monitor::cache_dir_ = new string(cache_dir);
  monitor::process_name_ = new string(process_name);
  if (platform_spinlock_init(&lock_handler_, 0) != 0) return false;

  /* check number of open files */
  if (check_max_open_files) {
    unsigned int soft_limit = 0;
    int hard_limit = 0;

    struct rlimit rpl;
    memset(&rpl, 0, sizeof(rpl));
    getrlimit(RLIMIT_NOFILE, &rpl);
    soft_limit = rpl.rlim_cur;

#ifdef __APPLE__
    hard_limit = sysconf(_SC_OPEN_MAX);
    if (hard_limit < 0) {
      LogCvmfs(kLogMonitor, kLogStdout, "Warning: could not retrieve "
               "hard limit for the number of open files");
    }
#else
    hard_limit = rpl.rlim_max;
#endif

    if (soft_limit < kMinOpenFiles) {
      LogCvmfs(kLogMonitor, kLogSyslog | kLogDebug,
               "Warning: current limits for number of open files are "
               "(%lu/%lu)\n"
               "CernVM-FS is likely to run out of file descriptors, "
               "set ulimit -n to at least %lu",
               soft_limit, hard_limit, kMinOpenFiles);
    }
    max_open_files_ = soft_limit;
  } else {
    max_open_files_ = 0;
  }

  // Dummy call to backtrace to load library
  void *unused = NULL;
  backtrace(&unused, 1);
  if (!unused) return false;

  return true;
}

void Fini() {
  // Reset signal handlers
  if (spawned_) {
    signal(SIGQUIT, SIG_DFL);
    signal(SIGILL, SIG_DFL);
    signal(SIGABRT, SIG_DFL);
    signal(SIGFPE, SIG_DFL);
    signal(SIGSEGV, SIG_DFL);
    signal(SIGBUS, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
    signal(SIGXFSZ, SIG_DFL);
    free(sighandler_stack_.ss_sp);
    sighandler_stack_.ss_size = 0;
  }

  delete process_name_;
  delete cache_dir_;
  process_name_ = NULL;
  cache_dir_ = NULL;
  if (spawned_) {
    char quit = 'Q';
    (void)write(pipe_wd_[1], &quit, 1);
    close(pipe_wd_[1]);
  }
  platform_spinlock_destroy(&lock_handler_);
}

/**
 * Fork watchdog.
 */
void Spawn() {
  MakePipe(pipe_wd_);

  pid_t pid;
  int statloc;
  switch (pid = fork()) {
    case -1: abort();
    case 0:
      // Double fork to avoid zombie
      switch (fork()) {
        case -1: exit(1);
        case 0: {
          close(pipe_wd_[1]);
          Daemonize();
          Watchdog();
          exit(0);
        }
        default:
          exit(0);
      }
    default:
      close(pipe_wd_[0]);
      if (waitpid(pid, &statloc, 0) != pid) abort();
      if (!WIFEXITED(statloc) || WEXITSTATUS(statloc)) abort();
  }

  // Extra stack for signal handlers
  int stack_size = kSignalHandlerStacksize;  // 2 MB
  sighandler_stack_.ss_sp = smalloc(stack_size);
  sighandler_stack_.ss_size = stack_size;
  sighandler_stack_.ss_flags = 0;
  if (sigaltstack(&sighandler_stack_, NULL) != 0)
    abort();

  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_sigaction = SendTrace;
  sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
  sigfillset(&sa.sa_mask);

  if (sigaction(SIGQUIT, &sa, NULL) ||
      sigaction(SIGILL, &sa, NULL) ||
      sigaction(SIGABRT, &sa, NULL) ||
      sigaction(SIGFPE, &sa, NULL) ||
      sigaction(SIGSEGV, &sa, NULL) ||
      sigaction(SIGBUS, &sa, NULL) ||
      sigaction(SIGPIPE, &sa, NULL) ||
      sigaction(SIGXFSZ, &sa, NULL))
  {
    abort();
  }
  spawned_ = true;
}

unsigned GetMaxOpenFiles() {
  return max_open_files_;
}

}  // namespace monitor
<|endoftext|>


<commit_before>#include"panelview.h"

PMonitor::PMonitor(void) : Dialog(false)
{
	const int width = qApp->desktop()->rect().width();
	const int height = qApp->desktop()->rect().height();

	setSceneRect(0, 0, width, height);
	setViewportUpdateMode(QGraphicsView::NoViewportUpdate);

	setAttribute(Qt::WA_PaintUnclipped);
	setAttribute(Qt::WA_NoSystemBackground);
	setAttribute(Qt::WA_NoBackground);
	setCacheMode(QGraphicsView::CacheNone);
	setOptimizationFlags(
		QGraphicsView::DontSavePainterState |
		QGraphicsView::DontAdjustForAntialiasing);

	viewport()->setAttribute(Qt::WA_TranslucentBackground, false);
	scene()->setItemIndexMethod(QGraphicsScene::NoIndex);

	rootContext()->setContextProperty("screenWidth", width);
	rootContext()->setContextProperty("screenHeight", height);

	setSource(QUrl::fromLocalFile("/usr/share/meego-ux-panels/main.qml"));
}

PanelView::PanelView(void) : Dialog(false),
		QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap)
{

	const int width = qApp->desktop()->rect().width();
	const int height = qApp->desktop()->rect().height();

	int j, k, total=1, cur_width, cur_height=0;
	QList<QObject*> tmp;
	QDeclarativeItem *dec;
	QObject *i;

	r = new PMonitor();

	if((i = r->rootObject()->findChild<QDeclarativeItem *>("appPage")) == NULL |
	   (i = i->findChild<QDeclarativeItem *>("PC")) == NULL |
	   (i = i->findChild<QDeclarativeItem *>("PLV")) == NULL) {
		qFatal("Upgrade your version of MeeGo-UX-Panels");
	}
	fwidth = i->property("contentWidth").toInt();
	r->rootObject()->setProperty("width", fwidth);
	r->rootObject()->setProperty("height", height);

	QObject::connect(r->scene(), SIGNAL(changed(const QList<QRectF>&)),
			this, SLOT(invalidate(void)));

	setSceneRect(0, 0, width, height);

	const int p_width = fwidth /  NUM_C;
	const int p_height = height / NUM_R;
	for(j = 0; j < NUM_P; j++) {
		cache[j] = new QPixmap(p_width, p_height);
	}

	invalidate();
	engine()->addImageProvider(QLatin1String("gen"), this);

	setSource(QUrl::fromLocalFile("/usr/share/meego-ux-daemon/real.qml"));
	rootObject()->setProperty("contentWidth", fwidth);
	rootObject()->setProperty("contentHeight", height);
	rootObject()->setProperty("width", width);
	rootObject()->setProperty("height", height);

	dec =  qobject_cast<QDeclarativeItem*>(rootObject());
	tmp = dec->children();

	for(j = 0; j < NUM_R; j++) {
		cur_width = 0;
		for(k = 0; k < NUM_C; k++) {
			tmp.at(total)->setProperty("width", p_width);
			tmp.at(total)->setProperty("height", p_height);
			tmp.at(total)->setProperty("x", cur_width);
			tmp.at(total)->setProperty("y", cur_height);

			QString meh = QString(ISRC);
			meh += QString::number(total-1);
			tmp.at(total)->setProperty("source", meh);

			cur_width += p_width;
			total++;
		}
		cur_height += p_height;
	}

	setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);

	setOptimizationFlags(
		QGraphicsView::DontSavePainterState |
		QGraphicsView::DontAdjustForAntialiasing);

	setCacheMode(QGraphicsView::CacheBackground);
	scene()->setItemIndexMethod(QGraphicsScene::NoIndex);
	viewport()->setAttribute(Qt::WA_PaintUnclipped);

	create_bg();
}

PanelView::~PanelView(void)
{
	int i;

	for(i = 0; i < NUM_P; i++) {
		delete cache[i];
	}

	delete r;
	delete background;
	delete bg_window;

}

void PanelView::keyPressEvent(QKeyEvent *e)
{
	r->keyPressEvent(e);
	return;
}

void PanelView::keyReleaseEvent(QKeyEvent *e)
{
	r->keyReleaseEvent(e);
	return;
}

void PanelView::mouseDoubleClickEvent(QMouseEvent *e)
{
	r->mouseDoubleClickEvent(e);
	return;
}

void PanelView::mousePressEvent(QMouseEvent *e)
{
	QDeclarativeItem *i;

	i = qobject_cast<QDeclarativeItem *>(rootObject());
	QPoint j(e->x() + i->property("contentX").toDouble(), e->y());
	QMouseEvent k(e->type(), j, e->button(), e->buttons(), e->modifiers());

	bg_window->mousePressEvent(e);
	r->mousePressEvent(&k);
	QDeclarativeView::mousePressEvent(e);
	return;
}

void PanelView::mouseReleaseEvent(QMouseEvent *e)
{
	bg_window->mouseReleaseEvent(e);
	r->mouseReleaseEvent(e);
	QDeclarativeView::mouseReleaseEvent(e);
	return;
}

void PanelView::tabletEvent(QTabletEvent *e)
{
	r->tabletEvent(e);
	return;
}

QPixmap PanelView::requestPixmap(const QString &id, QSize *size,
		const QSize &resize)
{
	int i = id.toInt();
	while(i >= NUM_P) { i -= NUM_P; }
	return *cache[i];
}

void PanelView::invalidate(void)
{
	int i,j,k,m;

	QPixmap *old, *tmp;
	QPainter p;

	QDeclarativeItem *dec;
	QList<QObject *> kids;
	QString src;

	const int height = qApp->desktop()->rect().height();
	const int p_width = fwidth /  NUM_C;
	const int p_height = height / NUM_R;
	const QRgb tran  = QColor(Qt::transparent).rgb();
	QRgb bg_color;

	dec = qobject_cast<QDeclarativeItem *>(rootObject());
	if(dec != NULL) {
		kids = dec->children();
	}

	int total = 0;
	for(i = 0; i < NUM_R; i++) {
		for(j = 0; j < NUM_C; j++) {
			old = cache[total];

			QImage img(p_width, p_height,QImage::Format_ARGB32_Premultiplied);

			p.begin(&img);
			r->viewport()->render(&p, QPoint(),
				 QRegion( p_width * j, p_height * i,
					  p_width, p_height));
			p.end();

			if(total == 0) {
				bg_color = img.pixel(0,0);
			}

			tmp = new QPixmap(p_width, p_height);
			tmp->convertFromImage(img,
				Qt::ColorOnly | Qt::NoOpaqueDetection);
			QBitmap mask = QBitmap::fromImage(
					img.createMaskFromColor(bg_color));
			tmp->setMask(mask);

			cache[total] = tmp;
			delete old;

			if(dec != NULL) {
				src = kids.at(total+1)->property("source").toString();
				k = src.right( src.size() - ISRC_LEN).toInt();
				src.truncate(ISRC_LEN);
				k += NUM_P;
				src += QString::number(k);
				kids.at(total+1)->setProperty("source", src);
			}

			total++;
		}
	}
	return;
}

void PanelView::create_bg(void)
{
	const int width = qApp->desktop()->rect().width();
	const int height = qApp->desktop()->rect().height();

	bg_window = new PMonitor();
	bg_window->setSource(QUrl::fromLocalFile("/usr/share/meego-ux-daemon/background.qml"));
	background = new QPixmap(width, height);

	QObject::connect(bg_window->scene(), SIGNAL(changed(const QList<QRectF>&)),
			this, SLOT(bg_changed(void)));
}

void PanelView::bg_changed(void)
{
	QPainter bg_painter(background);
	bg_window->viewport()->render(&bg_painter);
	bg_painter.end();
	QBrush br(*background);
	br.setStyle(Qt::TexturePattern);
	setBackgroundBrush(br);

	scene()->invalidate(QRectF(0,0,0,0), QGraphicsScene::BackgroundLayer);
}

<commit_msg>Remove attribute WA_PaintUnclipped, as it only works with WA_PaintOnScreen.<commit_after>#include"panelview.h"

PMonitor::PMonitor(void) : Dialog(false)
{
	const int width = qApp->desktop()->rect().width();
	const int height = qApp->desktop()->rect().height();

	setSceneRect(0, 0, width, height);
	setViewportUpdateMode(QGraphicsView::NoViewportUpdate);

	setAttribute(Qt::WA_NoSystemBackground);
	setAttribute(Qt::WA_NoBackground);
	setCacheMode(QGraphicsView::CacheNone);
	setOptimizationFlags(
		QGraphicsView::DontSavePainterState |
		QGraphicsView::DontAdjustForAntialiasing);

	viewport()->setAttribute(Qt::WA_TranslucentBackground, false);
	scene()->setItemIndexMethod(QGraphicsScene::NoIndex);

	rootContext()->setContextProperty("screenWidth", width);
	rootContext()->setContextProperty("screenHeight", height);

	setSource(QUrl::fromLocalFile("/usr/share/meego-ux-panels/main.qml"));
}

PanelView::PanelView(void) : Dialog(false),
		QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap)
{

	const int width = qApp->desktop()->rect().width();
	const int height = qApp->desktop()->rect().height();

	int j, k, total=1, cur_width, cur_height=0;
	QList<QObject*> tmp;
	QDeclarativeItem *dec;
	QObject *i;

	r = new PMonitor();

	if((i = r->rootObject()->findChild<QDeclarativeItem *>("appPage")) == NULL |
	   (i = i->findChild<QDeclarativeItem *>("PC")) == NULL |
	   (i = i->findChild<QDeclarativeItem *>("PLV")) == NULL) {
		qFatal("Upgrade your version of MeeGo-UX-Panels");
	}
	fwidth = i->property("contentWidth").toInt();
	r->rootObject()->setProperty("width", fwidth);
	r->rootObject()->setProperty("height", height);

	QObject::connect(r->scene(), SIGNAL(changed(const QList<QRectF>&)),
			this, SLOT(invalidate(void)));

	setSceneRect(0, 0, width, height);

	const int p_width = fwidth /  NUM_C;
	const int p_height = height / NUM_R;
	for(j = 0; j < NUM_P; j++) {
		cache[j] = new QPixmap(p_width, p_height);
	}

	invalidate();
	engine()->addImageProvider(QLatin1String("gen"), this);

	setSource(QUrl::fromLocalFile("/usr/share/meego-ux-daemon/real.qml"));
	rootObject()->setProperty("contentWidth", fwidth);
	rootObject()->setProperty("contentHeight", height);
	rootObject()->setProperty("width", width);
	rootObject()->setProperty("height", height);

	dec =  qobject_cast<QDeclarativeItem*>(rootObject());
	tmp = dec->children();

	for(j = 0; j < NUM_R; j++) {
		cur_width = 0;
		for(k = 0; k < NUM_C; k++) {
			tmp.at(total)->setProperty("width", p_width);
			tmp.at(total)->setProperty("height", p_height);
			tmp.at(total)->setProperty("x", cur_width);
			tmp.at(total)->setProperty("y", cur_height);

			QString meh = QString(ISRC);
			meh += QString::number(total-1);
			tmp.at(total)->setProperty("source", meh);

			cur_width += p_width;
			total++;
		}
		cur_height += p_height;
	}

	setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);

	setOptimizationFlags(
		QGraphicsView::DontSavePainterState |
		QGraphicsView::DontAdjustForAntialiasing);

	setCacheMode(QGraphicsView::CacheBackground);
	scene()->setItemIndexMethod(QGraphicsScene::NoIndex);
	viewport()->setAttribute(Qt::WA_OpaquePaintEvent);

	create_bg();
}

PanelView::~PanelView(void)
{
	int i;

	for(i = 0; i < NUM_P; i++) {
		delete cache[i];
	}

	delete r;
	delete background;
	delete bg_window;

}

void PanelView::keyPressEvent(QKeyEvent *e)
{
	r->keyPressEvent(e);
	return;
}

void PanelView::keyReleaseEvent(QKeyEvent *e)
{
	r->keyReleaseEvent(e);
	return;
}

void PanelView::mouseDoubleClickEvent(QMouseEvent *e)
{
	r->mouseDoubleClickEvent(e);
	return;
}

void PanelView::mousePressEvent(QMouseEvent *e)
{
	QDeclarativeItem *i;

	i = qobject_cast<QDeclarativeItem *>(rootObject());
	QPoint j(e->x() + i->property("contentX").toDouble(), e->y());
	QMouseEvent k(e->type(), j, e->button(), e->buttons(), e->modifiers());

	bg_window->mousePressEvent(e);
	r->mousePressEvent(&k);
	QDeclarativeView::mousePressEvent(e);
	return;
}

void PanelView::mouseReleaseEvent(QMouseEvent *e)
{
	bg_window->mouseReleaseEvent(e);
	r->mouseReleaseEvent(e);
	QDeclarativeView::mouseReleaseEvent(e);
	return;
}

void PanelView::tabletEvent(QTabletEvent *e)
{
	r->tabletEvent(e);
	return;
}

QPixmap PanelView::requestPixmap(const QString &id, QSize *size,
		const QSize &resize)
{
	int i = id.toInt();
	while(i >= NUM_P) { i -= NUM_P; }
	return *cache[i];
}

void PanelView::invalidate(void)
{
	int i,j,k,m;

	QPixmap *old, *tmp;
	QPainter p;

	QDeclarativeItem *dec;
	QList<QObject *> kids;
	QString src;

	const int height = qApp->desktop()->rect().height();
	const int p_width = fwidth /  NUM_C;
	const int p_height = height / NUM_R;
	const QRgb tran  = QColor(Qt::transparent).rgb();
	QRgb bg_color;

	dec = qobject_cast<QDeclarativeItem *>(rootObject());
	if(dec != NULL) {
		kids = dec->children();
	}

	int total = 0;
	for(i = 0; i < NUM_R; i++) {
		for(j = 0; j < NUM_C; j++) {
			old = cache[total];

			QImage img(p_width, p_height,QImage::Format_ARGB32_Premultiplied);

			p.begin(&img);
			r->viewport()->render(&p, QPoint(),
				 QRegion( p_width * j, p_height * i,
					  p_width, p_height));
			p.end();

			if(total == 0) {
				bg_color = img.pixel(0,0);
			}

			tmp = new QPixmap(p_width, p_height);
			tmp->convertFromImage(img,
				Qt::ColorOnly | Qt::NoOpaqueDetection);
			QBitmap mask = QBitmap::fromImage(
					img.createMaskFromColor(bg_color));
			tmp->setMask(mask);

			cache[total] = tmp;
			delete old;

			if(dec != NULL) {
				src = kids.at(total+1)->property("source").toString();
				k = src.right( src.size() - ISRC_LEN).toInt();
				src.truncate(ISRC_LEN);
				k += NUM_P;
				src += QString::number(k);
				kids.at(total+1)->setProperty("source", src);
			}

			total++;
		}
	}
	return;
}

void PanelView::create_bg(void)
{
	const int width = qApp->desktop()->rect().width();
	const int height = qApp->desktop()->rect().height();

	bg_window = new PMonitor();
	bg_window->setSource(QUrl::fromLocalFile("/usr/share/meego-ux-daemon/background.qml"));
	background = new QPixmap(width, height);

	QObject::connect(bg_window->scene(), SIGNAL(changed(const QList<QRectF>&)),
			this, SLOT(bg_changed(void)));
}

void PanelView::bg_changed(void)
{
	QPainter bg_painter(background);
	bg_window->viewport()->render(&bg_painter);
	bg_painter.end();
	QBrush br(*background);
	br.setStyle(Qt::TexturePattern);
	setBackgroundBrush(br);

	scene()->invalidate(QRectF(0,0,0,0), QGraphicsScene::BackgroundLayer);
}

<|endoftext|>


<commit_before>#include "parser_impl.hpp"
#include <boost/spirit/include/qi_uint.hpp>

#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
// #define BOOST_SPIRIT_QI_DEBUG

// shorthand

namespace qi = boost::spirit::qi;

// integer grammar implementation

formast::Parser::Impl::integer_grammar::integer_grammar() : integer_grammar::base_type(uint_or_version)
{

    qi::uint_parser<boost::uint64_t, 16> hex_parser;
    qi::lit_type lit;
    qi::uint_type ulong_long;
    qi::_val_type _val;
    qi::_1_type _1;
    qi::_2_type _2;
    qi::_3_type _3;
    qi::_4_type _4;

    uint_or_version =
        hex
        |   (lit("2.3")   [_val = 0x02030000])
        |   (lit("3.03")  [_val = 0x03000300]) // special case
        |   (lit("3.0")   [_val = 0x03000000])
        |   (lit("3.1")   [_val = 0x03010000])
        |   ((ulong_long                [_val = _1])
             >> -('.' >> (ulong_long    [_val = _val * 256 + _1])
                  >> '.' > (ulong_long  [_val = _val * 256 + _1])
                  > '.' > (ulong_long   [_val = _val * 256 + _1])))
        ;

    hex = lit("0x") > hex_parser;

    // Debugging and error handling and reporting support.
    BOOST_SPIRIT_DEBUG_NODE(uint_or_version);

    // Error handling
    qi::on_error<qi::fail>(uint_or_version, error_handler(_4, _3, _2));
}
<commit_msg>Fix hex parsing.<commit_after>#include "parser_impl.hpp"
#include <boost/spirit/include/qi_uint.hpp>

#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
// #define BOOST_SPIRIT_QI_DEBUG

// shorthand

namespace qi = boost::spirit::qi;

// integer grammar implementation

formast::Parser::Impl::integer_grammar::integer_grammar() : integer_grammar::base_type(uint_or_version)
{

    qi::uint_parser<boost::uint64_t, 16> hex_parser;
    qi::lit_type lit;
    qi::uint_type ulong_long;
    qi::_val_type _val;
    qi::_1_type _1;
    qi::_2_type _2;
    qi::_3_type _3;
    qi::_4_type _4;

    uint_or_version =
        (hex              [_val = _1])
        |   (lit("2.3")   [_val = 0x02030000])
        |   (lit("3.03")  [_val = 0x03000300]) // special case
        |   (lit("3.0")   [_val = 0x03000000])
        |   (lit("3.1")   [_val = 0x03010000])
        |   ((ulong_long                [_val = _1])
             >> -('.' >> (ulong_long    [_val = _val * 256 + _1])
                  >> '.' > (ulong_long  [_val = _val * 256 + _1])
                  > '.' > (ulong_long   [_val = _val * 256 + _1])))
        ;

    hex %= lit("0x") > hex_parser;

    // Debugging and error handling and reporting support.
    BOOST_SPIRIT_DEBUG_NODE(uint_or_version);
    BOOST_SPIRIT_DEBUG_NODE(hex);

    // Error handling
    qi::on_error<qi::fail>(uint_or_version, error_handler(_4, _3, _2));
}
<|endoftext|>