add a cheap unique ID generator

Summary:
Add a very cheap unique ID allocator designed for extremely
low-latency uses like D10384071.

Differential Revision: D10501712

fbshipit-source-id: 15a0b7a2d344c0f6100082850dd967c585f3e2da
This commit is contained in:
Chad Austin 2018-10-23 10:41:09 -07:00 committed by Facebook Github Bot
parent c292d5e9bf
commit 078d57c4ee
3 changed files with 108 additions and 0 deletions

58
eden/fs/utils/IDGen.cpp Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "eden/fs/utils/IDGen.h"
#include <folly/CachelinePadded.h>
#include <folly/ThreadLocal.h>
#include <atomic>
namespace {
/**
* Allocating one unique ID per nanosecond would wrap around in over 500 years.
*
* CachelinePadded may be excessive here.
*/
folly::CachelinePadded<std::atomic<uint64_t>> globalCounter;
struct LocalRange {
uint64_t begin{0};
uint64_t end{0};
};
folly::ThreadLocal<LocalRange> localRange;
/**
* Number of unique IDs to hand out to a thread at a time. This avoids cache
* line contention on globalCounter. kRangeSize should be large enough to reduce
* contention but small enough that the pathological case of threads being
* spawned in a tight loop, each allocating one unique ID, does not rapidly
* exhaust the 64-bit counter space.
*
* I haven't measured, but I'd be surprised if a thread could be created in
* 2000 nanoseconds.
*/
constexpr uint64_t kRangeSize = 2000;
} // namespace
namespace facebook {
namespace eden {
uint64_t generateUniqueID() {
auto range = localRange.get();
if (UNLIKELY(range->begin == range->end)) {
auto begin =
globalCounter->fetch_add(kRangeSize, std::memory_order_relaxed);
range->begin = begin;
range->end = begin + kRangeSize;
}
return range->begin++;
}
} // namespace eden
} // namespace facebook

27
eden/fs/utils/IDGen.h Normal file
View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#pragma once
#include <stdint.h>
namespace facebook {
namespace eden {
/**
* Very efficiently returns a new uint64_t unique to this process. Amortizes
* the cost of synchronizing threads across many ID allocations.
*
* TODO: It could be beneficial to add a parameter to request more than one
* unique ID at a time.
*/
uint64_t generateUniqueID();
} // namespace eden
} // namespace facebook

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "eden/fs/utils/IDGen.h"
#include <gtest/gtest.h>
using namespace facebook::eden;
TEST(IDGenTest, producesUniqueIDs) {
auto id1 = generateUniqueID();
auto id2 = generateUniqueID();
auto id3 = generateUniqueID();
EXPECT_NE(id1, id2);
EXPECT_NE(id2, id3);
EXPECT_NE(id2, id3);
}