OmniSciDB  a987f07e93
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Buffer_Namespace::BufferMgr Class Referenceabstract

Note(s): Forbid Copying Idiom 4.1. More...

#include <BufferMgr.h>

+ Inheritance diagram for Buffer_Namespace::BufferMgr:
+ Collaboration diagram for Buffer_Namespace::BufferMgr:

Public Member Functions

 BufferMgr (const int device_id, const size_t max_buffer_size, const size_t min_slab_size, const size_t max_slab_size, const size_t page_size, AbstractBufferMgr *parent_mgr=0)
 Constructs a BufferMgr object that allocates memSize bytes. More...
 
 ~BufferMgr () override
 Destructor. More...
 
void reinit ()
 
std::string printSlab (size_t slab_num)
 
std::string printSlabs () override
 
void clearSlabs ()
 
std::string printMap ()
 
void printSegs ()
 
std::string printSeg (BufferList::iterator &seg_it)
 
std::string keyToString (const ChunkKey &key)
 
size_t getInUseSize () override
 
size_t getMaxSize () override
 
size_t getAllocated () override
 
size_t getMaxBufferSize ()
 
size_t getMaxSlabSize ()
 
size_t getPageSize ()
 
bool isAllocationCapped () override
 
const std::vector< BufferList > & getSlabSegments ()
 
AbstractBuffercreateBuffer (const ChunkKey &key, const size_t page_size=0, const size_t initial_size=0) override
 Creates a chunk with the specified key and page size. More...
 
void deleteBuffer (const ChunkKey &key, const bool purge=true) override
 Deletes the chunk with the specified key. More...
 
void deleteBuffersWithPrefix (const ChunkKey &key_prefix, const bool purge=true) override
 
AbstractBuffergetBuffer (const ChunkKey &key, const size_t num_bytes=0) override
 Returns the a pointer to the chunk with the specified key. More...
 
bool isBufferOnDevice (const ChunkKey &key) override
 Puts the contents of d into the Buffer with ChunkKey key. More...
 
void fetchBuffer (const ChunkKey &key, AbstractBuffer *dest_buffer, const size_t num_bytes=0) override
 
AbstractBufferputBuffer (const ChunkKey &key, AbstractBuffer *d, const size_t num_bytes=0) override
 
void checkpoint () override
 
void checkpoint (const int db_id, const int tb_id) override
 
void removeTableRelatedDS (const int db_id, const int table_id) override
 
AbstractBufferalloc (const size_t num_bytes=0) override
 client is responsible for deleting memory allocated for b->mem_ More...
 
void free (AbstractBuffer *buffer) override
 
size_t size ()
 Returns the total number of bytes allocated. More...
 
size_t getNumChunks () override
 
BufferList::iterator reserveBuffer (BufferList::iterator &seg_it, const size_t num_bytes)
 
void getChunkMetadataVecForKeyPrefix (ChunkMetadataVector &chunk_metadata_vec, const ChunkKey &key_prefix) override
 

Protected Attributes

const size_t max_buffer_pool_size_
 
const size_t min_slab_size_
 max number of bytes allocated for the buffer pool More...
 
const size_t max_slab_size_
 
const size_t page_size_
 
std::vector< int8_t * > slabs_
 
std::vector< BufferListslab_segments_
 

Private Member Functions

 BufferMgr (const BufferMgr &)
 
BufferMgroperator= (const BufferMgr &)
 
void removeSegment (BufferList::iterator &seg_it)
 
BufferList::iterator findFreeBufferInSlab (const size_t slab_num, const size_t num_pages_requested)
 
int getBufferId ()
 
virtual void addSlab (const size_t slab_size)=0
 
virtual void freeAllMem ()=0
 
virtual void allocateBuffer (BufferList::iterator seg_it, const size_t page_size, const size_t num_bytes)=0
 
void clear ()
 
BufferList::iterator evict (BufferList::iterator &evict_start, const size_t num_pages_requested, const int slab_num)
 
BufferList::iterator findFreeBuffer (size_t num_bytes)
 Gets a buffer of required size and returns an iterator to it. More...
 

Private Attributes

std::mutex chunk_index_mutex_
 
std::mutex sized_segs_mutex_
 
std::mutex unsized_segs_mutex_
 
std::mutex buffer_id_mutex_
 
std::mutex global_mutex_
 
std::map< ChunkKey,
BufferList::iterator > 
chunk_index_
 
size_t max_buffer_pool_num_pages_
 
size_t num_pages_allocated_
 
size_t min_num_pages_per_slab_
 
size_t max_num_pages_per_slab_
 
size_t current_max_slab_page_size_
 
bool allocations_capped_
 
AbstractBufferMgrparent_mgr_
 
int max_buffer_id_
 
unsigned int buffer_epoch_
 
BufferList unsized_segs_
 

Detailed Description

Note(s): Forbid Copying Idiom 4.1.

Definition at line 96 of file BufferMgr.h.

Constructor & Destructor Documentation

Buffer_Namespace::BufferMgr::BufferMgr ( const int  device_id,
const size_t  max_buffer_size,
const size_t  min_slab_size,
const size_t  max_slab_size,
const size_t  page_size,
AbstractBufferMgr parent_mgr = 0 
)

Constructs a BufferMgr object that allocates memSize bytes.

Allocates memSize bytes for the buffer pool and initializes the free memory map.

Definition at line 47 of file BufferMgr.cpp.

References CHECK, current_max_slab_page_size_, max_buffer_pool_num_pages_, max_buffer_pool_size_, max_num_pages_per_slab_, max_slab_size_, min_num_pages_per_slab_, min_slab_size_, and page_size_.

53  : AbstractBufferMgr(device_id)
54  , max_buffer_pool_size_(max_buffer_pool_size)
55  , min_slab_size_(min_slab_size)
56  , max_slab_size_(max_slab_size)
57  , page_size_(page_size)
59  , allocations_capped_(false)
60  , parent_mgr_(parent_mgr)
61  , max_buffer_id_(0)
62  , buffer_epoch_(0) {
64  CHECK(page_size_ > 0);
65  // TODO change checks on run-time configurable slab size variables to exceptions
66  CHECK(min_slab_size_ > 0);
67  CHECK(max_slab_size_ > 0);
71 
76  max_num_pages_per_slab_; // current_max_slab_page_size_ will drop as allocations
77  // fail - this is the high water mark
78 }
AbstractBufferMgr * parent_mgr_
Definition: BufferMgr.h:210
const size_t max_buffer_pool_size_
Definition: BufferMgr.h:173
unsigned int buffer_epoch_
Definition: BufferMgr.h:212
const size_t min_slab_size_
max number of bytes allocated for the buffer pool
Definition: BufferMgr.h:174
#define CHECK(condition)
Definition: Logger.h:289
const size_t max_slab_size_
Definition: BufferMgr.h:176
Buffer_Namespace::BufferMgr::~BufferMgr ( )
override

Destructor.

Frees the heap-allocated buffer pool memory.

Definition at line 81 of file BufferMgr.cpp.

References clear().

81  {
82  clear();
83 }

+ Here is the call graph for this function:

Buffer_Namespace::BufferMgr::BufferMgr ( const BufferMgr )
private

Member Function Documentation

virtual void Buffer_Namespace::BufferMgr::addSlab ( const size_t  slab_size)
privatepure virtual

Implemented in Buffer_Namespace::TieredCpuBufferMgr, Buffer_Namespace::CpuBufferMgr, and Buffer_Namespace::GpuCudaBufferMgr.

Referenced by findFreeBuffer().

+ Here is the caller graph for this function:

AbstractBuffer * Buffer_Namespace::BufferMgr::alloc ( const size_t  num_bytes = 0)
override

client is responsible for deleting memory allocated for b->mem_

Definition at line 859 of file BufferMgr.cpp.

References createBuffer(), getBufferId(), global_mutex_, and page_size_.

