classArena { public: // Return a pointer to a newly allocated memory block of "bytes" bytes. char* Allocate(size_t bytes);
// Allocate memory with the normal alignment guarantees provided by malloc. char* AllocateAligned(size_t bytes);
// Returns an estimate of the total memory usage of data allocated // by the arena. size_tMemoryUsage()const{ return memory_usage_.load(std::memory_order_relaxed); }
private: // Allocation state char* alloc_ptr_; size_t alloc_bytes_remaining_;
// Array of new[] allocated memory blocks std::vector<char*> blocks_;
// Total memory usage of the arena. // // TODO(costan): This member is accessed via atomics, but the others are // accessed without any locking. Is this OK? std::atomic<size_t> memory_usage_; };
inlinechar* Arena::Allocate(size_t bytes){ // The semantics of what to return are a bit messy if we allow // 0-byte allocations, so we disallow them here (we don't need // them for our internal use). assert(bytes > 0); if (bytes <= alloc_bytes_remaining_) { char* result = alloc_ptr_; alloc_ptr_ += bytes; alloc_bytes_remaining_ -= bytes; return result; } returnAllocateFallback(bytes); }
例如,线程 1 和线程 2 同时调用 Allocate 函数,申请相同
bytes 大小的内存,并发进入
if (bytes <= alloc_bytes_remaining_) 分支,并同时返回了
result
指针。这样,两个线程就会持有执行同一个内存区域的指针,后续如果两个线程都对内存进行写入操作,就会导致部分写失效,发生非预期行为。
// Standard Put... routines append to a string voidPutFixed32(std::string* dst, uint32_t value); voidPutFixed64(std::string* dst, uint64_t value); voidPutVarint32(std::string* dst, uint32_t value); voidPutVarint64(std::string* dst, uint64_t value); voidPutLengthPrefixedSlice(std::string* dst, const Slice& value);
// Standard Get... routines parse a value from the beginning of a Slice // and advance the slice past the parsed value. boolGetVarint32(Slice* input, uint32_t* value); boolGetVarint64(Slice* input, uint64_t* value); boolGetLengthPrefixedSlice(Slice* input, Slice* result);
// Pointer-based variants of GetVarint... These either store a value // in *v and return a pointer just past the parsed value, or return // nullptr on error. These routines only look at bytes in the range // [p..limit-1] constchar* GetVarint32Ptr(constchar* p, constchar* limit, uint32_t* v); constchar* GetVarint64Ptr(constchar* p, constchar* limit, uint64_t* v);
// Returns the length of the varint32 or varint64 encoding of "v" intVarintLength(uint64_t v);
// Append a human-readable printout of "num" to *str voidAppendNumberTo(std::string* str, uint64_t num);
// Append a human-readable printout of "value" to *str. // Escapes any non-printable characters found in "value". voidAppendEscapedStringTo(std::string* str, const Slice& value);
// Return a human-readable printout of "num" std::string NumberToString(uint64_t num);
// Return a human-readable version of "value". // Escapes any non-printable characters found in "value". std::string EscapeString(const Slice& value);
// Parse a human-readable number from "*in" into *value. On success, // advances "*in" past the consumed number and sets "*val" to the // numeric value. Otherwise, returns false and leaves *in in an // unspecified state. boolConsumeDecimalNumber(Slice* in, uint64_t* val);
// Wraps an instance whose destructor is never called. // // This is intended for use with function-level static variables. template <typename InstanceType> classNoDestructor { public: template <typename... ConstructorArgTypes> explicitNoDestructor(ConstructorArgTypes&&... constructor_args){ static_assert(sizeof(instance_storage_) >= sizeof(InstanceType), "instance_storage_ is not large enough to hold the instance"); static_assert( alignof(decltype(instance_storage_)) >= alignof(InstanceType), "instance_storage_ does not meet the instance's alignment requirement"); new (&instance_storage_) InstanceType(std::forward<ConstructorArgTypes>(constructor_args)...); }
// A very simple random number generator. Not especially good at // generating truly random bits, but good enough for our needs in this // package. classRandom { private: uint32_t seed_;
public: explicitRandom(uint32_t s) : seed_(s & 0x7fffffffu) { // Avoid bad seeds. if (seed_ == 0 || seed_ == 2147483647L) { seed_ = 1; } } uint32_tNext(){ // 具体实现省略 } // Returns a uniformly distributed value in the range [0..n-1] // REQUIRES: n > 0 uint32_tUniform(int n){ returnNext() % n; }
// Randomly returns true ~"1/n" of the time, and false otherwise. // REQUIRES: n > 0 boolOneIn(int n){ return (Next() % n) == 0; }
// Skewed: pick "base" uniformly from range [0,max_log] and then // return "base" random bits. The effect is to pick a number in the // range [0,2^max_log-1] with exponential bias towards smaller numbers. uint32_tSkewed(int max_log){ returnUniform(1 << Uniform(max_log + 1)); } };
// A Comparator object provides a total order across slices that are // used as keys in an sstable or a database. A Comparator implementation // must be thread-safe since leveldb may invoke its methods concurrently // from multiple threads. classLEVELDB_EXPORT Comparator { public: virtual ~Comparator();
// 三路比较运算,大等小分别返回 1,0,-1 virtualintCompare(const Slice& a, const Slice& b)const= 0;
// 返回比较器名称 virtualconstchar* Name()const= 0;
// Advanced functions: these are used to reduce the space requirements // for internal data structures like index blocks.
// If *start < limit, changes *start to a short string in [start,limit). // Simple comparator implementations may return with *start unchanged, // i.e., an implementation of this method that does nothing is correct. virtualvoidFindShortestSeparator(std::string* start, const Slice& limit)const= 0;
// Changes *key to a short string >= *key. // Simple comparator implementations may return with *key unchanged, // i.e., an implementation of this method that does nothing is correct. virtualvoidFindShortSuccessor(std::string* key)const= 0; };