mirror of
https://github.com/facebook/sapling.git
synced 2025-01-06 04:43:19 +03:00
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:
parent
c292d5e9bf
commit
078d57c4ee
58
eden/fs/utils/IDGen.cpp
Normal file
58
eden/fs/utils/IDGen.cpp
Normal 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
27
eden/fs/utils/IDGen.h
Normal 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
|
23
eden/fs/utils/test/IDGenTest.cpp
Normal file
23
eden/fs/utils/test/IDGenTest.cpp
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user