void AntiCacheEvictionManager::printLRUChain(PersistentTable* table, int max, bool forward) { VOLT_INFO("num tuples in chain: %d", table->getNumTuplesInEvictionChain()); VOLT_INFO("oldest tuple id: %u", table->getOldestTupleID()); VOLT_INFO("newest tuple id: %u", table->getNewestTupleID()); char chain[max * 4]; int tuple_id; TableTuple tuple = table->tempTuple(); if(forward) tuple_id = table->getOldestTupleID(); else tuple_id = table->getNewestTupleID(); chain[0] = '\0'; int iterations = 0; while(iterations < table->getNumTuplesInEvictionChain() && iterations < max) { strcat(chain, itoa(tuple_id)); strcat(chain, " "); tuple.move(table->dataPtrForTuple(tuple_id)); if(forward) tuple_id = tuple.getNextTupleInChain(); else tuple_id = tuple.getPreviousTupleInChain(); iterations++; } VOLT_INFO("LRU CHAIN: %s", chain); }
AntiCacheBlock AntiCacheDB::readBlockNVM(std::string tableName, int16_t blockId) { std::map<int16_t, std::pair<int, int32_t> >::iterator itr; itr = m_blockMap.find(blockId); if (itr == m_blockMap.end()) { VOLT_INFO("Invalid anti-cache blockId '%d' for table '%s'", blockId, tableName.c_str()); VOLT_ERROR("Invalid anti-cache blockId '%d' for table '%s'", blockId, tableName.c_str()); throw UnknownBlockAccessException(tableName, blockId); } int blockIndex = itr->second.first; // VOLT_INFO("Reading NVM block: ID = %d, index = %d, size = %ld.", blockId, blockIndex, itr->second.second); char* block_ptr = getNVMBlock(blockIndex); char* block = new char[itr->second.second]; memcpy(block, block_ptr, itr->second.second); AntiCacheBlock anticache_block(blockId, block, itr->second.second); freeNVMBlock(blockId); m_blockMap.erase(itr); return (anticache_block); }
TableIndex *getInstanceIfKeyFits() { if (m_keySize > KeySize) { return NULL; } if (m_intsOnly) { // The IntsKey size parameter ((KeySize-1)/8 + 1) is calculated to be // the number of 8-byte uint64's required to store KeySize packed bytes. return getInstanceForKeyType<IntsKey<(KeySize-1)/8 + 1> >(); } // Generic Key if (m_type == HASH_TABLE_INDEX) { VOLT_INFO("Producing a tree index for %s: " "hash index not currently supported for this index key.\n", m_scheme.name.c_str()); m_type = BALANCED_TREE_INDEX; } // If any indexed expression value can not either be stored "inline" within a (GenericKey) key tuple // or specifically in a non-inlined object shared with the base table (because it is a simple column value), // then the GenericKey will have to reference and maintain its own persistent non-inline storage. // That's exactly what the GenericPersistentKey subtype of GenericKey does. This incurs extra overhead // for object copying and freeing, so is only enabled as needed. if (m_inlinesOrColumnsOnly) { return getInstanceForKeyType<GenericKey<KeySize> >(); } return getInstanceForKeyType<GenericPersistentKey<KeySize> >(); }
NVMAntiCacheBlock::NVMAntiCacheBlock(uint32_t blockId, char* block, long size) : AntiCacheBlock(blockId) { /* m_block = block; m_size = size; m_blockType = ANTICACHEDB_NVM; */ char* buffer = block; std::string tableName = buffer; block = buffer + tableName.size() + 1; size -= tableName.size() + 1; m_block = new char[size]; memcpy(m_block, block, size); delete [] buffer; payload p; p.tableName = tableName; p.blockId = blockId; p.data = m_block; p.size = size; m_payload = p; m_size = static_cast<int32_t>(size); m_blockType = ANTICACHEDB_NVM; //std::string payload_str(m_payload.data, m_size); VOLT_INFO("NVMAntiCacheBlock #%u from table: %s [size=%d / payload=%ld]", blockId, m_payload.tableName.c_str(), m_size, m_payload.size); }
AntiCacheBlock* NVMAntiCacheDB::readBlock(uint32_t blockId, bool isMigrate) { std::map<uint32_t, std::pair<uint32_t, int32_t> >::iterator itr; itr = m_blockMap.find(blockId); if (itr == m_blockMap.end()) { VOLT_INFO("Invalid anti-cache blockId '%u'", blockId); VOLT_ERROR("Invalid anti-cache blockId '%u'", blockId); //throw UnknownBlockAccessException(tableName, blockId); throw UnknownBlockAccessException(blockId); } uint32_t blockIndex = itr->second.first; int blockSize = itr->second.second; char* block_ptr = getNVMBlock(blockIndex); char* block = new char[blockSize]; memcpy(block, block_ptr, blockSize); VOLT_DEBUG("Reading NVM block: ID = %u, index = %u, size = %d, isMigrate = %d, data = %s", blockId, blockIndex, blockSize, isMigrate, block); AntiCacheBlock* anticache_block = new NVMAntiCacheBlock(blockId, block, blockSize); if (this->isBlockMerge()) { freeNVMBlock(blockIndex); m_blockMap.erase(itr); //FIXME: I'm hacking!!!!!!!!!!!!!!!!!!!!!!!!! removeBlockLRU(blockId); m_bytesUnevicted += blockSize; m_blocksUnevicted++; } else { if (isMigrate) { freeNVMBlock(blockIndex); m_blockMap.erase(itr); removeBlockLRU(blockId); m_bytesUnevicted += static_cast<int32_t>( (int64_t)blockSize - blockSize / tupleInBlock[blockId] * (tupleInBlock[blockId] - evictedTupleInBlock[blockId])); m_blocksUnevicted++; } else { m_bytesUnevicted += static_cast<int32_t>( blockSize / tupleInBlock[blockId]); evictedTupleInBlock[blockId]--; // FIXME: I'm hacking!!!!!!!!!!!!!!!!!!!!!!!!! if (rand() % 100 == 0) { removeBlockLRU(blockId); pushBlockLRU(blockId); } } } return (anticache_block); }
Table* AntiCacheEvictionManager::readBlocks(PersistentTable *table, int numBlocks, int16_t blockIds[], int32_t tuple_offsets[]) { VOLT_INFO("Reading %d evicted blocks.", numBlocks); for(int i = 0; i < numBlocks; i++) table->readEvictedBlock(blockIds[i], tuple_offsets[i]); return (m_readResultTable); }
void AntiCacheDB::writeBlockNVM(const std::string tableName, int16_t blockId, const int tupleCount, const char* data, const long size) { //int index = getFreeNVMBlockIndex(); //char* block = getNVMBlock(index); char* block = getNVMBlock(m_totalBlocks); memcpy(block, data, size); //m_NVMBlocks[m_totalBlocks] = new char[size]; //memcpy(m_NVMBlocks[m_totalBlocks], data, size); VOLT_INFO("Writing NVM Block: ID = %d, index = %d, size = %ld", blockId, m_totalBlocks, size); m_blockMap.insert(std::pair<int16_t, std::pair<int, int32_t> >(blockId, std::pair<int, int32_t>(m_totalBlocks, static_cast<int32_t>(size)))); m_totalBlocks++; }
void AntiCacheDB::writeBlockBerkeleyDB(const std::string tableName, int16_t blockId, const int tupleCount, const char* data, const long size) { Dbt key; key.set_data(&blockId); key.set_size(sizeof(int16_t)); Dbt value; value.set_data(const_cast<char*>(data)); value.set_size(static_cast<int32_t>(size)); VOLT_INFO("Writing out a block #%d to anti-cache database [tuples=%d / size=%ld]", blockId, tupleCount, size); // TODO: Error checking m_db->put(NULL, &key, &value, 0); }
TableIndex *getInstanceIfKeyFits() { if (m_keySize > KeySize) { return NULL; } if (m_intsOnly) { // The IntsKey size parameter ((KeySize-1)/8 + 1) is calculated to be // the number of 8-byte uint64's required to store KeySize packed bytes. return getInstanceForKeyType<IntsKey<(KeySize-1)/8 + 1> >(); } // Generic Key if (m_type == HASH_TABLE_INDEX) { VOLT_INFO("Producing a tree index for %s: " "hash index not currently supported for this index key.\n", m_scheme.name.c_str()); m_type = BALANCED_TREE_INDEX; } return getInstanceForKeyType<GenericKey<KeySize> >(); }
bool UpdateExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *tracker) { assert(m_inputTable); assert(m_targetTable); VOLT_TRACE("INPUT TABLE: %s\n", m_inputTable->debug().c_str()); VOLT_TRACE("TARGET TABLE - BEFORE: %s\n", m_targetTable->debug().c_str()); assert(m_inputTuple.sizeInValues() == m_inputTable->columnCount()); assert(m_targetTuple.sizeInValues() == m_targetTable->columnCount()); TableIterator input_iterator(m_inputTable); while (input_iterator.next(m_inputTuple)) { // // OPTIMIZATION: Single-Sited Query Plans // If our beloved UpdatePlanNode is apart of a single-site query plan, // then the first column in the input table will be the address of a // tuple on the target table that we will want to update. This saves us // the trouble of having to do an index lookup // void *target_address = m_inputTuple.getNValue(0).castAsAddress(); m_targetTuple.move(target_address); // Read/Write Set Tracking if (tracker != NULL) { tracker->markTupleWritten(m_targetTable, &m_targetTuple); } // Loop through INPUT_COL_IDX->TARGET_COL_IDX mapping and only update // the values that we need to. The key thing to note here is that we // grab a temp tuple that is a copy of the target tuple (i.e., the tuple // we want to update). This insures that if the input tuple is somehow // bringing garbage with it, we're only going to copy what we really // need to into the target tuple. // TableTuple &tempTuple = m_targetTable->getTempTupleInlined(m_targetTuple); for (int map_ctr = 0; map_ctr < m_inputTargetMapSize; map_ctr++) { tempTuple.setNValue(m_inputTargetMap[map_ctr].second, m_inputTuple.getNValue(m_inputTargetMap[map_ctr].first)); } // if there is a partition column for the target table if (m_partitionColumn != -1) { // check for partition problems // get the value for the partition column NValue value = tempTuple.getNValue(m_partitionColumn); bool isLocal = m_engine->isLocalSite(value); // if it doesn't map to this site if (!isLocal) { VOLT_ERROR("Mispartitioned tuple in single-partition plan for" " table '%s'", m_targetTable->name().c_str()); return false; } } #ifdef ARIES if(m_engine->isARIESEnabled()){ // add persistency check: PersistentTable* table = dynamic_cast<PersistentTable*>(m_targetTable); // only log if we are writing to a persistent table. if (table != NULL) { // before image -- target is old val with no updates // XXX: what about uninlined fields? // should we not be doing // m_targetTable->getTempTupleInlined(m_targetTuple); instead? TableTuple *beforeImage = &m_targetTuple; // after image -- temp is NEW, created using target and input TableTuple *afterImage = &tempTuple; TableTuple *keyTuple = NULL; char *keydata = NULL; std::vector<int32_t> modifiedCols; int32_t numCols = -1; // See if we can do better by using an index instead TableIndex *index = table->primaryKeyIndex(); if (index != NULL) { // First construct tuple for primary key keydata = new char[index->getKeySchema()->tupleLength()]; keyTuple = new TableTuple(keydata, index->getKeySchema()); for (int i = 0; i < index->getKeySchema()->columnCount(); i++) { keyTuple->setNValue(i, beforeImage->getNValue(index->getColumnIndices()[i])); } // no before image need be recorded, just the primary key beforeImage = NULL; } // Set the modified column list numCols = m_inputTargetMapSize; modifiedCols.resize(m_inputTargetMapSize, -1); for (int map_ctr = 0; map_ctr < m_inputTargetMapSize; map_ctr++) { // can't use column-id directly, otherwise we would go over vector bounds int pos = m_inputTargetMap[map_ctr].first - 1; modifiedCols.at(pos) = m_inputTargetMap[map_ctr].second; } // Next, let the input tuple be the diff after image afterImage = &m_inputTuple; LogRecord *logrecord = new LogRecord(computeTimeStamp(), LogRecord::T_UPDATE,// this is an update record LogRecord::T_FORWARD,// the system is running normally -1,// XXX: prevLSN must be fetched from table! m_engine->getExecutorContext()->currentTxnId() ,// txn id m_engine->getSiteId(),// which execution site m_targetTable->name(),// the table affected keyTuple,// primary key numCols, (numCols > 0) ? &modifiedCols : NULL, beforeImage, afterImage ); size_t logrecordLength = logrecord->getEstimatedLength(); char *logrecordBuffer = new char[logrecordLength]; FallbackSerializeOutput output; output.initializeWithPosition(logrecordBuffer, logrecordLength, 0); logrecord->serializeTo(output); LogManager* m_logManager = this->m_engine->getLogManager(); Logger m_ariesLogger = m_logManager->getAriesLogger(); //VOLT_WARN("m_logManager : %p AriesLogger : %p",&m_logManager, &m_ariesLogger); const Logger *logger = m_logManager->getThreadLogger(LOGGERID_MM_ARIES); logger->log(LOGLEVEL_INFO, output.data(), output.position()); delete[] logrecordBuffer; logrecordBuffer = NULL; delete logrecord; logrecord = NULL; if (keydata != NULL) { delete[] keydata; keydata = NULL; } if (keyTuple != NULL) { delete keyTuple; keyTuple = NULL; } } } #endif if (!m_targetTable->updateTuple(tempTuple, m_targetTuple, m_updatesIndexes)) { VOLT_INFO("Failed to update tuple from table '%s'", m_targetTable->name().c_str()); return false; } } VOLT_TRACE("TARGET TABLE - AFTER: %s\n", m_targetTable->debug().c_str()); // TODO lets output result table here, not in result executor. same thing in // delete/insert // add to the planfragments count of modified tuples m_engine->m_tuplesModified += m_inputTable->activeTupleCount(); return true; }
void AntiCacheDB::initializeNVM() { char nvm_file_name[150]; char partition_str[50]; m_totalBlocks = 0; #ifdef ANTICACHE_DRAM VOLT_INFO("Allocating anti-cache in DRAM."); m_NVMBlocks = new char[aligned_file_size]; return; #endif // use executor context to figure out which partition we are at int partition_id = (int)m_executorContext->getPartitionId(); sprintf(partition_str, "%d", partition_id); strcpy(nvm_file_name, m_dbDir.c_str()); // there will be one NVM anti-cache file per partition, saved in /mnt/pmfs/anticache-XX strcat(nvm_file_name, "/anticache-"); strcat(nvm_file_name, partition_str); VOLT_INFO("Creating nvm file: %s", nvm_file_name); nvm_file = fopen(nvm_file_name, "w"); if(nvm_file == NULL) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to open PMFS file %s: %s.", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } fclose(nvm_file); nvm_file = fopen(nvm_file_name, "rw+"); if(nvm_file == NULL) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to open PMFS file %s: %s.", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } nvm_fd = fileno(nvm_file); if(nvm_fd < 0) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to allocate anti-cache PMFS file in directory %s.", m_dbDir.c_str()); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } if(ftruncate(nvm_fd, NVM_FILE_SIZE) < 0) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to ftruncate anti-cache PMFS file %s: %s", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } //off_t aligned_file_size = (((NVM_FILE_SIZE) + MMAP_PAGE_SIZE - 1) / MMAP_PAGE_SIZE * MMAP_PAGE_SIZE); off_t aligned_file_size = NVM_FILE_SIZE; m_NVMBlocks = (char*)mmap(NULL, aligned_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, nvm_fd, 0); if(m_NVMBlocks == MAP_FAILED) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to mmap PMFS file %s: %s", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } close(nvm_fd); // can safely close file now, mmap creates new reference /* // write out NULL characters to ensure entire file has been fetchted from memory for(int i = 0; i < NVM_FILE_SIZE; i++) { m_NVMBlocks[i] = '\0'; } */ }
/** * Reserve some tuples when an eviction requested. */ void EvictionIterator::reserve(int64_t amount) { VOLT_DEBUG("amount: %ld\n", amount); char* addr = NULL; PersistentTable* ptable = static_cast<PersistentTable*>(table); int tuple_size = ptable->m_schema->tupleLength() + TUPLE_HEADER_SIZE; int active_tuple = (int)ptable->activeTupleCount(); int evict_num = 0; int64_t used_tuple = ptable->usedTupleCount(); #ifdef ANTICACHE_TIMESTAMPS_PRIME uint32_t tuples_per_block = ptable->m_tuplesPerBlock; #endif if (active_tuple) evict_num = (int)(amount / (tuple_size + ptable->nonInlinedMemorySize() / active_tuple)); else evict_num = (int)(amount / tuple_size); VOLT_DEBUG("Count: %lu %lu\n", ptable->usedTupleCount(), ptable->activeTupleCount()); if (evict_num > active_tuple) evict_num = active_tuple; int pick_num = evict_num * RANDOM_SCALE; int block_num = (int)ptable->m_data.size(); int block_size = ptable->m_tuplesPerBlock; int location_size; #ifndef ANTICACHE_TIMESTAMPS_PRIME int block_location; #endif srand((unsigned int)time(0)); VOLT_INFO("evict pick num: %d %d\n", evict_num, pick_num); VOLT_INFO("active_tuple: %d\n", active_tuple); VOLT_INFO("block number: %d\n", block_num); m_size = 0; current_tuple_id = 0; #ifdef ANTICACHE_TIMESTAMPS_PRIME int pick_num_block = (int)(((int64_t)pick_num * tuples_per_block) / used_tuple); int last_full_block = (int)(used_tuple / block_size); VOLT_INFO("LOG: %d %d %ld\n", last_full_block, tuples_per_block, used_tuple); int last_block_size = (int)(used_tuple % block_size); int pick_num_last_block = pick_num - pick_num_block * last_full_block; #endif // If we'll evict the entire table, we should do a scan instead of sampling. // The main reason we should do that is to past the test... if (evict_num < active_tuple) { candidates = new EvictionTuple[pick_num]; #ifdef ANTICACHE_TIMESTAMPS_PRIME for (int i = 0; i < last_full_block; ++i) { /** * if this is a beginning of a loop of scan, find a proper step to let it sample tuples from almost the whole block * TODO: Here we use a method that every time try a different prime number from what we use last time. Is it better? * That would need further analysis. */ if (ptable->m_stepPrime[i] < 0) { int ideal_step = (rand() % 5) * tuples_per_block / pick_num_block; int old_prime = - ptable->m_stepPrime[i]; for (int j = prime_size - 1; j >= 0; --j) { if (prime_list[j] != old_prime && (tuples_per_block % prime_list[j]) > 0) { ptable->m_stepPrime[i] = prime_list[j]; VOLT_TRACE("DEBUG: %d %d\n", tuples_per_block, ptable->m_stepPrime[i]); } if (prime_list[j] <= ideal_step) break; } VOLT_INFO("Prime of block %d: %d %d\n", i, tuples_per_block, ptable->m_stepPrime[i]); } // now scan the block with a step of we select. // if we go across the boundry, minus it back to the beginning (like a mod operation) int step_prime = ptable->m_stepPrime[i]; int step_offset = step_prime * tuple_size; int block_size_bytes = block_size * tuple_size; addr = ptable->m_data[i] + ptable->m_evictPosition[i]; uint64_t end_of_block = (uint64_t)ptable->m_data[i] + block_size_bytes; bool flag_new = false; for (int j = 0; j < pick_num_block; ++j) { VOLT_TRACE("Flip addr: %p %p %lu\n", addr, ptable->m_data[i], ((uint64_t)addr - (uint64_t)ptable->m_data[i]) / 1024); current_tuple->move(addr); if (current_tuple->isActive()) { candidates[m_size].setTuple(current_tuple->getTimeStamp(), addr); m_size++; } addr += step_offset; if ((uint64_t)addr >= end_of_block) addr -= block_size_bytes; if (addr == ptable->m_data[i]) flag_new = true; } int new_position = (int)((uint64_t)addr - (uint64_t)ptable->m_data[i]); ptable->m_evictPosition[i] = new_position; if (flag_new) ptable->m_stepPrime[i] = - ptable->m_stepPrime[i]; } if (last_full_block < block_num) { addr = ptable->m_data[last_full_block]; char* current_addr; for (int j = 0; j < pick_num_last_block; ++j) { current_addr = addr + (rand() % last_block_size) * tuple_size; current_tuple->move(current_addr); if (!current_tuple->isActive() || current_tuple->isEvicted()) continue; candidates[m_size].setTuple(current_tuple->getTimeStamp(), current_addr); m_size++; } } #else for (int i = 0; i < pick_num; i++) { // should we use a faster random generator? block_location = rand() % block_num; addr = ptable->m_data[block_location]; if ((block_location + 1) * block_size > used_tuple) location_size = (int)(used_tuple - block_location * block_size); else location_size = block_size; addr += (rand() % location_size) * tuple_size; current_tuple->move(addr); VOLT_DEBUG("Flip addr: %p\n", addr); if (!current_tuple->isActive() || current_tuple->isEvicted()) continue; candidates[m_size].setTuple(current_tuple->getTimeStamp(), addr); m_size++; } #endif } else { candidates = new EvictionTuple[active_tuple]; for (int i = 0; i < block_num; ++i) { addr = ptable->m_data[i]; if ((i + 1) * block_size > ptable->usedTupleCount()) location_size = (int)(ptable->usedTupleCount() - i * block_size); else location_size = block_size; for (int j = 0; j < location_size; j++) { current_tuple->move(addr); if (!current_tuple->isActive() || current_tuple->isEvicted()) { addr += tuple_size; continue; } VOLT_TRACE("Flip addr: %p\n", addr); candidates[m_size].setTuple(current_tuple->getTimeStamp(), addr); m_size++; addr += tuple_size; } } } sort(candidates, candidates + m_size, less <EvictionTuple>()); //VOLT_INFO("Size of eviction candidates: %lu %d %d\n", (long unsigned int)m_size, activeN, evictedN); }
void NVMAntiCacheDB::initializeDB() { char nvm_file_name[150]; char partition_str[50]; m_blockIndex = 0; m_nextFreeBlock = 0; m_monoBlockID = 0; // TODO: Make DRAM based store a separate type #ifdef ANTICACHE_DRAM VOLT_INFO("Allocating anti-cache in DRAM."); m_NVMBlocks = new char[m_maxDBSize]; return; #endif int partition_id; // use executor context to figure out which partition we are at // if there is no executor context, assume this is a test and let it go if (!m_executorContext) { VOLT_WARN("NVMAntiCacheDB has no executor context. If this is an EE test, don't worry\n"); partition_id = 0; } else { partition_id = (int)m_executorContext->getPartitionId(); } sprintf(partition_str, "%d", partition_id); strcpy(nvm_file_name, m_dbDir.c_str()); // there will be one NVM anti-cache file per partition, saved in /mnt/pmfs/anticache-XX strcat(nvm_file_name, "/anticache-"); strcat(nvm_file_name, partition_str); VOLT_INFO("Creating size %ld nvm file: %s", m_maxDBSize, nvm_file_name); nvm_file = fopen(nvm_file_name, "w"); if(nvm_file == NULL) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to open PMFS file %s: %s.", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } fclose(nvm_file); nvm_file = fopen(nvm_file_name, "rw+"); if(nvm_file == NULL) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to open PMFS file %s: %s.", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } nvm_fd = fileno(nvm_file); if(nvm_fd < 0) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to allocate anti-cache PMFS file in directory %s.", m_dbDir.c_str()); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } if(ftruncate(nvm_fd, m_maxDBSize) < 0) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to ftruncate anti-cache PMFS file %s: %s", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } //off_t aligned_file_size = (((NVM_FILE_SIZE) + MMAP_PAGE_SIZE - 1) / MMAP_PAGE_SIZE * MMAP_PAGE_SIZE); off_t aligned_file_size = (off_t)m_maxDBSize; m_NVMBlocks = (char*)mmap(NULL, aligned_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, nvm_fd, 0); if(m_NVMBlocks == MAP_FAILED) { VOLT_ERROR("Anti-Cache initialization error."); VOLT_ERROR("Failed to mmap PMFS file %s: %s", nvm_file_name, strerror(errno)); throwFatalException("Failed to initialize anti-cache PMFS file in directory %s.", m_dbDir.c_str()); } close(nvm_fd); // can safely close file now, mmap creates new reference // write out NULL characters to ensure entire file has been fetchted from memory for(int i = 0; i < m_maxDBSize; i++) { m_NVMBlocks[i] = '\0'; } }