示例#1
0
TEST_F(HashTableTest, CanInsertUniqueKeys) {
  codegen::util::HashTable table{GetMemPool(), sizeof(Key), sizeof(Value)};

  constexpr uint32_t to_insert = 50000;
  constexpr uint32_t c1 = 4444;

  std::vector<Key> keys;

  // Insert keys
  for (uint32_t i = 0; i < to_insert; i++) {
    Key k{1, i};
    Value v = {.v1 = k.k2, .v2 = 2, .v3 = 3, .v4 = c1};
    table.TypedInsert(k.Hash(), k, v);

    keys.emplace_back(k);
  }

  EXPECT_EQ(to_insert, table.NumElements());

  // Lookup
  for (const auto &key : keys) {
    uint32_t count = 0;
    std::function<void(const Value &v)> f = [&key, &count, &c1](const Value &v) {
      EXPECT_EQ(key.k2, v.v1)
          << "Value's [v1] found in table doesn't match insert key";
      EXPECT_EQ(c1, v.v4) << "Value's [v4] doesn't match constant";
      count++;
    };
    table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(1, count) << "Found duplicate keys in unique key test";
  }
}

TEST_F(HashTableTest, BuildEmptyHashTable) {
  codegen::util::HashTable table{GetMemPool(), sizeof(Key), sizeof(Value)};

  std::vector<Key> keys;

  // Insert keys
  for (uint32_t i = 0; i < 10; i++) {
    Key k{1, i};
    // do NOT insert into hash table

    keys.emplace_back(k);
  }

  EXPECT_EQ(0, table.NumElements());

  // Build lazy
  table.BuildLazy();

  // Lookups should succeed
  for (const auto &key : keys) {
    std::function<void(const Value &v)> f =
        [](UNUSED_ATTRIBUTE const Value &v) {};
    auto ret = table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(false, ret);
  }
}
bool CMempoolComponent::ComponentInitialize()
{
    NLogStream() << "initialize CTxMemPool component";

    InitializeForNet();

    InitFeeEstimate();
    GetMemPool().SetEstimator(&feeEstimator);

    if (Args().GetArg<bool>("-persistmempool", DEFAULT_PERSIST_MEMPOOL))
    {
        LoadMempool();
        bDumpMempoolLater = true;
    }
    return true;
}
示例#3
0
TEST_F(HashTableTest, CanInsertDuplicateKeys) {
  codegen::util::HashTable table{GetMemPool(), sizeof(Key), sizeof(Value)};

  constexpr uint32_t to_insert = 50000;
  constexpr uint32_t c1 = 4444;
  constexpr uint32_t max_dups = 4;

  std::vector<Key> keys;

  // Insert keys
  uint32_t num_inserts = 0;
  for (uint32_t i = 0; i < to_insert; i++) {
    // Choose a random number of duplicates to insert. Store this in the k1.
    uint32_t num_dups = 1 + (rand() % max_dups);
    Key k{num_dups, i};

    // Duplicate insertion
    for (uint32_t dup = 0; dup < num_dups; dup++) {
      Value v = {.v1 = k.k2, .v2 = 2, .v3 = 3, .v4 = c1};
      table.TypedInsert(k.Hash(), k, v);
      num_inserts++;
    }

    keys.emplace_back(k);
  }

  EXPECT_EQ(num_inserts, table.NumElements());

  // Lookup
  for (const auto &key : keys) {
    uint32_t count = 0;
    std::function<void(const Value &v)> f = [&key, &count, &c1](const Value &v) {
      EXPECT_EQ(key.k2, v.v1)
          << "Value's [v1] found in table doesn't match insert key";
      EXPECT_EQ(c1, v.v4) << "Value's [v4] doesn't match constant";
      count++;
    };
    table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(key.k1, count) << key << " found " << count << " dups ...";
  }
}

