structSharedSymbol{SharedSymbol(Symbolsymbol):symbol_(symbol),ref_count_(1){}Symbolsymbol_;// 记录Symbol被引用的次数,当引用次数为0的时候才会删除uint32_tref_count_;};// Bitmap implementation.// The encode map stores both the symbol and the ref count of that symbol.// Using absl::string_view lets us only store the complete string once, in the decode map.// 根据stats name查询对应的symbolusingEncodeMap=absl::flat_hash_map<absl::string_view,SharedSymbol,StringViewHash>;// 根据symbol查询对应的stats nameusingDecodeMap=absl::flat_hash_map<Symbol,InlineStringPtr>;EncodeMapencode_map_GUARDED_BY(lock_);DecodeMapdecode_map_GUARDED_BY(lock_);
voidSymbolTableImpl::addTokensToEncoding(constabsl::string_viewname,Encoding&encoding){if(name.empty()){return;}// We want to hold the lock for the minimum amount of time, so we do the// string-splitting and prepare a temp vector of Symbol first.conststd::vector<absl::string_view>tokens=absl::StrSplit(name,'.');std::vector<Symbol>symbols;symbols.reserve(tokens.size());// Now take the lock and populate the Symbol objects, which involves bumping// ref-counts in this.{Thread::LockGuardlock(lock_);for(auto&token:tokens){symbols.push_back(toSymbol(token));}}// Now efficiently encode the array of 32-bit symbols into a uint8_t array.for(Symbolsymbol:symbols){encoding.addSymbol(symbol);}}
SymbolSymbolTableImpl::toSymbol(absl::string_viewsv){Symbolresult;autoencode_find=encode_map_.find(sv);// If the string segment doesn't already exist,if(encode_find==encode_map_.end()){// We create the actual string, place it in the decode_map_, and then insert// a string_view pointing to it in the encode_map_. This allows us to only// store the string once. We use unique_ptr so copies are not made as// flat_hash_map moves values around.InlineStringPtrstr=InlineString::create(sv);autoencode_insert=encode_map_.insert({str->toStringView(),SharedSymbol(next_symbol_)});ASSERT(encode_insert.second);autodecode_insert=decode_map_.insert({next_symbol_,std::move(str)});ASSERT(decode_insert.second);result=next_symbol_;newSymbol();}else{// If the insertion didn't take place, return the actual value at that location and up the// refcount at that locationresult=encode_find->second.symbol_;++(encode_find->second.ref_count_);}returnresult;}
// pool_定义std::stack<Symbol>pool_voidSymbolTableImpl::newSymbol()EXCLUSIVE_LOCKS_REQUIRED(lock_){if(pool_.empty()){next_symbol_=++monotonic_counter_;}else{next_symbol_=pool_.top();pool_.pop();}// This should catch integer overflow for the new symbol.ASSERT(monotonic_counter_!=0);}voidSymbolTableImpl::free(constStatName&stat_name){// Before taking the lock, decode the array of symbols from the SymbolTable::Storage.constSymbolVecsymbols=Encoding::decodeSymbols(stat_name.data(),stat_name.dataSize());Thread::LockGuardlock(lock_);for(Symbolsymbol:symbols){autodecode_search=decode_map_.find(symbol);ASSERT(decode_search!=decode_map_.end());autoencode_search=encode_map_.find(decode_search->second->toStringView());ASSERT(encode_search!=encode_map_.end());// If that was the last remaining client usage of the symbol, erase the// current mappings and add the now-unused symbol to the reuse pool.//// The "if (--EXPR.ref_count_)" pattern speeds up BM_CreateRace by 20% in// symbol_table_speed_test.cc, relative to breaking out the decrement into a// separate step, likely due to the non-trivial dereferences in EXPR.if(--encode_search->second.ref_count_==0){decode_map_.erase(decode_search);encode_map_.erase(encode_search);// 回收Symbolpool_.push(symbol);}}}
staticconstuint32_tSpilloverMask=0x80;staticconstuint32_tLow7Bits=0x7f;std::vector<uint8_t>vec_;voidSymbolTableImpl::Encoding::addSymbol(Symbolsymbol){// UTF-8-like encoding where a value 127 or less gets written as a single// byte. For higher values we write the low-order 7 bits with a 1 in// the high-order bit. Then we right-shift 7 bits and keep adding more bytes// until we have consumed all the non-zero bits in symbol.//// When decoding, we stop consuming uint8_t when we see a uint8_t with// high-order bit 0.do{if(symbol<(1<<7)){vec_.push_back(symbol);// symbols <= 127 get encoded in one byte.}else{vec_.push_back((symbol&Low7Bits)|SpilloverMask);// symbols >= 128 need spillover bytes.}symbol>>=7;}while(symbol!=0);}
uint64_tSymbolTableImpl::Encoding::moveToStorage(SymbolTable::Storagesymbol_array){constuint64_tsz=dataBytesRequired();symbol_array=writeLengthReturningNext(sz,symbol_array);if(sz!=0){memcpy(symbol_array,vec_.data(),sz*sizeof(uint8_t));}vec_.clear();// Logically transfer ownership, enabling empty assert on destruct.returnsz+StatNameSizeEncodingBytes;}
std::stringSymbolTableImpl::toString(constStatName&stat_name)const{returndecodeSymbolVec(Encoding::decodeSymbols(stat_name.data(),stat_name.dataSize()));}SymbolVecSymbolTableImpl::Encoding::decodeSymbols(constSymbolTable::Storagearray,uint64_tsize){SymbolVecsymbol_vec;Symbolsymbol=0;for(uint32_tshift=0;size>0;--size,++array){uint32_tuc=static_cast<uint32_t>(*array);// Inverse addSymbol encoding, walking down the bytes, shifting them into// symbol, until a byte with a zero high order bit indicates this symbol is// complete and we can move to the next one.symbol|=(uc&Low7Bits)<<shift;if((uc&SpilloverMask)==0){symbol_vec.push_back(symbol);shift=0;symbol=0;}else{shift+=7;}}returnsymbol_vec;}