/* Copyright (C) 2014 InfiniDB, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /****************************************************************************************** * $Id: we_cache.cpp 33 2006-10-30 13:45:13Z wzhou $ * ******************************************************************************************/ /** @file */ #include using namespace std; namespace WriteEngine { CacheControl* Cache::m_cacheParam = nullptr; FreeBufList* Cache::m_freeList = nullptr; CacheMap* Cache::m_lruList = nullptr; CacheMap* Cache::m_writeList = nullptr; bool Cache::m_useCache = false; /*********************************************************** * DESCRIPTION: * Clear all list and free memory * PARAMETERS: * none * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ void Cache::clear() { CacheMapIt it; BlockBuffer* block; size_t i; // free list if (m_freeList != nullptr) { for (i = 0; i < m_freeList->size(); i++) { block = m_freeList->at(i); block->clear(); } } // LRU list if (m_lruList != nullptr) { for (it = m_lruList->begin(); it != m_lruList->end(); it++) { block = it->second; block->clear(); m_freeList->push_back(block); } m_lruList->clear(); } // Write list if (m_writeList != nullptr) { for (it = m_writeList->begin(); it != m_writeList->end(); it++) { block = it->second; block->clear(); m_freeList->push_back(block); } m_writeList->clear(); } } /*********************************************************** * DESCRIPTION: * Flush write cache * PARAMETERS: * none * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ int Cache::flushCache() { bool bHasReadBlock = false; BlockBuffer* curBuf; // add lock here if (m_lruList && !m_lruList->empty()) { bHasReadBlock = true; for (auto& it : *m_lruList) { curBuf = it.second; curBuf->clear(); m_freeList->push_back(curBuf); } m_lruList->clear(); } // must write to disk first if (m_writeList && !m_writeList->empty()) { if (!bHasReadBlock) for (auto& it : *m_writeList) { curBuf = it.second; curBuf->clear(); m_freeList->push_back(curBuf); } else for (auto& it : *m_writeList) { curBuf = it.second; (*curBuf).block.dirty = false; processCacheMap(m_lruList, curBuf, INSERT); } m_writeList->clear(); } // end of if( m_writeList->size() // add unlock here return NO_ERROR; } /*********************************************************** * DESCRIPTION: * Free memory * PARAMETERS: * none * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ void Cache::freeMemory() { CacheMapIt it; BlockBuffer* block; size_t i; // free list if (m_freeList != nullptr) { for (i = 0; i < m_freeList->size(); i++) { block = m_freeList->at(i); block->freeMem(); delete block; } m_freeList->clear(); delete m_freeList; m_freeList = nullptr; } // LRU list if (m_lruList != nullptr) { for (it = m_lruList->begin(); it != m_lruList->end(); it++) { block = it->second; block->freeMem(); delete block; } m_lruList->clear(); delete m_lruList; m_lruList = nullptr; } // Write list if (m_writeList != nullptr) { for (it = m_writeList->begin(); it != m_writeList->end(); it++) { block = it->second; block->freeMem(); delete block; } m_writeList->clear(); delete m_writeList; m_writeList = nullptr; } // param if (m_cacheParam != nullptr) { delete m_cacheParam; m_cacheParam = nullptr; } } /*********************************************************** * DESCRIPTION: * get a list size * PARAMETERS: * listType - List type * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ int Cache::getListSize(const CacheListType listType) { int size = 0; if (!m_useCache) return size; switch (listType) { case FREE_LIST: size = m_freeList->size(); break; case LRU_LIST: size = m_lruList->size(); break; case WRITE_LIST: default: size = m_writeList->size(); break; } return size; } /*********************************************************** * DESCRIPTION: * Init all parameters and list * PARAMETERS: * totalBlock - total blocks * chkPoint - checkpoint interval * pctFree - percentage free * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ void Cache::init(const int totalBlock, const int chkPoint, const int pctFree) { BlockBuffer* buffer; if (m_cacheParam && m_freeList && m_lruList && m_writeList) return; m_cacheParam = new CacheControl(); m_cacheParam->totalBlock = totalBlock; m_cacheParam->checkInterval = chkPoint; m_cacheParam->pctFree = pctFree; m_freeList = new FreeBufList(); m_lruList = new CacheMap(); m_writeList = new CacheMap(); for (int i = 0; i < m_cacheParam->totalBlock; i++) { buffer = new BlockBuffer(); buffer->init(); m_freeList->push_back(buffer); } } /*********************************************************** * DESCRIPTION: * Insert a buffer to LRU list * PARAMETERS: * cb - Comm Block * lbid - lbid value * fbo - fbo * buf - input buffer * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ int Cache::insertLRUList(CommBlock& cb, const uint64_t lbid, const uint64_t fbo, const unsigned char* buf) { BlockBuffer* buffer; vector::iterator it; if (m_freeList->empty()) return ERR_FREE_LIST_EMPTY; // make sure flush first if necessary it = m_freeList->begin(); buffer = *it; memcpy((*buffer).block.data, buf, BYTE_PER_BLOCK); (*buffer).listType = LRU_LIST; (*buffer).block.lbid = lbid; (*buffer).block.fbo = fbo; (*buffer).block.dirty = false; (*buffer).block.hitCount = 1; (*buffer).cb.file.oid = cb.file.oid; (*buffer).cb.file.pFile = cb.file.pFile; RETURN_ON_ERROR(processCacheMap(m_lruList, buffer, INSERT)); m_freeList->erase(it); return NO_ERROR; } /*********************************************************** * DESCRIPTION: * Load cache block * PARAMETERS: * key - Cache key * buf - output buffer * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ int Cache::loadCacheBlock(const CacheKey& key, unsigned char* buf) { BlockBuffer* buffer; CacheMapIt iter; iter = m_lruList->find(key); if (iter != m_lruList->end()) buffer = iter->second; else { iter = m_writeList->find(key); if (iter != m_writeList->end()) buffer = iter->second; else return ERR_CACHE_KEY_NOT_EXIST; } memcpy(buf, (*buffer).block.data, BYTE_PER_BLOCK); (*buffer).block.hitCount++; return NO_ERROR; } /*********************************************************** * DESCRIPTION: * Modify cache block * PARAMETERS: * key - Cache key * buf - output buffer * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ int Cache::modifyCacheBlock(const CacheKey& key, const unsigned char* buf) { BlockBuffer* buffer; CacheMapIt iter; iter = m_lruList->find(key); if (iter != m_lruList->end()) { buffer = iter->second; (*buffer).listType = WRITE_LIST; (*buffer).block.dirty = true; (*m_writeList)[key] = iter->second; m_lruList->erase(iter); } else { iter = m_writeList->find(key); if (iter != m_writeList->end()) buffer = iter->second; else return ERR_CACHE_KEY_NOT_EXIST; } memcpy((*buffer).block.data, buf, BYTE_PER_BLOCK); (*buffer).block.hitCount++; return NO_ERROR; } /*********************************************************** * DESCRIPTION: * Print cache list * PARAMETERS: * none * RETURN: * none ***********************************************************/ void Cache::printCacheList() { BlockBuffer* buffer; int i = 0; if (!m_useCache) return; cout << "\nFree List has " << m_freeList->size() << " elements" << endl; cout << "LRU List has " << m_lruList->size() << " elements" << endl; for (const auto& it : *m_lruList) { buffer = it.second; cout << "\t[" << i++ << "] key=" << it.first << " listType=" << buffer->listType << " oid=" << (*buffer).cb.file.oid << " fbo=" << (*buffer).block.fbo << " dirty=" << (*buffer).block.dirty << " hitCount=" << (*buffer).block.hitCount << endl; } i = 0; cout << "Write List has " << m_writeList->size() << " elements" << endl; for (const auto& it : *m_writeList) { buffer = it.second; cout << "\t[" << i++ << "] key=" << it.first << " listType=" << buffer->listType << " oid=" << (*buffer).cb.file.oid << " fbo=" << (*buffer).block.fbo << " dirty=" << (*buffer).block.dirty << " hitCount=" << (*buffer).block.hitCount << endl; } } /*********************************************************** * DESCRIPTION: * Process a buffer in a cache map * PARAMETERS: * buffer - block buffer * opType - insert or delete * RETURN: * NO_ERROR if success, other otherwise ***********************************************************/ int Cache::processCacheMap(CacheMap* map, BlockBuffer* buffer, OpType opType) { RETURN_ON_NULL(buffer, ERR_NULL_BLOCK); CacheMapIt iter; CacheKey key = getCacheKey(buffer); iter = map->find(key); // only handle insert and delete if (iter == map->end()) { if (opType == INSERT) (*map)[key] = buffer; else return ERR_CACHE_KEY_NOT_EXIST; } else { if (opType == INSERT) return ERR_CACHE_KEY_EXIST; else map->erase(iter); } return NO_ERROR; } } // namespace WriteEngine