Resolve race when getting approximate-memory-usage property
The write operations in the table happens without holding the mutex lock, but concurrent writes are avoided using "writers_" queue. The Arena::MemoryUsage could access the blocks when write happens. So, the memory usage is cached in atomic word and can be loaded from any thread safely. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=107573379
This commit is contained in:
parent
3c9ff3c691
commit
706b7f8d43
@ -36,10 +36,7 @@ class MemTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns an estimate of the number of bytes of data in use by this
|
// Returns an estimate of the number of bytes of data in use by this
|
||||||
// data structure.
|
// data structure. It is safe to call when MemTable is being modified.
|
||||||
//
|
|
||||||
// REQUIRES: external synchronization to prevent simultaneous
|
|
||||||
// operations on the same MemTable.
|
|
||||||
size_t ApproximateMemoryUsage();
|
size_t ApproximateMemoryUsage();
|
||||||
|
|
||||||
// Return an iterator that yields the contents of the memtable.
|
// Return an iterator that yields the contents of the memtable.
|
||||||
|
@ -9,8 +9,7 @@ namespace leveldb {
|
|||||||
|
|
||||||
static const int kBlockSize = 4096;
|
static const int kBlockSize = 4096;
|
||||||
|
|
||||||
Arena::Arena() {
|
Arena::Arena() : memory_usage_(0) {
|
||||||
blocks_memory_ = 0;
|
|
||||||
alloc_ptr_ = NULL; // First allocation will allocate a block
|
alloc_ptr_ = NULL; // First allocation will allocate a block
|
||||||
alloc_bytes_remaining_ = 0;
|
alloc_bytes_remaining_ = 0;
|
||||||
}
|
}
|
||||||
@ -60,8 +59,9 @@ char* Arena::AllocateAligned(size_t bytes) {
|
|||||||
|
|
||||||
char* Arena::AllocateNewBlock(size_t block_bytes) {
|
char* Arena::AllocateNewBlock(size_t block_bytes) {
|
||||||
char* result = new char[block_bytes];
|
char* result = new char[block_bytes];
|
||||||
blocks_memory_ += block_bytes;
|
|
||||||
blocks_.push_back(result);
|
blocks_.push_back(result);
|
||||||
|
memory_usage_.NoBarrier_Store(
|
||||||
|
reinterpret_cast<void*>(MemoryUsage() + block_bytes + sizeof(char*)));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
util/arena.h
10
util/arena.h
@ -9,6 +9,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "port/port.h"
|
||||||
|
|
||||||
namespace leveldb {
|
namespace leveldb {
|
||||||
|
|
||||||
@ -24,10 +25,9 @@ class Arena {
|
|||||||
char* AllocateAligned(size_t bytes);
|
char* AllocateAligned(size_t bytes);
|
||||||
|
|
||||||
// Returns an estimate of the total memory usage of data allocated
|
// Returns an estimate of the total memory usage of data allocated
|
||||||
// by the arena (including space allocated but not yet used for user
|
// by the arena.
|
||||||
// allocations).
|
|
||||||
size_t MemoryUsage() const {
|
size_t MemoryUsage() const {
|
||||||
return blocks_memory_ + blocks_.capacity() * sizeof(char*);
|
return reinterpret_cast<uintptr_t>(memory_usage_.NoBarrier_Load());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -41,8 +41,8 @@ class Arena {
|
|||||||
// Array of new[] allocated memory blocks
|
// Array of new[] allocated memory blocks
|
||||||
std::vector<char*> blocks_;
|
std::vector<char*> blocks_;
|
||||||
|
|
||||||
// Bytes of memory in blocks allocated so far
|
// Total memory usage of the arena.
|
||||||
size_t blocks_memory_;
|
port::AtomicPointer memory_usage_;
|
||||||
|
|
||||||
// No copying allowed
|
// No copying allowed
|
||||||
Arena(const Arena&);
|
Arena(const Arena&);
|
||||||
|
Loading…
Reference in New Issue
Block a user