@ -123,8 +123,7 @@ extern ColumnFamilyOptions SanitizeOptions(const InternalKeyComparator* icmp,
class ColumnFamilySet ;
class ColumnFamilySet ;
// This class keeps all the data that a column family needs. It's mosly dumb and
// This class keeps all the data that a column family needs.
// used just to provide access to metadata.
// Most methods require DB mutex held, unless otherwise noted
// Most methods require DB mutex held, unless otherwise noted
class ColumnFamilyData {
class ColumnFamilyData {
public :
public :
@ -145,7 +144,10 @@ class ColumnFamilyData {
return - - refs_ = = 0 ;
return - - refs_ = = 0 ;
}
}
// This can only be called from single-threaded VersionSet::LogAndApply()
// SetDropped() can only be called under following conditions:
// 1) Holding a DB mutex,
// 2) from single-threaded write thread, AND
// 3) from single-threaded VersionSet::LogAndApply()
// After dropping column family no other operation on that column family
// After dropping column family no other operation on that column family
// will be executed. All the files and memory will be, however, kept around
// will be executed. All the files and memory will be, however, kept around
// until client drops the column family handle. That way, client can still
// until client drops the column family handle. That way, client can still
@ -153,17 +155,12 @@ class ColumnFamilyData {
// Column family can be dropped and still alive. In that state:
// Column family can be dropped and still alive. In that state:
// *) Column family is not included in the iteration.
// *) Column family is not included in the iteration.
// *) Compaction and flush is not executed on the dropped column family.
// *) Compaction and flush is not executed on the dropped column family.
// *) Client can continue writing and reading from column family. However, all
// *) Client can continue reading from column family. Writes will fail unless
// writes stay in the current memtable.
// WriteOptions::ignore_missing_column_families is true
// When the dropped column family is unreferenced, then we:
// When the dropped column family is unreferenced, then we:
// *) delete all memory associated with that column family
// *) delete all memory associated with that column family
// *) delete all the files associated with that column family
// *) delete all the files associated with that column family
void SetDropped ( ) {
void SetDropped ( ) ;
// can't drop default CF
assert ( id_ ! = 0 ) ;
dropped_ = true ;
write_controller_token_ . reset ( ) ;
}
bool IsDropped ( ) const { return dropped_ ; }
bool IsDropped ( ) const { return dropped_ ; }
// thread-safe
// thread-safe
@ -348,18 +345,21 @@ class ColumnFamilyData {
} ;
} ;
// ColumnFamilySet has interesting thread-safety requirements
// ColumnFamilySet has interesting thread-safety requirements
// * CreateColumnFamily() or RemoveColumnFamily() -- need to protect by DB
// * CreateColumnFamily() or RemoveColumnFamily() -- need to be protected by DB
// mutex. Inside, column_family_data_ and column_families_ will be protected
// mutex AND executed in the write thread.
// by Lock() and Unlock(). CreateColumnFamily() should ONLY be called from
// CreateColumnFamily() should ONLY be called from VersionSet::LogAndApply() AND
// VersionSet::LogAndApply() in the normal runtime. It is also called
// single-threaded write thread. It is also called during Recovery and in
// during Recovery and in DumpManifest(). RemoveColumnFamily() is called
// DumpManifest().
// from ColumnFamilyData destructor
// RemoveColumnFamily() is only called from SetDropped(). DB mutex needs to be
// held and it needs to be executed from the write thread. SetDropped() also
// guarantees that it will be called only from single-threaded LogAndApply(),
// but this condition is not that important.
// * Iteration -- hold DB mutex, but you can release it in the body of
// * Iteration -- hold DB mutex, but you can release it in the body of
// iteration. If you release DB mutex in body, reference the column
// iteration. If you release DB mutex in body, reference the column
// family before the mutex and unreference after you unlock, since the column
// family before the mutex and unreference after you unlock, since the column
// family might get dropped when the DB mutex is released
// family might get dropped when the DB mutex is released
// * GetDefault() -- thread safe
// * GetDefault() -- thread safe
// * GetColumnFamily() -- either inside of DB mutex or call Lock() <-> Unlock()
// * GetColumnFamily() -- either inside of DB mutex or from a write thread
// * GetNextColumnFamilyID(), GetMaxColumnFamily(), UpdateMaxColumnFamily(),
// * GetNextColumnFamilyID(), GetMaxColumnFamily(), UpdateMaxColumnFamily(),
// NumberOfColumnFamilies -- inside of DB mutex
// NumberOfColumnFamilies -- inside of DB mutex
class ColumnFamilySet {
class ColumnFamilySet {
@ -410,9 +410,6 @@ class ColumnFamilySet {
iterator begin ( ) { return iterator ( dummy_cfd_ - > next_ ) ; }
iterator begin ( ) { return iterator ( dummy_cfd_ - > next_ ) ; }
iterator end ( ) { return iterator ( dummy_cfd_ ) ; }
iterator end ( ) { return iterator ( dummy_cfd_ ) ; }
void Lock ( ) ;
void Unlock ( ) ;
// REQUIRES: DB mutex held
// REQUIRES: DB mutex held
// Don't call while iterating over ColumnFamilySet
// Don't call while iterating over ColumnFamilySet
void FreeDeadColumnFamilies ( ) ;
void FreeDeadColumnFamilies ( ) ;
@ -424,9 +421,12 @@ class ColumnFamilySet {
void RemoveColumnFamily ( ColumnFamilyData * cfd ) ;
void RemoveColumnFamily ( ColumnFamilyData * cfd ) ;
// column_families_ and column_family_data_ need to be protected:
// column_families_ and column_family_data_ need to be protected:
// * when mutating: 1. DB mutex locked first, 2. spinlock locked second
// * when mutating both conditions have to be satisfied:
// * when reading, either: 1. lock DB mutex, or 2. lock spinlock
// 1. DB mutex locked
// (if both, respect the ordering to avoid deadlock!)
// 2. thread currently in single-threaded write thread
// * when reading, at least one condition needs to be satisfied:
// 1. DB mutex locked
// 2. accessed from a single-threaded write thread
std : : unordered_map < std : : string , uint32_t > column_families_ ;
std : : unordered_map < std : : string , uint32_t > column_families_ ;
std : : unordered_map < uint32_t , ColumnFamilyData * > column_family_data_ ;
std : : unordered_map < uint32_t , ColumnFamilyData * > column_family_data_ ;
@ -444,7 +444,6 @@ class ColumnFamilySet {
Cache * table_cache_ ;
Cache * table_cache_ ;
WriteBuffer * write_buffer_ ;
WriteBuffer * write_buffer_ ;
WriteController * write_controller_ ;
WriteController * write_controller_ ;
std : : atomic_flag spin_lock_ ;
} ;
} ;
// We use ColumnFamilyMemTablesImpl to provide WriteBatch a way to access
// We use ColumnFamilyMemTablesImpl to provide WriteBatch a way to access
@ -459,17 +458,22 @@ class ColumnFamilyMemTablesImpl : public ColumnFamilyMemTables {
// sets current_ to ColumnFamilyData with column_family_id
// sets current_ to ColumnFamilyData with column_family_id
// returns false if column family doesn't exist
// returns false if column family doesn't exist
// REQUIRES: under a DB mutex OR from a write thread
bool Seek ( uint32_t column_family_id ) override ;
bool Seek ( uint32_t column_family_id ) override ;
// Returns log number of the selected column family
// Returns log number of the selected column family
// REQUIRES: under a DB mutex OR from a write thread
uint64_t GetLogNumber ( ) const override ;
uint64_t GetLogNumber ( ) const override ;
// REQUIRES: Seek() called first
// REQUIRES: Seek() called first
// REQUIRES: under a DB mutex OR from a write thread
virtual MemTable * GetMemTable ( ) const override ;
virtual MemTable * GetMemTable ( ) const override ;
// Returns column family handle for the selected column family
// Returns column family handle for the selected column family
// REQUIRES: under a DB mutex OR from a write thread
virtual ColumnFamilyHandle * GetColumnFamilyHandle ( ) override ;
virtual ColumnFamilyHandle * GetColumnFamilyHandle ( ) override ;
// REQUIRES: under a DB mutex OR from a write thread
virtual void CheckMemtableFull ( ) override ;
virtual void CheckMemtableFull ( ) override ;
private :
private :