TEST_F(HashTableTest, CanInsertLazilyWithDups) {
  codegen::util::HashTable table{GetMemPool(), sizeof(Key), sizeof(Value)};

  constexpr uint32_t to_insert = 50000;
  constexpr uint32_t c1 = 4444;
  constexpr uint32_t max_dups = 4;

  std::vector<Key> keys;

  // Insert keys
  uint32_t num_inserts = 0;
  for (uint32_t i = 0; i < to_insert; i++) {
    // Choose a random number of duplicates to insert. Store this in the k1.
    uint32_t num_dups = 1 + (rand() % max_dups);
    Key k{num_dups, i};

    // Duplicate insertion
    for (uint32_t dup = 0; dup < num_dups; dup++) {
      Value v = {.v1 = k.k2, .v2 = 2, .v3 = 3, .v4 = c1};
      table.TypedInsertLazy(k.Hash(), k, v);
      num_inserts++;
    }

    keys.emplace_back(k);
  }

  // Number of elements should reflect lazy insertions
  EXPECT_EQ(num_inserts, table.NumElements());
  EXPECT_LT(table.Capacity(), table.NumElements());

  // Build lazy
  table.BuildLazy();

  // Lookups should succeed
  for (const auto &key : keys) {
    uint32_t count = 0;
    std::function<void(const Value &v)> f = [&key, &count, &c1](const Value &v) {
      EXPECT_EQ(key.k2, v.v1)
          << "Value's [v1] found in table doesn't match insert key";
      EXPECT_EQ(c1, v.v4) << "Value's [v4] doesn't match constant";
      count++;
    };
    table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(key.k1, count) << key << " found " << count << " dups ...";
  }
}

TEST_F(HashTableTest, ParallelMerge) {
  constexpr uint32_t num_threads = 4;
  constexpr uint32_t to_insert = 20000;

  // Allocate hash tables for each thread
  executor::ExecutorContext exec_ctx{nullptr};

  auto &thread_states = exec_ctx.GetThreadStates();
  thread_states.Reset(sizeof(codegen::util::HashTable));
  thread_states.Allocate(num_threads);

  // The keys we insert
  std::mutex keys_mutex;
  std::vector<Key> keys;

  // The global hash table
  codegen::util::HashTable global_table{*exec_ctx.GetPool(), sizeof(Key),
                                        sizeof(Value)};

  auto add_key = [&keys_mutex, &keys](const Key &k) {
    std::lock_guard<std::mutex> lock{keys_mutex};
    keys.emplace_back(k);
  };

  // Insert function
  auto insert_fn = [&add_key, &exec_ctx](uint64_t tid) {
    // Get the local table for this thread
    auto *table = reinterpret_cast<codegen::util::HashTable *>(
        exec_ctx.GetThreadStates().AccessThreadState(tid));

    // Initialize it
    codegen::util::HashTable::Init(*table, exec_ctx, sizeof(Key),
                                   sizeof(Value));

    // Insert keys disjoint from other threads
    for (uint32_t i = tid * to_insert, end = i + to_insert; i != end; i++) {
      Key k{static_cast<uint32_t>(tid), i};
      Value v = {.v1 = k.k2, .v2 = k.k1, .v3 = 3, .v4 = 4444};
      table->TypedInsertLazy(k.Hash(), k, v);

      add_key(k);
    }
  };

  auto merge_fn = [&global_table, &thread_states](uint64_t tid) {
    // Get the local table for this threads
    auto *table = reinterpret_cast<codegen::util::HashTable *>(
        thread_states.AccessThreadState(tid));

    // Merge it into the global table
    global_table.MergeLazyUnfinished(*table);
  };

  // First insert into thread local tables in parallel
  LaunchParallelTest(num_threads, insert_fn);
  for (uint32_t tid = 0; tid < num_threads; tid++) {
    auto *ht = reinterpret_cast<codegen::util::HashTable *>(
        thread_states.AccessThreadState(tid));
    EXPECT_EQ(to_insert, ht->NumElements());
  }

  // Now resize global table
  global_table.ReserveLazy(thread_states, 0);
  EXPECT_EQ(NextPowerOf2(keys.size()), global_table.Capacity());

  // Now merge thread-local tables into global table in parallel
  LaunchParallelTest(num_threads, merge_fn);

  // Clean up local tables
  for (uint32_t tid = 0; tid < num_threads; tid++) {
    auto *table = reinterpret_cast<codegen::util::HashTable *>(
        thread_states.AccessThreadState(tid));
    codegen::util::HashTable::Destroy(*table);
  }

  // Now probe global
  EXPECT_EQ(to_insert * num_threads, global_table.NumElements());
  EXPECT_LE(global_table.NumElements(), global_table.Capacity());
  for (const auto &key : keys) {
    uint32_t count = 0;
    std::function<void(const Value &v)> f = [&key, &count](const Value &v) {
      EXPECT_EQ(key.k2, v.v1)
          << "Value's [v1] found in table doesn't match insert key";
      EXPECT_EQ(key.k1, v.v2) << "Key " << key << " inserted by thread "
                              << key.k1 << " but value was inserted by thread "
                              << v.v2;
      count++;
    };
    global_table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(1, count) << "Found duplicate keys in unique key test";
  }
}

}  // namespace test