859  {
860  std::lock_guard<std::mutex> lock(global_mutex_);
861  ChunkKey chunk_key = {-1, getBufferId()};
862  return createBuffer(chunk_key, page_size_, num_bytes);
863 }
std::vector< int > ChunkKey
Definition: types.h:36
AbstractBuffer * createBuffer(const ChunkKey &key, const size_t page_size=0, const size_t initial_size=0) override
Creates a chunk with the specified key and page size.
Definition: BufferMgr.cpp:110

+ Here is the call graph for this function:

virtual void Buffer_Namespace::BufferMgr::allocateBuffer ( BufferList::iterator  seg_it,
const size_t  page_size,
const size_t  num_bytes 
)
privatepure virtual

Implemented in Buffer_Namespace::CpuBufferMgr, and Buffer_Namespace::GpuCudaBufferMgr.

Referenced by createBuffer().

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::checkpoint ( )
override

Definition at line 681 of file BufferMgr.cpp.

References chunk_index_, chunk_index_mutex_, global_mutex_, and parent_mgr_.

681  {
682  std::lock_guard<std::mutex> lock(global_mutex_); // granular lock
683  std::lock_guard<std::mutex> chunkIndexLock(chunk_index_mutex_);
684 
685  for (auto& chunk_itr : chunk_index_) {
686  // checks that buffer is actual chunk (not just buffer) and is dirty
687  auto& buffer_itr = chunk_itr.second;
688  if (buffer_itr->chunk_key[0] != -1 && buffer_itr->buffer->isDirty()) {
689  parent_mgr_->putBuffer(buffer_itr->chunk_key, buffer_itr->buffer);
690  buffer_itr->buffer->clearDirtyBits();
691  }
692  }
693 }
AbstractBufferMgr * parent_mgr_
Definition: BufferMgr.h:210
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
void Buffer_Namespace::BufferMgr::checkpoint ( const int  db_id,
const int  tb_id 
)
override

Definition at line 695 of file BufferMgr.cpp.

References chunk_index_, chunk_index_mutex_, global_mutex_, and parent_mgr_.

695  {
696  std::lock_guard<std::mutex> lock(global_mutex_); // granular lock
697  std::lock_guard<std::mutex> chunk_index_lock(chunk_index_mutex_);
698 
699  ChunkKey key_prefix;
700  key_prefix.push_back(db_id);
701  key_prefix.push_back(tb_id);
702  auto start_chunk_it = chunk_index_.lower_bound(key_prefix);
703  if (start_chunk_it == chunk_index_.end()) {
704  return;
705  }
706 
707  auto buffer_it = start_chunk_it;
708  while (buffer_it != chunk_index_.end() &&
709  std::search(buffer_it->first.begin(),
710  buffer_it->first.begin() + key_prefix.size(),
711  key_prefix.begin(),
712  key_prefix.end()) != buffer_it->first.begin() + key_prefix.size()) {
713  if (buffer_it->second->chunk_key[0] != -1 &&
714  buffer_it->second->buffer->isDirty()) { // checks that buffer is actual chunk
715  // (not just buffer) and is dirty
716 
717  parent_mgr_->putBuffer(buffer_it->second->chunk_key, buffer_it->second->buffer);
718  buffer_it->second->buffer->clearDirtyBits();
719  }
720  buffer_it++;
721  }
722 }
AbstractBufferMgr * parent_mgr_
Definition: BufferMgr.h:210
std::vector< int > ChunkKey
Definition: types.h:36
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
void Buffer_Namespace::BufferMgr::clear ( )
private

Definition at line 93 of file BufferMgr.cpp.

References buffer_epoch_, chunk_index_, chunk_index_mutex_, sized_segs_mutex_, slab_segments_, slabs_, unsized_segs_, and unsized_segs_mutex_.

Referenced by clearSlabs(), and ~BufferMgr().

93  {
94  std::lock_guard<std::mutex> sized_segs_lock(sized_segs_mutex_);
95  std::lock_guard<std::mutex> chunk_index_lock(chunk_index_mutex_);
96  std::lock_guard<std::mutex> unsized_segs_lock(unsized_segs_mutex_);
97 
98  for (auto& buf : chunk_index_) {
99  delete buf.second->buffer;
100  }
101 
102  chunk_index_.clear();
103  slabs_.clear();
104  slab_segments_.clear();
105  unsized_segs_.clear();
106  buffer_epoch_ = 0;
107 }
unsigned int buffer_epoch_
Definition: BufferMgr.h:212
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
std::mutex unsized_segs_mutex_
Definition: BufferMgr.h:199
std::vector< int8_t * > slabs_
Definition: BufferMgr.h:179

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::clearSlabs ( )

Definition at line 472 of file BufferMgr.cpp.

References clear(), deleteBuffer(), Buffer_Namespace::FREE, freeAllMem(), reinit(), and slab_segments_.

472  {
473  bool pinned_exists = false;
474  for (auto& segment_list : slab_segments_) {
475  for (auto& segment : segment_list) {
476  if (segment.mem_status == FREE) {
477  // no need to free
478  } else if (segment.buffer->getPinCount() < 1) {
479  deleteBuffer(segment.chunk_key, true);
480  } else {
481  pinned_exists = true;
482  }
483  }
484  }
485  if (!pinned_exists) {
486  // lets actually clear the buffer from memory
487  freeAllMem();
488  clear();
489  reinit();
490  }
491 }
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
void deleteBuffer(const ChunkKey &key, const bool purge=true) override
Deletes the chunk with the specified key.
Definition: BufferMgr.cpp:597
virtual void freeAllMem()=0

+ Here is the call graph for this function:

AbstractBuffer * Buffer_Namespace::BufferMgr::createBuffer ( const ChunkKey key,
const size_t  page_size = 0,
const size_t  initial_size = 0 
)
override

Creates a chunk with the specified key and page size.

Throws a runtime_error if the Chunk already exists.

Definition at line 110 of file BufferMgr.cpp.

References allocateBuffer(), CHECK, chunk_index_, chunk_index_mutex_, deleteBuffer(), page_size_, unsized_segs_, unsized_segs_mutex_, and Buffer_Namespace::USED.

Referenced by alloc(), fetchBuffer(), getBuffer(), and putBuffer().

112  {
113  // LOG(INFO) << printMap();
114  size_t actual_chunk_page_size = chunk_page_size;
115  if (actual_chunk_page_size == 0) {
116  actual_chunk_page_size = page_size_;
117  }
118 
119  // chunk_page_size is just for recording dirty pages
120  {
121  std::lock_guard<std::mutex> lock(chunk_index_mutex_);
122  CHECK(chunk_index_.find(chunk_key) == chunk_index_.end());
123  BufferSeg buffer_seg(BufferSeg(-1, 0, USED));
124  buffer_seg.chunk_key = chunk_key;
125  std::lock_guard<std::mutex> unsizedSegsLock(unsized_segs_mutex_);
126  unsized_segs_.push_back(buffer_seg); // race condition?
127  chunk_index_[chunk_key] =
128  std::prev(unsized_segs_.end(),
129  1); // need to do this before allocating Buffer because doing so could
130  // change the segment used
131  }
132  // following should be safe outside the lock b/c first thing Buffer
133  // constructor does is pin (and its still in unsized segs at this point
134  // so can't be evicted)
135  try {
136  allocateBuffer(chunk_index_[chunk_key], actual_chunk_page_size, initial_size);
137  } catch (const OutOfMemory&) {
138  auto buffer_it = chunk_index_.find(chunk_key);
139  CHECK(buffer_it != chunk_index_.end());
140  buffer_it->second->buffer =
141  nullptr; // constructor failed for the buffer object so make sure to mark it null
142  // so deleteBuffer doesn't try to delete it
143  deleteBuffer(chunk_key);
144  throw;
145  }
146  CHECK(initial_size == 0 || chunk_index_[chunk_key]->buffer->getMemoryPtr());
147  // chunk_index_[chunk_key]->buffer->pin();
148  std::lock_guard<std::mutex> lock(chunk_index_mutex_);
149  return chunk_index_[chunk_key]->buffer;
150 }
virtual void allocateBuffer(BufferList::iterator seg_it, const size_t page_size, const size_t num_bytes)=0
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
std::mutex unsized_segs_mutex_
Definition: BufferMgr.h:199
#define CHECK(condition)
Definition: Logger.h:289
void deleteBuffer(const ChunkKey &key, const bool purge=true) override
Deletes the chunk with the specified key.
Definition: BufferMgr.cpp:597

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::deleteBuffer ( const ChunkKey key,
const bool  purge = true 
)
override

