text: /*
   * FlashHeaderStoreCacheElement.cpp
   *
   *  Created on: 2022/03/28
   *      Author: iizuka
   */
  
  #include "flash_header_store/main/FlashHeaderStoreCacheElement.h"
  #include "flash_header_store/store/FlashHeaderStore.h"
  #include "flash_header_store/store/FlashHeaderHeightIndex.h"
  
  #include "base_io/File.h"
  
  #include "osenv/funcs.h"
  
  #include "random_access_file/DiskCacheManager.h"
  
  #include "bc_network/NetworkShard.h"
  
  #include "flash/AbstractFlashBlockHeader.h"
  
  #include "base/StackRelease.h"
  
  #include "flash_header_store/store/ShardsFlashHeadersList.h"
  
  #include "flash_header_store/store/FlashHeaderList.h"
  
  #include "bc_network/NetworkShardsStatus.h"
  
  #include "flash/FlashBlockId.h"
  namespace codablecash {
  
  FlashHeaderStoreCacheElement::FlashHeaderStoreCacheElement(const File* baseDir, uint64_t index) {
  	this->baseDir = new File(*baseDir);
  	this->index = index;
  
  	this->cacheManager = new DiskCacheManager(Os::getSystemPageSize() * 4 * 4);
  	this->store = nullptr;
  	this->heightIndex = nullptr;
  }
  
  FlashHeaderStoreCacheElement::~FlashHeaderStoreCacheElement() {
  	close();
  	delete this->cacheManager;
  	delete this->baseDir;
  }
  
  void FlashHeaderStoreCacheElement::init() {
  	this->store = new FlashHeaderStore(this->index, this->baseDir, this->cacheManager);
  	this->heightIndex = new FlashHeaderHeightIndex(this->index, this->baseDir, this->cacheManager);
  
  	this->store->open();
  	this->heightIndex->open();
  }
  
  bool FlashHeaderStoreCacheElement::exist() const noexcept {
  	FlashHeaderStore s(this->index, this->baseDir, this->cacheManager);
  	FlashHeaderHeightIndex h(this->index, this->baseDir, this->cacheManager);
  
  	return s.exists() && h.exists();
  }
  
  void FlashHeaderStoreCacheElement::create() {
  	FlashHeaderStore s(this->index, this->baseDir, this->cacheManager);
  	FlashHeaderHeightIndex h(this->index, this->baseDir, this->cacheManager);
  
  	s.create();
  	h.create();
  }
  
  void FlashHeaderStoreCacheElement::close() {
  	if(this->store != nullptr){
  		this->store->close();
  		delete this->store, this->store = nullptr;
  	}
  	if(this->heightIndex != nullptr){
  		this->heightIndex->close();
  		delete this->heightIndex, this->heightIndex = nullptr;
  	}
  }
  
  void FlashHeaderStoreCacheElement::addHeader(const AbstractFlashBlockHeader* header, const NetworkShardsStatus* shardsStatus) {
  	uint64_t fpos = this->store->storeHeader(header);
  
  	uint64_t height = header->getHeight();
  
  	const NetworkShard* shard = header->getShard();
  	uint8_t shardId = shard->getBegin();
  
  	this->heightIndex->addHeader(height, fpos, shardId, shardsStatus);
  }
  
  ArrayList<AbstractFlashBlockHeader>* FlashHeaderStoreCacheElement::getHeadersAtHeight(
  		uint64_t height, uint8_t shardId, const NetworkShardsStatus* shardsStatus) {
  	ShardsFlashHeadersList* shardslist = this->heightIndex->getHeadersAtHeight(height); __STP(shardslist);
  
  	if(shardslist == nullptr){
  		return nullptr;
  	}
  
  	int pos = shardsStatus->getShardPosition(shardId);
  	const FlashHeaderList* list = shardslist->get(pos);
  
  	ArrayList<AbstractFlashBlockHeader>* headers = new ArrayList<AbstractFlashBlockHeader>();
  
  	int maxLoop = list->size();
  	for(int i = 0; i != maxLoop; ++i){
  		uint64_t fpos = list->get(i);
  
  		AbstractFlashBlockHeader* header = this->store->loadHeader(fpos);
  		headers->addElement(header);
  	}
  
  	return headers;
  }
  
  void FlashHeaderStoreCacheElement::removeBlock(const FlashBlockId* blockId,
  		uint64_t height, uint8_t shardId, const NetworkShardsStatus* shardsStatus) {
  	ShardsFlashHeadersList* shardslist = this->heightIndex->getHeadersAtHeight(height); __STP(shardslist);
  
  	if(shardslist == nullptr){
  		return;
  	}
  
  	int pos = shardsStatus->getShardPosition(shardId);
  	const FlashHeaderList* list = shardslist->get(pos);
  
  	uint64_t fpos2remove = -1;
  
  	int maxLoop = list->size();
  	for(int i = 0; i != maxLoop; ++i){
  		uint64_t fpos = list->get(i);
  
  		AbstractFlashBlockHeader* header = this->store->loadHeader(fpos); __STP(header);
  		const FlashBlockId* bid = header->getBlockId();
  
  		if(bid->compareTo(blockId) == 0){
  			fpos2remove = fpos;
  			break;
  		}
  	}
  
  	assert(fpos2remove > 0);
  
  	this->heightIndex->removeIndex(height, fpos2remove);
  	this->store->removeHeader(fpos2remove);
  }
  
  } /* namespace codablecash */
  