Browse Source

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
naive_version
ssid 9 years ago
committed by Chris Mumford
parent
commit
706b7f8d43
3 changed files with 9 additions and 12 deletions
  1. +1
    -4
      db/memtable.h
  2. +3
    -3
      util/arena.cc
  3. +5
    -5
      util/arena.h

+ 1
- 4
db/memtable.h View File

@ -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.
//
// REQUIRES: external synchronization to prevent simultaneous
// operations on the same MemTable.
// data structure. It is safe to call when MemTable is being modified.
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.

+ 3
- 3
util/arena.cc View File

@ -9,8 +9,7 @@ namespace leveldb {
static const int kBlockSize = 4096; static const int kBlockSize = 4096;
Arena::Arena() {
blocks_memory_ = 0;
Arena::Arena() : memory_usage_(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;
} }

+ 5
- 5
util/arena.h View File

@ -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
// allocations).
// by the arena.
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
size_t blocks_memory_;
// Total memory usage of the arena.
port::AtomicPointer memory_usage_;
// No copying allowed // No copying allowed
Arena(const Arena&); Arena(const Arena&);

Loading…
Cancel
Save