Deletes the chunk with the specified key.

This method throws a runtime_error when deleting a Chunk that does not exist.

Definition at line 597 of file BufferMgr.cpp.

References CHECK, chunk_index_, chunk_index_mutex_, removeSegment(), and sized_segs_mutex_.

Referenced by clearSlabs(), createBuffer(), fetchBuffer(), free(), and getBuffer().

597  {
598  // Note: purge is unused
599  std::unique_lock<std::mutex> chunk_index_lock(chunk_index_mutex_);
600 
601  // lookup the buffer for the Chunk in chunk_index_
602  auto buffer_it = chunk_index_.find(key);
603  CHECK(buffer_it != chunk_index_.end());
604  auto seg_it = buffer_it->second;
605  chunk_index_.erase(buffer_it);
606  chunk_index_lock.unlock();
607  std::lock_guard<std::mutex> sized_segs_lock(sized_segs_mutex_);
608  if (seg_it->buffer) {
609  delete seg_it->buffer; // Delete Buffer for segment
610  seg_it->buffer = 0;
611  }
612  removeSegment(seg_it);
613 }
void removeSegment(BufferList::iterator &seg_it)
Definition: BufferMgr.cpp:650
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
#define CHECK(condition)
Definition: Logger.h:289

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::deleteBuffersWithPrefix ( const ChunkKey key_prefix,
const bool  purge = true 
)
override

Definition at line 615 of file BufferMgr.cpp.

References chunk_index_, chunk_index_mutex_, removeSegment(), and sized_segs_mutex_.

615  {
616  // Note: purge is unused
617  // lookup the buffer for the Chunk in chunk_index_
618  std::lock_guard<std::mutex> sized_segs_lock(
619  sized_segs_mutex_); // Take this lock early to prevent deadlock with
620  // reserveBuffer which needs segs_mutex_ and then
621  // chunk_index_mutex_
622  std::lock_guard<std::mutex> chunk_index_lock(chunk_index_mutex_);
623  auto startChunkIt = chunk_index_.lower_bound(key_prefix);
624  if (startChunkIt == chunk_index_.end()) {
625  return;
626  }
627 
628  auto buffer_it = startChunkIt;
629  while (buffer_it != chunk_index_.end() &&
630  std::search(buffer_it->first.begin(),
631  buffer_it->first.begin() + key_prefix.size(),
632  key_prefix.begin(),
633  key_prefix.end()) != buffer_it->first.begin() + key_prefix.size()) {
634  auto seg_it = buffer_it->second;
635  if (seg_it->buffer) {
636  if (seg_it->buffer->getPinCount() != 0) {
637  // leave the buffer and buffer segment in place, they are in use elsewhere. once
638  // unpinned, the buffer will be inaccessible and evicted
639  buffer_it++;
640  continue;
641  }
642  delete seg_it->buffer; // Delete Buffer for segment
643  seg_it->buffer = nullptr;
644  }
645  removeSegment(seg_it);
646  chunk_index_.erase(buffer_it++);
647  }
648 }
void removeSegment(BufferList::iterator &seg_it)
Definition: BufferMgr.cpp:650
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203

+ Here is the call graph for this function:

BufferList::iterator Buffer_Namespace::BufferMgr::evict ( BufferList::iterator &  evict_start,
const size_t  num_pages_requested,
const int  slab_num 
)
private

Definition at line 152 of file BufferMgr.cpp.

References buffer_epoch_, CHECK, chunk_index_, Buffer_Namespace::FREE, Buffer_Namespace::BufferSeg::slab_num, slab_segments_, and Buffer_Namespace::USED.

Referenced by findFreeBuffer().

154  {
155  // We can assume here that buffer for evictStart either doesn't exist
156  // (evictStart is first buffer) or was not free, so don't need ot merge
157  // it
158  auto evict_it = evict_start;
159  size_t num_pages = 0;
160  size_t start_page = evict_start->start_page;
161  while (num_pages < num_pages_requested) {
162  if (evict_it->mem_status == USED) {
163  CHECK(evict_it->buffer->getPinCount() < 1);
164  }
165  num_pages += evict_it->num_pages;
166  if (evict_it->mem_status == USED && evict_it->chunk_key.size() > 0) {
167  chunk_index_.erase(evict_it->chunk_key);
168  }
169  if (evict_it->buffer != nullptr) {
170  // If we don't delete buffers here then we lose reference to them later and cause a
171  // memleak.
172  delete evict_it->buffer;
173  }
174  evict_it = slab_segments_[slab_num].erase(
175  evict_it); // erase operations returns next iterator - safe if we ever move
176  // to a vector (as opposed to erase(evict_it++)
177  }
178  BufferSeg data_seg(
179  start_page, num_pages_requested, USED, buffer_epoch_++); // until we can
180  // data_seg.pinCount++;
181  data_seg.slab_num = slab_num;
182  auto data_seg_it =
183  slab_segments_[slab_num].insert(evict_it, data_seg); // Will insert before evict_it
184  if (num_pages_requested < num_pages) {
185  size_t excess_pages = num_pages - num_pages_requested;
186  if (evict_it != slab_segments_[slab_num].end() &&
187  evict_it->mem_status == FREE) { // need to merge with current page
188  evict_it->start_page = start_page + num_pages_requested;
189  evict_it->num_pages += excess_pages;
190  } else { // need to insert a free seg before evict_it for excess_pages
191  BufferSeg free_seg(start_page + num_pages_requested, excess_pages, FREE);
192  slab_segments_[slab_num].insert(evict_it, free_seg);
193  }
194  }
195  return data_seg_it;
196 }
unsigned int buffer_epoch_
Definition: BufferMgr.h:212
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
#define CHECK(condition)
Definition: Logger.h:289

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::fetchBuffer ( const ChunkKey key,
AbstractBuffer dest_buffer,
const size_t  num_bytes = 0 
)
override

Definition at line 766 of file BufferMgr.cpp.

References CHECK, chunk_index_, chunk_index_mutex_, Data_Namespace::AbstractBuffer::copyTo(), createBuffer(), deleteBuffer(), logger::FATAL, global_mutex_, keyToString(), LOG, page_size_, parent_mgr_, Data_Namespace::AbstractBuffer::pin(), Data_Namespace::AbstractBuffer::size(), sized_segs_mutex_, Data_Namespace::AbstractBuffer::unPin(), and logger::WARNING.

768  {
769  std::unique_lock<std::mutex> lock(global_mutex_); // granular lock
770  std::unique_lock<std::mutex> sized_segs_lock(sized_segs_mutex_);
771  std::unique_lock<std::mutex> chunk_index_lock(chunk_index_mutex_);
772 
773  auto buffer_it = chunk_index_.find(key);
774  bool found_buffer = buffer_it != chunk_index_.end();
775  chunk_index_lock.unlock();
776  AbstractBuffer* buffer;
777  if (!found_buffer) {
778  sized_segs_lock.unlock();
779  CHECK(parent_mgr_ != 0);
780  buffer = createBuffer(key, page_size_, num_bytes); // will pin buffer
781  try {
782  parent_mgr_->fetchBuffer(key, buffer, num_bytes);
783  } catch (const foreign_storage::ForeignStorageException& error) {
784  deleteBuffer(key); // buffer failed to load, ensure it is cleaned up
785  LOG(WARNING) << "Could not fetch parent chunk " << keyToString(key)
786  << " from foreign storage. Error was " << error.what();
787  throw error;
788  } catch (std::runtime_error& error) {
789  LOG(FATAL) << "Could not fetch parent buffer " << keyToString(key)
790  << " error: " << error.what();
791  }
792  } else {
793  buffer = buffer_it->second->buffer;
794  buffer->pin();
795  if (num_bytes > buffer->size()) {
796  try {
797  parent_mgr_->fetchBuffer(key, buffer, num_bytes);
798  } catch (const foreign_storage::ForeignStorageException& error) {
799  LOG(WARNING) << "Could not fetch parent chunk " << keyToString(key)
800  << " from foreign storage. Error was " << error.what();
801  throw error;
802  } catch (std::runtime_error& error) {
803  LOG(FATAL) << "Could not fetch parent buffer " << keyToString(key)
804  << " error: " << error.what();
805  }
806  }
807  sized_segs_lock.unlock();
808  }
809  lock.unlock();
810  buffer->copyTo(dest_buffer, num_bytes);
811  buffer->unPin();
812 }
AbstractBufferMgr * parent_mgr_
Definition: BufferMgr.h:210
AbstractBuffer * createBuffer(const ChunkKey &key, const size_t page_size=0, const size_t initial_size=0) override
Creates a chunk with the specified key and page size.
Definition: BufferMgr.cpp:110
#define LOG(tag)
Definition: Logger.h:283
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
An AbstractBuffer is a unit of data management for a data manager.
void copyTo(AbstractBuffer *destination_buffer, const size_t num_bytes=0)
#define CHECK(condition)
Definition: Logger.h:289
std::string keyToString(const ChunkKey &key)
Definition: BufferMgr.cpp:36
void deleteBuffer(const ChunkKey &key, const bool purge=true) override
Deletes the chunk with the specified key.
Definition: BufferMgr.cpp:597

+ Here is the call graph for this function:

BufferList::iterator Buffer_Namespace::BufferMgr::findFreeBuffer ( size_t  num_bytes)
private

Gets a buffer of required size and returns an iterator to it.

If possible, this function will just select a free buffer of sufficient size and use that. If not, it will evict as many non-pinned but used buffers as needed to have enough space for the buffer

Returns
An iterator to the reserved buffer. We guarantee that this buffer won't be evicted by PINNING it - caller should change this to USED if applicable

Definition at line 281 of file BufferMgr.cpp.

References addSlab(), allocations_capped_, current_max_slab_page_size_, logger::ERROR, evict(), measure< TimeT >::execution(), findFreeBufferInSlab(), logger::INFO, LOG, max_buffer_pool_num_pages_, max_num_pages_per_slab_, min_num_pages_per_slab_, num_pages_allocated_, page_size_, printSlabs(), slab_segments_, Buffer_Namespace::USED, and VLOG.

Referenced by reserveBuffer().

281  {
282  size_t num_pages_requested = (num_bytes + page_size_ - 1) / page_size_;
283  if (num_pages_requested > max_num_pages_per_slab_) {
284  throw TooBigForSlab(num_bytes);
285  }
286 
287  size_t num_slabs = slab_segments_.size();
288 
289  for (size_t slab_num = 0; slab_num != num_slabs; ++slab_num) {
290  auto seg_it = findFreeBufferInSlab(slab_num, num_pages_requested);
291  if (seg_it != slab_segments_[slab_num].end()) {
292  return seg_it;
293  }
294  }
295 
296  // If we're here then we didn't find a free segment of sufficient size
297  // First we see if we can add another slab
299  try {
301  if (pagesLeft < current_max_slab_page_size_) {
302  current_max_slab_page_size_ = pagesLeft;
303  }
304  if (num_pages_requested <=
305  current_max_slab_page_size_) { // don't try to allocate if the
306  // new slab won't be big enough
307  auto alloc_ms = measure<>::execution(
309  LOG(INFO) << "ALLOCATION slab of " << current_max_slab_page_size_ << " pages ("
310  << current_max_slab_page_size_ * page_size_ << "B) created in "
311  << alloc_ms << " ms " << getStringMgrType() << ":" << device_id_;
312  } else {
313  break;
314  }
315  // if here then addSlab succeeded
316  num_pages_allocated_ += current_max_slab_page_size_;
317  return findFreeBufferInSlab(
318  num_slabs,
319  num_pages_requested); // has to succeed since we made sure to request a slab
320  // big enough to accomodate request
321  } catch (std::runtime_error& error) { // failed to allocate slab
322  LOG(INFO) << "ALLOCATION Attempted slab of " << current_max_slab_page_size_
323  << " pages (" << current_max_slab_page_size_ * page_size_ << "B) failed "
324  << getStringMgrType() << ":" << device_id_;
325  // check if there is any point halving currentMaxSlabSize and trying again
326  // if the request wont fit in half available then let try once at full size
327  // if we have already tries at full size and failed then break as
328  // there could still be room enough for other later request but
329  // not for his current one
330  if (num_pages_requested > current_max_slab_page_size_ / 2 &&
331  current_max_slab_page_size_ != num_pages_requested) {
332  current_max_slab_page_size_ = num_pages_requested;
333  } else {
336  (min_num_pages_per_slab_)) { // should be a constant
337  allocations_capped_ = true;
338  // dump out the slabs and their sizes
339  LOG(INFO) << "ALLOCATION Capped " << current_max_slab_page_size_
340  << " Minimum size = " << (min_num_pages_per_slab_) << " "
341  << getStringMgrType() << ":" << device_id_;
342  }
343  }
344  }
345  }
346 
347  if (num_pages_allocated_ == 0 && allocations_capped_) {
348  throw FailedToCreateFirstSlab(num_bytes);
349  }
350 
351  // If here then we can't add a slab - so we need to evict
352 
353  size_t min_score = std::numeric_limits<size_t>::max();
354  // We're going for lowest score here, like golf
355  // This is because score is the sum of the lastTouched score for all pages evicted.
356  // Evicting fewer pages and older pages will lower the score
357  BufferList::iterator best_eviction_start = slab_segments_[0].end();
358  int best_eviction_start_slab = -1;
359  int slab_num = 0;
360 
361  for (auto slab_it = slab_segments_.begin(); slab_it != slab_segments_.end();
362  ++slab_it, ++slab_num) {
363  for (auto buffer_it = slab_it->begin(); buffer_it != slab_it->end(); ++buffer_it) {
364  // Note there are some shortcuts we could take here - like we should never consider
365  // a USED buffer coming after a free buffer as we would have used the FREE buffer,
366  // but we won't worry about this for now
367 
368  // We can't evict pinned buffers - only normal usedbuffers
369 
370  // if (buffer_it->mem_status == FREE || buffer_it->buffer->getPinCount() == 0) {
371  size_t page_count = 0;
372  size_t score = 0;
373  bool solution_found = false;
374  auto evict_it = buffer_it;
375  for (; evict_it != slab_segments_[slab_num].end(); ++evict_it) {
376  // pinCount should never go up - only down because we have
377  // global lock on buffer pool and pin count only increments
378  // on getChunk
379  if (evict_it->mem_status == USED && evict_it->buffer->getPinCount() > 0) {
380  break;
381  }
382  page_count += evict_it->num_pages;
383  if (evict_it->mem_status == USED) {
384  // MAT changed from
385  // score += evictIt->lastTouched;
386  // Issue was thrashing when going from 8M fragment size chunks back to 64M
387  // basically the large chunks were being evicted prior to small as many small
388  // chunk score was larger than one large chunk so it always would evict a large
389  // chunk so under memory pressure a query would evict its own current chunks and
390  // cause reloads rather than evict several smaller unused older chunks.
391  score = std::max(score, static_cast<size_t>(evict_it->last_touched));
392  }
393  if (page_count >= num_pages_requested) {
394  solution_found = true;
395  break;
396  }
397  }
398  if (solution_found && score < min_score) {
399  min_score = score;
400  best_eviction_start = buffer_it;
401  best_eviction_start_slab = slab_num;
402  } else if (evict_it == slab_segments_[slab_num].end()) {
403  // this means that every segment after this will fail as well, so our search has
404  // proven futile
405  // throw std::runtime_error ("Couldn't evict chunks to get free space");
406  break;
407  // in reality we should try to rearrange the buffer to get more contiguous free
408  // space
409  }
410  // other possibility is ending at PINNED - do nothing in this case
411  //}
412  }
413  }
414  if (best_eviction_start == slab_segments_[0].end()) {
415  LOG(ERROR) << "ALLOCATION failed to find " << num_bytes << "B throwing out of memory "
416  << getStringMgrType() << ":" << device_id_;
417  VLOG(2) << printSlabs();
418  throw OutOfMemory(num_bytes);
419  }
420  LOG(INFO) << "ALLOCATION failed to find " << num_bytes << "B free. Forcing Eviction."
421  << " Eviction start " << best_eviction_start->start_page
422  << " Number pages requested " << num_pages_requested
423  << " Best Eviction Start Slab " << best_eviction_start_slab << " "
424  << getStringMgrType() << ":" << device_id_;
425  best_eviction_start =
426  evict(best_eviction_start, num_pages_requested, best_eviction_start_slab);
427  return best_eviction_start;
428 }
static TimeT::rep execution(F func, Args &&...args)
Definition: sample.cpp:29
#define LOG(tag)
Definition: Logger.h:283
virtual void addSlab(const size_t slab_size)=0
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
BufferList::iterator findFreeBufferInSlab(const size_t slab_num, const size_t num_pages_requested)
Definition: BufferMgr.cpp:253
std::string printSlabs() override
Definition: BufferMgr.cpp:459
BufferList::iterator evict(BufferList::iterator &evict_start, const size_t num_pages_requested, const int slab_num)
Definition: BufferMgr.cpp:152
#define VLOG(n)
Definition: Logger.h:383

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

BufferList::iterator Buffer_Namespace::BufferMgr::findFreeBufferInSlab ( const size_t  slab_num,
const size_t  num_pages_requested 
)
private

Definition at line 253 of file BufferMgr.cpp.

References buffer_epoch_, Buffer_Namespace::FREE, slab_segments_, and Buffer_Namespace::USED.

Referenced by findFreeBuffer().

254  {
255  for (auto buffer_it = slab_segments_[slab_num].begin();
256  buffer_it != slab_segments_[slab_num].end();
257  ++buffer_it) {
258  if (buffer_it->mem_status == FREE && buffer_it->num_pages >= num_pages_requested) {
259  // startPage doesn't change
260  size_t excess_pages = buffer_it->num_pages - num_pages_requested;
261  buffer_it->num_pages = num_pages_requested;
262  buffer_it->mem_status = USED;
263  buffer_it->last_touched = buffer_epoch_++;
264  buffer_it->slab_num = slab_num;
265  if (excess_pages > 0) {
266  BufferSeg free_seg(
267  buffer_it->start_page + num_pages_requested, excess_pages, FREE);
268  auto temp_it = buffer_it; // this should make a copy and not be a reference
269  // - as we do not want to increment buffer_it
270  temp_it++;
271  slab_segments_[slab_num].insert(temp_it, free_seg);
272  }
273  return buffer_it;
274  }
275  }
276  // If here then we did not find a free buffer of sufficient size in this slab,
277  // return the end iterator
278  return slab_segments_[slab_num].end();
279 }
unsigned int buffer_epoch_
Definition: BufferMgr.h:212
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::free ( AbstractBuffer buffer)
override

Definition at line 865 of file BufferMgr.cpp.

References deleteBuffer(), logger::FATAL, global_mutex_, LOG, and Buffer_Namespace::Buffer::seg_it_.

865  {
866  std::lock_guard<std::mutex> lock(global_mutex_); // hack for now
867  Buffer* casted_buffer = dynamic_cast<Buffer*>(buffer);
868  if (casted_buffer == 0) {
869  LOG(FATAL) << "Wrong buffer type - expects base class pointer to Buffer type.";
870  }
871  deleteBuffer(casted_buffer->seg_it_->chunk_key);
872 }
#define LOG(tag)
Definition: Logger.h:283
void deleteBuffer(const ChunkKey &key, const bool purge=true) override
Deletes the chunk with the specified key.
Definition: BufferMgr.cpp:597

+ Here is the call graph for this function:

virtual void Buffer_Namespace::BufferMgr::freeAllMem ( )
privatepure virtual

Implemented in Buffer_Namespace::TieredCpuBufferMgr, Buffer_Namespace::CpuBufferMgr, and Buffer_Namespace::GpuCudaBufferMgr.

Referenced by clearSlabs().

+ Here is the caller graph for this function:

size_t Buffer_Namespace::BufferMgr::getAllocated ( )
override

Definition at line 499 of file BufferMgr.cpp.

References num_pages_allocated_, and page_size_.

Referenced by Data_Namespace::DataMgr::getMemoryInfoUnlocked().

499  {
501 }

+ Here is the caller graph for this function:

AbstractBuffer * Buffer_Namespace::BufferMgr::getBuffer ( const ChunkKey key,
const size_t  num_bytes = 0 
)
override

Returns the a pointer to the chunk with the specified key.

Returns a pointer to the Buffer holding the chunk, if it exists; otherwise, throws a runtime_error.

Definition at line 726 of file BufferMgr.cpp.

References buffer_epoch_, CHECK, chunk_index_, chunk_index_mutex_, createBuffer(), deleteBuffer(), logger::FATAL, global_mutex_, keyToString(), LOG, page_size_, parent_mgr_, sized_segs_mutex_, and logger::WARNING.

726  {
727  std::lock_guard<std::mutex> lock(global_mutex_); // granular lock
728 
729  std::unique_lock<std::mutex> sized_segs_lock(sized_segs_mutex_);
730  std::unique_lock<std::mutex> chunk_index_lock(chunk_index_mutex_);
731  auto buffer_it = chunk_index_.find(key);
732  bool found_buffer = buffer_it != chunk_index_.end();
733  chunk_index_lock.unlock();
734  if (found_buffer) {
735  CHECK(buffer_it->second->buffer);
736  buffer_it->second->buffer->pin();
737  sized_segs_lock.unlock();
738 
739  buffer_it->second->last_touched = buffer_epoch_++; // race
740 
741  if (buffer_it->second->buffer->size() < num_bytes) {
742  // need to fetch part of buffer we don't have - up to numBytes
743  parent_mgr_->fetchBuffer(key, buffer_it->second->buffer, num_bytes);
744  }
745  return buffer_it->second->buffer;
746  } else { // If wasn't in pool then we need to fetch it
747  sized_segs_lock.unlock();
748  // createChunk pins for us
749  AbstractBuffer* buffer = createBuffer(key, page_size_, num_bytes);
750  try {
751  parent_mgr_->fetchBuffer(
752  key, buffer, num_bytes); // this should put buffer in a BufferSegment
753  } catch (const foreign_storage::ForeignStorageException& error) {
754  deleteBuffer(key); // buffer failed to load, ensure it is cleaned up
755  LOG(WARNING) << "Get chunk - Could not load chunk " << keyToString(key)
756  << " from foreign storage. Error was " << error.what();
757  throw error;
758  } catch (const std::exception& error) {
759  LOG(FATAL) << "Get chunk - Could not find chunk " << keyToString(key)
760  << " in buffer pool or parent buffer pools. Error was " << error.what();
761  }
762  return buffer;
763  }
764 }
AbstractBufferMgr * parent_mgr_
Definition: BufferMgr.h:210
AbstractBuffer * createBuffer(const ChunkKey &key, const size_t page_size=0, const size_t initial_size=0) override
Creates a chunk with the specified key and page size.
Definition: BufferMgr.cpp:110
#define LOG(tag)
Definition: Logger.h:283
unsigned int buffer_epoch_
Definition: BufferMgr.h:212
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
An AbstractBuffer is a unit of data management for a data manager.
#define CHECK(condition)
Definition: Logger.h:289
std::string keyToString(const ChunkKey &key)
Definition: BufferMgr.cpp:36
void deleteBuffer(const ChunkKey &key, const bool purge=true) override
Deletes the chunk with the specified key.
Definition: BufferMgr.cpp:597

+ Here is the call graph for this function:

int Buffer_Namespace::BufferMgr::getBufferId ( )
private

Definition at line 853 of file BufferMgr.cpp.

References buffer_id_mutex_, and max_buffer_id_.

Referenced by alloc().

853  {
854  std::lock_guard<std::mutex> lock(buffer_id_mutex_);
855  return max_buffer_id_++;
856 }

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::getChunkMetadataVecForKeyPrefix ( ChunkMetadataVector chunk_metadata_vec,
const ChunkKey key_prefix 
)
override

Definition at line 891 of file BufferMgr.cpp.

References logger::FATAL, and LOG.

892  {
893  LOG(FATAL) << "getChunkMetadataVecForPrefix not supported for BufferMgr.";
894 }
#define LOG(tag)
Definition: Logger.h:283
size_t Buffer_Namespace::BufferMgr::getInUseSize ( )
override

Definition at line 513 of file BufferMgr.cpp.

References Buffer_Namespace::FREE, page_size_, and slab_segments_.

513  {
514  size_t in_use = 0;
515  for (auto& segment_list : slab_segments_) {
516  for (auto& segment : segment_list) {
517  if (segment.mem_status != FREE) {
518  in_use += segment.num_pages * page_size_;
519  }
520  }
521  }
522  return in_use;
523 }
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
size_t Buffer_Namespace::BufferMgr::getMaxBufferSize ( )

Definition at line 883 of file BufferMgr.cpp.

References max_buffer_pool_size_.

883  {
884  return max_buffer_pool_size_;
885 }
const size_t max_buffer_pool_size_
Definition: BufferMgr.h:173
size_t Buffer_Namespace::BufferMgr::getMaxSize ( )
override

Definition at line 494 of file BufferMgr.cpp.

References max_buffer_pool_num_pages_, and page_size_.

Referenced by Data_Namespace::DataMgr::getMemoryInfoUnlocked().

494  {
496 }

+ Here is the caller graph for this function:

size_t Buffer_Namespace::BufferMgr::getMaxSlabSize ( )

Definition at line 887 of file BufferMgr.cpp.

References max_slab_size_.

887  {
888  return max_slab_size_;
889 }
const size_t max_slab_size_
Definition: BufferMgr.h:176
size_t Buffer_Namespace::BufferMgr::getNumChunks ( )
override

Definition at line 874 of file BufferMgr.cpp.

References chunk_index_, and chunk_index_mutex_.

874  {
875  std::lock_guard<std::mutex> chunk_index_lock(chunk_index_mutex_);
876  return chunk_index_.size();
877 }
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
size_t Buffer_Namespace::BufferMgr::getPageSize ( )

Definition at line 508 of file BufferMgr.cpp.

References page_size_.

Referenced by Data_Namespace::DataMgr::getMemoryInfoUnlocked().

508  {
509  return page_size_;
510 }

+ Here is the caller graph for this function:

const std::vector< BufferList > & Buffer_Namespace::BufferMgr::getSlabSegments ( )

Definition at line 896 of file BufferMgr.cpp.

References slab_segments_.

Referenced by Data_Namespace::DataMgr::getMemoryInfoUnlocked().

896  {
897  return slab_segments_;
898 }
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181

+ Here is the caller graph for this function:

bool Buffer_Namespace::BufferMgr::isAllocationCapped ( )
override

Definition at line 504 of file BufferMgr.cpp.

References allocations_capped_.

Referenced by Data_Namespace::DataMgr::getMemoryInfoUnlocked().

504  {
505  return allocations_capped_;
506 }

+ Here is the caller graph for this function:

bool Buffer_Namespace::BufferMgr::isBufferOnDevice ( const ChunkKey key)
override

Puts the contents of d into the Buffer with ChunkKey key.

Parameters
key- Unique identifier for a Chunk.
d- An object representing the source data for the Chunk.
Returns
AbstractBuffer*

Definition at line 587 of file BufferMgr.cpp.

References chunk_index_, and chunk_index_mutex_.

587  {
588  std::lock_guard<std::mutex> chunkIndexLock(chunk_index_mutex_);
589  if (chunk_index_.find(key) == chunk_index_.end()) {
590  return false;
591  } else {
592  return true;
593  }
594 }
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
std::string Buffer_Namespace::BufferMgr::keyToString ( const ChunkKey key)

Definition at line 36 of file BufferMgr.cpp.

Referenced by fetchBuffer(), and getBuffer().

36  {
37  std::ostringstream oss;
38 
39  oss << " key: ";
40  for (auto sub_key : key) {
41  oss << sub_key << ",";
42  }
43  return oss.str();
44 }

+ Here is the caller graph for this function:

BufferMgr& Buffer_Namespace::BufferMgr::operator= ( const BufferMgr )
private
std::string Buffer_Namespace::BufferMgr::printMap ( )

Definition at line 546 of file BufferMgr.cpp.

References chunk_index_, chunk_index_mutex_, and printSeg().

546  {
547  std::ostringstream tss;
548  int seg_num = 1;
549  tss << std::endl
550  << "Map Contents: "
551  << " " << getStringMgrType() << ":" << device_id_ << std::endl;
552  std::lock_guard<std::mutex> chunk_index_lock(chunk_index_mutex_);
553  for (auto seg_it = chunk_index_.begin(); seg_it != chunk_index_.end();
554  ++seg_it, ++seg_num) {
555  // tss << "Map Entry " << seg_num << ": ";
556  // for (auto vec_it = seg_it->first.begin(); vec_it != seg_it->first.end();
557  // ++vec_it)
558  // {
559  // tss << *vec_it << ",";
560  // }
561  // tss << " " << std::endl;
562  tss << printSeg(seg_it->second);
563  }
564  tss << "--------------------" << std::endl;
565  return tss.str();
566 }
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
std::string printSeg(BufferList::iterator &seg_it)
Definition: BufferMgr.cpp:525

+ Here is the call graph for this function:

std::string Buffer_Namespace::BufferMgr::printSeg ( BufferList::iterator &  seg_it)

Definition at line 525 of file BufferMgr.cpp.

References Buffer_Namespace::FREE.

Referenced by printMap(), and printSegs().

525  {
526  std::ostringstream tss;
527  tss << "SN: " << setfill(' ') << setw(2) << seg_it->slab_num;
528  tss << " SP: " << setfill(' ') << setw(7) << seg_it->start_page;
529  tss << " NP: " << setfill(' ') << setw(7) << seg_it->num_pages;
530  tss << " LT: " << setfill(' ') << setw(7) << seg_it->last_touched;
531  tss << " PC: " << setfill(' ') << setw(2) << seg_it->buffer->getPinCount();
532  if (seg_it->mem_status == FREE) {
533  tss << " FREE"
534  << " ";
535  } else {
536  tss << " USED - Chunk: ";
537  for (auto vec_it = seg_it->chunk_key.begin(); vec_it != seg_it->chunk_key.end();
538  ++vec_it) {
539  tss << *vec_it << ",";
540  }
541  tss << std::endl;
542  }
543  return tss.str();
544 }

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::printSegs ( )

Definition at line 568 of file BufferMgr.cpp.

References logger::INFO, LOG, printSeg(), and slab_segments_.

568  {
569  int seg_num = 1;
570  int slab_num = 1;
571  LOG(INFO) << std::endl << " " << getStringMgrType() << ":" << device_id_;
572  for (auto slab_it = slab_segments_.begin(); slab_it != slab_segments_.end();
573  ++slab_it, ++slab_num) {
574  LOG(INFO) << "Slab Num: " << slab_num << " " << getStringMgrType() << ":"
575  << device_id_;
576  for (auto seg_it = slab_it->begin(); seg_it != slab_it->end(); ++seg_it, ++seg_num) {
577  LOG(INFO) << "Segment: " << seg_num << " " << getStringMgrType() << ":"
578  << device_id_;
579  printSeg(seg_it);
580  LOG(INFO) << " " << getStringMgrType() << ":" << device_id_;
581  }
582  LOG(INFO) << "--------------------"
583  << " " << getStringMgrType() << ":" << device_id_;
584  }
585 }
#define LOG(tag)
Definition: Logger.h:283
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
std::string printSeg(BufferList::iterator &seg_it)
Definition: BufferMgr.cpp:525

+ Here is the call graph for this function:

std::string Buffer_Namespace::BufferMgr::printSlab ( size_t  slab_num)

Definition at line 430 of file BufferMgr.cpp.

References Buffer_Namespace::FREE, and slab_segments_.

Referenced by printSlabs().

430  {
431  std::ostringstream tss;
432  // size_t lastEnd = 0;
433  tss << "Slab St.Page Pages Touch" << std::endl;
434  for (auto segment : slab_segments_[slab_num]) {
435  tss << setfill(' ') << setw(4) << slab_num;
436  // tss << " BSN: " << setfill(' ') << setw(2) << segment.slab_num;
437  tss << setfill(' ') << setw(8) << segment.start_page;
438  tss << setfill(' ') << setw(8) << segment.num_pages;
439  // tss << " GAP: " << setfill(' ') << setw(7) << segment.start_page - lastEnd;
440  // lastEnd = segment.start_page + segment.num_pages;
441  tss << setfill(' ') << setw(7) << segment.last_touched;
442  // tss << " PC: " << setfill(' ') << setw(2) << segment.buffer->getPinCount();
443  if (segment.mem_status == FREE) {
444  tss << " FREE"
445  << " ";
446  } else {
447  tss << " PC: " << setfill(' ') << setw(2) << segment.buffer->getPinCount();
448  tss << " USED - Chunk: ";
449 
450  for (auto&& key_elem : segment.chunk_key) {
451  tss << key_elem << ",";
452  }
453  }
454  tss << std::endl;
455  }
456  return tss.str();
457 }
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181

+ Here is the caller graph for this function:

std::string Buffer_Namespace::BufferMgr::printSlabs ( )
override

Definition at line 459 of file BufferMgr.cpp.

References printSlab(), and slab_segments_.

Referenced by findFreeBuffer().

459  {
460  std::ostringstream tss;
461  tss << std::endl
462  << "Slabs Contents: "
463  << " " << getStringMgrType() << ":" << device_id_ << std::endl;
464  size_t num_slabs = slab_segments_.size();
465  for (size_t slab_num = 0; slab_num != num_slabs; ++slab_num) {
466  tss << printSlab(slab_num);
467  }
468  tss << "--------------------" << std::endl;
469  return tss.str();
470 }
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
std::string printSlab(size_t slab_num)
Definition: BufferMgr.cpp:430

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

AbstractBuffer * Buffer_Namespace::BufferMgr::putBuffer ( const ChunkKey key,
AbstractBuffer d,
const size_t  num_bytes = 0 
)
override

Definition at line 814 of file BufferMgr.cpp.

References Data_Namespace::AbstractBuffer::append(), CHECK, chunk_index_, chunk_index_mutex_, Data_Namespace::AbstractBuffer::clearDirtyBits(), createBuffer(), Data_Namespace::AbstractBuffer::getDeviceId(), Data_Namespace::AbstractBuffer::getMemoryPtr(), Data_Namespace::AbstractBuffer::getType(), Data_Namespace::AbstractBuffer::isAppended(), Data_Namespace::AbstractBuffer::isDirty(), Data_Namespace::AbstractBuffer::isUpdated(), page_size_, Data_Namespace::AbstractBuffer::size(), Data_Namespace::AbstractBuffer::syncEncoder(), UNREACHABLE, and Data_Namespace::AbstractBuffer::write().

816  {
817  std::unique_lock<std::mutex> chunk_index_lock(chunk_index_mutex_);
818  auto buffer_it = chunk_index_.find(key);
819  bool found_buffer = buffer_it != chunk_index_.end();
820  chunk_index_lock.unlock();
821  AbstractBuffer* buffer;
822  if (!found_buffer) {
823  buffer = createBuffer(key, page_size_);
824  } else {
825  buffer = buffer_it->second->buffer;
826  }
827  size_t old_buffer_size = buffer->size();
828  size_t new_buffer_size = num_bytes == 0 ? src_buffer->size() : num_bytes;
829  CHECK(!buffer->isDirty());
830 
831  if (src_buffer->isUpdated()) {
832  //@todo use dirty flags to only flush pages of chunk that need to
833  // be flushed
834  buffer->write((int8_t*)src_buffer->getMemoryPtr(),
835  new_buffer_size,
836  0,
837  src_buffer->getType(),
838  src_buffer->getDeviceId());
839  } else if (src_buffer->isAppended()) {
840  CHECK(old_buffer_size < new_buffer_size);
841  buffer->append((int8_t*)src_buffer->getMemoryPtr() + old_buffer_size,
842  new_buffer_size - old_buffer_size,
843  src_buffer->getType(),
844  src_buffer->getDeviceId());
845  } else {
846  UNREACHABLE();
847  }
848  src_buffer->clearDirtyBits();
849  buffer->syncEncoder(src_buffer);
850  return buffer;
851 }
AbstractBuffer * createBuffer(const ChunkKey &key, const size_t page_size=0, const size_t initial_size=0) override
Creates a chunk with the specified key and page size.
Definition: BufferMgr.cpp:110
void syncEncoder(const AbstractBuffer *src_buffer)
#define UNREACHABLE()
Definition: Logger.h:333
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
An AbstractBuffer is a unit of data management for a data manager.
virtual void write(int8_t *src, const size_t num_bytes, const size_t offset=0, const MemoryLevel src_buffer_type=CPU_LEVEL, const int src_device_id=-1)=0
virtual void append(int8_t *src, const size_t num_bytes, const MemoryLevel src_buffer_type=CPU_LEVEL, const int device_id=-1)=0
#define CHECK(condition)
Definition: Logger.h:289

+ Here is the call graph for this function:

void Buffer_Namespace::BufferMgr::reinit ( )

Definition at line 85 of file BufferMgr.cpp.

References allocations_capped_, current_max_slab_page_size_, max_num_pages_per_slab_, and num_pages_allocated_.

Referenced by clearSlabs().

85  {
88  max_num_pages_per_slab_; // current_max_slab_page_size_ will drop as allocations
89  // fail - this is the high water mark
90  allocations_capped_ = false;
91 }

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::removeSegment ( BufferList::iterator &  seg_it)
private

Definition at line 650 of file BufferMgr.cpp.

References Buffer_Namespace::FREE, slab_segments_, unsized_segs_, and unsized_segs_mutex_.

Referenced by deleteBuffer(), deleteBuffersWithPrefix(), and reserveBuffer().

650  {
651  // Note: does not delete buffer as this may be moved somewhere else
652  int slab_num = seg_it->slab_num;
653  // cout << "Slab num: " << slabNum << endl;
654  if (slab_num < 0) {
655  std::lock_guard<std::mutex> unsized_segs_lock(unsized_segs_mutex_);
656  unsized_segs_.erase(seg_it);
657  } else {
658  if (seg_it != slab_segments_[slab_num].begin()) {
659  auto prev_it = std::prev(seg_it);
660  // LOG(INFO) << "PrevIt: " << " " << getStringMgrType() << ":" << device_id_;
661  // printSeg(prev_it);
662  if (prev_it->mem_status == FREE) {
663  seg_it->start_page = prev_it->start_page;
664  seg_it->num_pages += prev_it->num_pages;
665  slab_segments_[slab_num].erase(prev_it);
666  }
667  }
668  auto next_it = std::next(seg_it);
669  if (next_it != slab_segments_[slab_num].end()) {
670  if (next_it->mem_status == FREE) {
671  seg_it->num_pages += next_it->num_pages;
672  slab_segments_[slab_num].erase(next_it);
673  }
674  }
675  seg_it->mem_status = FREE;
676  // seg_it->pinCount = 0;
677  seg_it->buffer = 0;
678  }
679 }
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
std::mutex unsized_segs_mutex_
Definition: BufferMgr.h:199

+ Here is the caller graph for this function:

void Buffer_Namespace::BufferMgr::removeTableRelatedDS ( const int  db_id,
const int  table_id 
)
override

Definition at line 900 of file BufferMgr.cpp.

References UNREACHABLE.

900  {
901  UNREACHABLE();
902 }
#define UNREACHABLE()
Definition: Logger.h:333
BufferList::iterator Buffer_Namespace::BufferMgr::reserveBuffer ( BufferList::iterator &  seg_it,
const size_t  num_bytes 
)

Definition at line 198 of file BufferMgr.cpp.

References chunk_index_, chunk_index_mutex_, findFreeBuffer(), Buffer_Namespace::FREE, page_size_, removeSegment(), slab_segments_, and slabs_.

Referenced by Buffer_Namespace::Buffer::reserve().

200  { // assumes buffer is already pinned
201 
202  size_t num_pages_requested = (num_bytes + page_size_ - 1) / page_size_;
203  size_t num_pages_extra_needed = num_pages_requested - seg_it->num_pages;
204 
205  if (num_pages_requested < seg_it->num_pages) {
206  // We already have enough pages in existing segment
207  return seg_it;
208  }
209  // First check for free segment after seg_it
210  int slab_num = seg_it->slab_num;
211  if (slab_num >= 0) { // not dummy page
212  BufferList::iterator next_it = std::next(seg_it);
213  if (next_it != slab_segments_[slab_num].end() && next_it->mem_status == FREE &&
214  next_it->num_pages >= num_pages_extra_needed) {
215  // Then we can just use the next BufferSeg which happens to be free
216  size_t leftover_pages = next_it->num_pages - num_pages_extra_needed;
217  seg_it->num_pages = num_pages_requested;
218  next_it->num_pages = leftover_pages;
219  next_it->start_page = seg_it->start_page + seg_it->num_pages;
220  return seg_it;
221  }
222  }
223  // If we're here then we couldn't keep buffer in existing slot
224  // need to find new segment, copy data over, and then delete old
225  auto new_seg_it = findFreeBuffer(num_bytes);
226 
227  // Below should be in copy constructor for BufferSeg?
228  new_seg_it->buffer = seg_it->buffer;
229  new_seg_it->chunk_key = seg_it->chunk_key;
230  int8_t* old_mem = new_seg_it->buffer->mem_;
231  new_seg_it->buffer->mem_ =
232  slabs_[new_seg_it->slab_num] + new_seg_it->start_page * page_size_;
233 
234  // now need to copy over memory
235  // only do this if the old segment is valid (i.e. not new w/ unallocated buffer
236  if (seg_it->start_page >= 0 && seg_it->buffer->mem_ != 0) {
237  new_seg_it->buffer->writeData(old_mem,
238  new_seg_it->buffer->size(),
239  0,
240  new_seg_it->buffer->getType(),
241  device_id_);
242  }
243  // Decrement pin count to reverse effect above
244  removeSegment(seg_it);
245  {
246  std::lock_guard<std::mutex> lock(chunk_index_mutex_);
247  chunk_index_[new_seg_it->chunk_key] = new_seg_it;
248  }
249 
250  return new_seg_it;
251 }
BufferList::iterator findFreeBuffer(size_t num_bytes)
Gets a buffer of required size and returns an iterator to it.
Definition: BufferMgr.cpp:281
void removeSegment(BufferList::iterator &seg_it)
Definition: BufferMgr.cpp:650
std::vector< BufferList > slab_segments_
Definition: BufferMgr.h:181
std::map< ChunkKey, BufferList::iterator > chunk_index_
Definition: BufferMgr.h:203
std::vector< int8_t * > slabs_
Definition: BufferMgr.h:179

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

size_t Buffer_Namespace::BufferMgr::size ( )

Returns the total number of bytes allocated.

Definition at line 879 of file BufferMgr.cpp.

References num_pages_allocated_.

879  {
880  return num_pages_allocated_;
881 }

Member Data Documentation

bool Buffer_Namespace::BufferMgr::allocations_capped_
private

Definition at line 209 of file BufferMgr.h.

Referenced by findFreeBuffer(), isAllocationCapped(), and reinit().

unsigned int Buffer_Namespace::BufferMgr::buffer_epoch_
private

Definition at line 212 of file BufferMgr.h.

Referenced by clear(), evict(), findFreeBufferInSlab(), and getBuffer().

std::mutex Buffer_Namespace::BufferMgr::buffer_id_mutex_
private

Definition at line 200 of file BufferMgr.h.

Referenced by getBufferId().

std::map<ChunkKey, BufferList::iterator> Buffer_Namespace::BufferMgr::chunk_index_
private
std::mutex Buffer_Namespace::BufferMgr::chunk_index_mutex_
private
size_t Buffer_Namespace::BufferMgr::current_max_slab_page_size_
private

Definition at line 208 of file BufferMgr.h.

Referenced by BufferMgr(), findFreeBuffer(), and reinit().

std::mutex Buffer_Namespace::BufferMgr::global_mutex_
private

Definition at line 201 of file BufferMgr.h.

Referenced by alloc(), checkpoint(), fetchBuffer(), free(), and getBuffer().

int Buffer_Namespace::BufferMgr::max_buffer_id_
private

Definition at line 211 of file BufferMgr.h.

Referenced by getBufferId().

size_t Buffer_Namespace::BufferMgr::max_buffer_pool_num_pages_
private

Definition at line 204 of file BufferMgr.h.

Referenced by BufferMgr(), findFreeBuffer(), and getMaxSize().

const size_t Buffer_Namespace::BufferMgr::max_buffer_pool_size_
protected

Definition at line 173 of file BufferMgr.h.

Referenced by BufferMgr(), and getMaxBufferSize().

size_t Buffer_Namespace::BufferMgr::max_num_pages_per_slab_
private

Definition at line 207 of file BufferMgr.h.

Referenced by BufferMgr(), findFreeBuffer(), and reinit().

const size_t Buffer_Namespace::BufferMgr::max_slab_size_
protected

minimum size of the individual memory allocations that compose the buffer pool (up to maxBufferSize_)

Definition at line 176 of file BufferMgr.h.

Referenced by BufferMgr(), getMaxSlabSize(), Buffer_Namespace::TieredCpuBufferMgr::initializeMem(), Buffer_Namespace::CpuBufferMgr::initializeMem(), and Buffer_Namespace::TieredCpuBufferMgr::TieredCpuBufferMgr().

size_t Buffer_Namespace::BufferMgr::min_num_pages_per_slab_
private

Definition at line 206 of file BufferMgr.h.

Referenced by BufferMgr(), and findFreeBuffer().

const size_t Buffer_Namespace::BufferMgr::min_slab_size_
protected

max number of bytes allocated for the buffer pool

Definition at line 174 of file BufferMgr.h.

Referenced by BufferMgr().

size_t Buffer_Namespace::BufferMgr::num_pages_allocated_
private

Definition at line 205 of file BufferMgr.h.

Referenced by findFreeBuffer(), getAllocated(), reinit(), and size().

const size_t Buffer_Namespace::BufferMgr::page_size_
protected
AbstractBufferMgr* Buffer_Namespace::BufferMgr::parent_mgr_
private

Definition at line 210 of file BufferMgr.h.

Referenced by checkpoint(), fetchBuffer(), and getBuffer().

std::mutex Buffer_Namespace::BufferMgr::sized_segs_mutex_
private

Definition at line 198 of file BufferMgr.h.

Referenced by clear(), deleteBuffer(), deleteBuffersWithPrefix(), fetchBuffer(), and getBuffer().

std::vector<BufferList> Buffer_Namespace::BufferMgr::slab_segments_
protected
BufferList Buffer_Namespace::BufferMgr::unsized_segs_
private

Definition at line 214 of file BufferMgr.h.

Referenced by clear(), createBuffer(), and removeSegment().

std::mutex Buffer_Namespace::BufferMgr::unsized_segs_mutex_
private

Definition at line 199 of file BufferMgr.h.

Referenced by clear(), createBuffer(), and removeSegment().


The documentation for this class was generated from the following files: