diff --git a/src/ee/anticache/AntiCacheDB.cpp b/src/ee/anticache/AntiCacheDB.cpp index c5a488e727..3b2224d033 100644 --- a/src/ee/anticache/AntiCacheDB.cpp +++ b/src/ee/anticache/AntiCacheDB.cpp @@ -39,51 +39,51 @@ using namespace std; namespace voltdb { - AntiCacheBlock::AntiCacheBlock(int16_t blockId, Dbt value) { - m_buf = (char *) value.get_data(); - - int16_t id = *((int16_t *)m_buf); - long bufLen_ = sizeof(int16_t); - std::string tableName = m_buf + bufLen_; - bufLen_ += tableName.size()+1; - long size = *((long *)(m_buf+bufLen_)); - bufLen_+=sizeof(long); - char * data = m_buf + bufLen_; - bufLen_ += size; -// for(int i=0;i 0 && m_buf != NULL){ - delete m_buf; + delete m_buf; } } BerkeleyDBBlock::~BerkeleyDBBlock() { - delete [] serialized_data; + delete [] serialized_data; } AntiCacheDB::AntiCacheDB(ExecutorContext *ctx, std::string db_dir, long blockSize) : @@ -130,7 +130,7 @@ void AntiCacheDB::initializeBerkeleyDB() { } } - void AntiCacheDB::initializeNVM() { +void AntiCacheDB::initializeNVM() { char nvm_file_name[150]; char partition_str[50]; @@ -140,7 +140,7 @@ void AntiCacheDB::initializeBerkeleyDB() { #ifdef ANTICACHE_DRAM VOLT_INFO("Allocating anti-cache in DRAM."); m_NVMBlocks = new char[aligned_file_size]; - return; + return; #endif // use executor context to figure out which partition we are at @@ -233,8 +233,7 @@ void AntiCacheDB::shutdownBerkeleyDB() { } } -void AntiCacheDB::shutdownNVM() -{ +void AntiCacheDB::shutdownNVM() { fclose(nvm_file); #ifdef ANTICACHE_DRAM @@ -264,27 +263,27 @@ void AntiCacheDB::writeBlockBerkeleyDB(const std::string tableName, char * databuf_ = new char [size+tableName.size() + 1+sizeof(blockId)+sizeof(size)]; - memset(databuf_, 0, size+tableName.size() + 1+sizeof(blockId)+sizeof(size)); - // Now pack the data into a single contiguous memory location - // for storage. - long bufLen_ = 0; - long dataLen = 0; - dataLen = sizeof(blockId); - memcpy(databuf_, &blockId, dataLen); - bufLen_ += dataLen; - dataLen = tableName.size() + 1; - memcpy(databuf_ + bufLen_, tableName.c_str(), dataLen); - bufLen_ += dataLen; - dataLen = sizeof(size); - memcpy(databuf_ + bufLen_, &size, dataLen); - bufLen_ += dataLen; - dataLen = size; - memcpy(databuf_ + bufLen_, data, dataLen); - bufLen_ += dataLen; + memset(databuf_, 0, size+tableName.size() + 1+sizeof(blockId)+sizeof(size)); + // Now pack the data into a single contiguous memory location + // for storage. + long bufLen_ = 0; + long dataLen = 0; + dataLen = sizeof(blockId); + memcpy(databuf_, &blockId, dataLen); + bufLen_ += dataLen; + dataLen = tableName.size() + 1; + memcpy(databuf_ + bufLen_, tableName.c_str(), dataLen); + bufLen_ += dataLen; + dataLen = sizeof(size); + memcpy(databuf_ + bufLen_, &size, dataLen); + bufLen_ += dataLen; + dataLen = size; + memcpy(databuf_ + bufLen_, data, dataLen); + bufLen_ += dataLen; Dbt value; - value.set_data(databuf_); - value.set_size(static_cast(bufLen_)); + value.set_data(databuf_); + value.set_size(static_cast(bufLen_)); VOLT_INFO("Writing out a block #%d to anti-cache database [tuples=%d / size=%ld]", @@ -325,10 +324,10 @@ AntiCacheBlock AntiCacheDB::readBlockBerkeleyDB(int16_t blockId) { } void AntiCacheDB::writeBlockNVM(const std::string tableName, - int16_t blockId, - const int tupleCount, - const char* data, - const long size) { + int16_t blockId, + const int tupleCount, + const char* data, + const long size) { //int index = getFreeNVMBlockIndex(); //char* block = getNVMBlock(index); @@ -347,15 +346,14 @@ AntiCacheBlock AntiCacheDB::readBlockNVM(std::string tableName, int16_t blockId) std::map >::iterator itr; itr = m_blockMap.find(blockId); - if (itr == m_blockMap.end()) - { + 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); + VOLT_INFO("Reading NVM block: ID = %d, index = %d, size = %d", blockId, blockIndex, itr->second.second); char* block_ptr = getNVMBlock(blockIndex); char* block = new char[itr->second.second]; @@ -377,9 +375,9 @@ void AntiCacheDB::writeBlock(const std::string tableName, const long size) { #ifdef ANTICACHE_NVM - return writeBlockNVM(tableName, blockId, tupleCount, data, size); + return writeBlockNVM(tableName, blockId, tupleCount, data, size); #else - return writeBlockBerkeleyDB(tableName, blockId, tupleCount, data, size); + return writeBlockBerkeleyDB(tableName, blockId, tupleCount, data, size); #endif } @@ -410,14 +408,13 @@ char* AntiCacheDB::getNVMBlock(int index) { return (m_NVMBlocks+(index*NVM_BLOCK_SIZE)); } -int AntiCacheDB::getFreeNVMBlockIndex() -{ +int AntiCacheDB::getFreeNVMBlockIndex() { int free_index = 0; if(m_NVMBlockFreeList.size() > 0) { free_index = m_NVMBlockFreeList.back(); - m_NVMBlockFreeList.pop_back(); + m_NVMBlockFreeList.pop_back(); } else { @@ -429,8 +426,7 @@ int AntiCacheDB::getFreeNVMBlockIndex() return free_index; } -void AntiCacheDB::freeNVMBlock(int index) -{ +void AntiCacheDB::freeNVMBlock(int index) { m_NVMBlockFreeList.push_back(index); //m_totalBlocks--; } diff --git a/src/ee/anticache/AntiCacheEvictionManager.cpp b/src/ee/anticache/AntiCacheEvictionManager.cpp index c6a0f79330..86aafccbd8 100644 --- a/src/ee/anticache/AntiCacheEvictionManager.cpp +++ b/src/ee/anticache/AntiCacheEvictionManager.cpp @@ -73,10 +73,15 @@ AntiCacheEvictionManager::AntiCacheEvictionManager(const VoltDBEngine *engine) { m_engine = engine; this->initEvictResultTable(); srand((int)time(NULL)); + + // Initialize EvictedTable Tuple + TupleSchema *evictedSchema = TupleSchema::createEvictedTupleSchema(); + m_evicted_tuple = new TableTuple(evictedSchema); } AntiCacheEvictionManager::~AntiCacheEvictionManager() { delete m_evictResultTable; + delete m_evicted_tuple; } void AntiCacheEvictionManager::initEvictResultTable() { @@ -165,7 +170,7 @@ bool AntiCacheEvictionManager::updateUnevictedTuple(PersistentTable* table, Tabl bool AntiCacheEvictionManager::updateTuple(PersistentTable* table, TableTuple* tuple, bool is_insert) { int SAMPLE_RATE = 1000; // aLRU sampling rate - if(table->getEvictedTable() == NULL || table->isBatchEvicted()) // no need to maintain chain for non-evictable tables or batch evicted tables + if (table->getEvictedTable() == NULL || table->isBatchEvicted()) // no need to maintain chain for non-evictable tables or batch evicted tables return true; //VOLT_INFO("updating LRU for %s", table->name().c_str()); @@ -177,15 +182,15 @@ bool AntiCacheEvictionManager::updateTuple(PersistentTable* table, TableTuple* t // this is an update, so we have to remove the previous entry in the chain if (!is_insert) { - if(rand() % SAMPLE_RATE != 0) + if (rand() % SAMPLE_RATE != 0) return true; assert(table->getNumTuplesInEvictionChain() > 0); -#ifdef ANTICACHE_REVERSIBLE_LRU + #ifdef ANTICACHE_REVERSIBLE_LRU removeTupleDoubleLinkedList(table, tuple, update_tuple_id); -#else + #else removeTupleSingleLinkedList(table, update_tuple_id); -#endif + #endif } if (table->getNumTuplesInEvictionChain() == 0) { // this is the first tuple in the chain @@ -207,10 +212,10 @@ bool AntiCacheEvictionManager::updateTuple(PersistentTable* table, TableTuple* t // update "next" pointer newest_tuple.setNextTupleInChain(update_tuple_id); -#ifdef ANTICACHE_REVERSIBLE_LRU + #ifdef ANTICACHE_REVERSIBLE_LRU // update "previous" pointer update_tuple.setPreviousTupleInChain(newest_tuple_id); -#endif + #endif // udpate oldest and newest pointers for the table table->setNewestTupleID(update_tuple_id); @@ -224,10 +229,10 @@ bool AntiCacheEvictionManager::updateTuple(PersistentTable* table, TableTuple* t // update "next" pointer newest_tuple.setNextTupleInChain(update_tuple_id); -#ifdef ANTICACHE_REVERSIBLE_LRU + #ifdef ANTICACHE_REVERSIBLE_LRU // update "previous" pointer update_tuple.setPreviousTupleInChain(newest_tuple_id); -#endif + #endif // insert the tuple we're updating to be the newest table->setNewestTupleID(update_tuple_id); @@ -245,11 +250,11 @@ bool AntiCacheEvictionManager::removeTuple(PersistentTable* table, TableTuple* t int current_tuple_id = table->getTupleID(tuple->address()); // the removeTuple() method called is dependent on whether it is a single or double linked list -#ifdef ANTICACHE_REVERSIBLE_LRU + #ifdef ANTICACHE_REVERSIBLE_LRU return removeTupleDoubleLinkedList(table, tuple, current_tuple_id); -#else + #else return removeTupleSingleLinkedList(table, current_tuple_id); -#endif + #endif } // for the double linked list we start from the tail of the chain and iterate backwards @@ -498,7 +503,7 @@ Table* AntiCacheEvictionManager::evictBlock(PersistentTable *table, long blockSi } bool AntiCacheEvictionManager::evictBlockToDisk(PersistentTable *table, const long block_size, int num_blocks) { - voltdb::Table* m_evictedTable = table->getEvictedTable(); + voltdb::Table* evictedTable = table->getEvictedTable(); int m_tuplesEvicted = table->getTuplesEvicted(); int m_blocksEvicted = table->getBlocksEvicted(); int64_t m_bytesEvicted = table->getBytesEvicted(); @@ -507,14 +512,14 @@ bool AntiCacheEvictionManager::evictBlockToDisk(PersistentTable *table, const lo int m_blocksWritten = table->getBlocksWritten(); int64_t m_bytesWritten = table->getBytesWritten(); - if (m_evictedTable == NULL) { + if (evictedTable == NULL) { throwFatalException("Trying to evict block from table '%s' before its "\ "EvictedTable has been initialized", table->name().c_str()); } VOLT_DEBUG("Evicting a block of size %ld bytes from table '%s' with %d tuples", block_size, table->name().c_str(), (int)table->allocatedTupleCount()); VOLT_DEBUG("%s Table Schema:\n%s", - m_evictedTable->name().c_str(), m_evictedTable->schema()->debug().c_str()); + evictedTable->name().c_str(), evictedTable->schema()->debug().c_str()); // get the AntiCacheDB instance from the executorContext AntiCacheDB* antiCacheDB = table->getAntiCacheDB(); @@ -533,8 +538,8 @@ bool AntiCacheEvictionManager::evictBlockToDisk(PersistentTable *table, const lo int16_t block_id = antiCacheDB->nextBlockId(); // create a new evicted table tuple based on the schema for the source tuple - TableTuple evicted_tuple = m_evictedTable->tempTuple(); - VOLT_DEBUG("Setting %s tuple blockId at offset %d", m_evictedTable->name().c_str(), 0); + TableTuple evicted_tuple = evictedTable->tempTuple(); + VOLT_DEBUG("Setting %s tuple blockId at offset %d", evictedTable->name().c_str(), 0); evicted_tuple.setNValue(0, ValueFactory::getSmallIntValue(block_id)); // Set the ID for this block evicted_tuple.setNValue(1, ValueFactory::getIntegerValue(0)); // set the tuple offset of this block @@ -544,7 +549,7 @@ bool AntiCacheEvictionManager::evictBlockToDisk(PersistentTable *table, const lo #ifdef VOLT_INFO_ENABLED boost::timer timer; -// int64_t origEvictedTableSize = m_evictedTable->activeTupleCount(); +// int64_t origEvictedTableSize = evictedTable->activeTupleCount(); #endif //size_t current_tuple_start_position; @@ -558,7 +563,7 @@ bool AntiCacheEvictionManager::evictBlockToDisk(PersistentTable *table, const lo num_tuples_evicted); int initSize = block.getSerializedSize(); - VOLT_DEBUG("Starting evictable tuple iterator for %s", name().c_str()); + VOLT_DEBUG("Starting evictable tuple iterator for %s", table->name().c_str()); while (evict_itr.hasNext() && (block.getSerializedSize() + MAX_EVICTED_TUPLE_SIZE < block_size)) { if(!evict_itr.next(tuple)) break; @@ -578,7 +583,7 @@ bool AntiCacheEvictionManager::evictBlockToDisk(PersistentTable *table, const lo VOLT_INFO("Tuple %d is already evicted. Skipping", table->getTupleID(tuple.address())); continue; } - VOLT_DEBUG("Evicting Tuple: %s", tuple.debug(name()).c_str()); + VOLT_DEBUG("Evicting Tuple: %s", tuple.debug(table->name()).c_str()); tuple.setEvictedTrue(); // Populate the evicted_tuple with the block id and tuple offset @@ -588,10 +593,10 @@ bool AntiCacheEvictionManager::evictBlockToDisk(PersistentTable *table, const lo evicted_tuple.setNValue(0, ValueFactory::getSmallIntValue(block_id)); evicted_tuple.setNValue(1, ValueFactory::getIntegerValue(num_tuples_evicted)); evicted_tuple.setEvictedTrue(); - VOLT_DEBUG("EvictedTuple: %s", evicted_tuple.debug(m_evictedTable->name()).c_str()); + VOLT_DEBUG("EvictedTuple: %s", evicted_tuple.debug(evictedTable->name()).c_str()); // Then add it to this table's EvictedTable - const void* evicted_tuple_address = static_cast(m_evictedTable)->insertEvictedTuple(evicted_tuple); + const void* evicted_tuple_address = static_cast(evictedTable)->insertEvictedTuple(evicted_tuple); VOLT_INFO("block address is %p", evicted_tuple_address); // Change all of the indexes to point to our new evicted tuple table->setEntryToNewAddressForAllIndexes(&tuple, evicted_tuple_address); @@ -604,7 +609,7 @@ VOLT_INFO("block address is %p", evicted_tuple_address); num_tuples_evicted++; VOLT_DEBUG("Added new evicted %s tuple to block #%d [tuplesEvicted=%d]", - name().c_str(), block_id, num_tuples_evicted); + table->name().c_str(), block_id, num_tuples_evicted); } // WHILE VOLT_DEBUG("Finished evictable tuple iterator for %s [tuplesEvicted=%d]", @@ -654,7 +659,7 @@ VOLT_INFO("block address is %p", evicted_tuple_address); block_id, table->name().c_str(), num_tuples_evicted, m_bytesEvicted, tuple_length); // VOLT_INFO("%s EvictedTable [origCount:%ld / newCount:%ld]", -// name().c_str(), (long)origEvictedTableSize, (long)m_evictedTable->activeTupleCount()); +// name().c_str(), (long)origEvictedTableSize, (long)evictedTable->activeTupleCount()); #endif } else { VOLT_WARN("No tuples were evicted from %s", table->name().c_str()); @@ -681,7 +686,7 @@ VOLT_INFO("block address is %p", evicted_tuple_address); } bool AntiCacheEvictionManager::evictBlockToDiskInBatch(PersistentTable *table, PersistentTable *childTable, const long block_size, int num_blocks) { - voltdb::Table* m_evictedTable = table->getEvictedTable(); + voltdb::Table* evictedTable = table->getEvictedTable(); voltdb::Table* child_evictedTable = childTable->getEvictedTable(); int m_tuplesEvicted = table->getTuplesEvicted(); int m_blocksEvicted = table->getBlocksEvicted(); @@ -691,14 +696,14 @@ bool AntiCacheEvictionManager::evictBlockToDiskInBatch(PersistentTable *table, P int m_blocksWritten = table->getBlocksWritten(); int64_t m_bytesWritten = table->getBytesWritten(); - if (m_evictedTable == NULL) { + if (evictedTable == NULL) { throwFatalException("Trying to evict block from table '%s' before its "\ "EvictedTable has been initialized", table->name().c_str()); } //VOLT_INFO("Evicting a block of size %ld bytes from table '%s' with %d tuples", // block_size, table->name().c_str(), (int)table->allocatedTupleCount()); // VOLT_DEBUG("%s Table Schema:\n%s", - // m_evictedTable->name().c_str(), m_evictedTable->schema()->debug().c_str()); + // evictedTable->name().c_str(), evictedTable->schema()->debug().c_str()); // get the AntiCacheDB instance from the executorContext AntiCacheDB* antiCacheDB = table->getAntiCacheDB(); @@ -723,8 +728,7 @@ bool AntiCacheEvictionManager::evictBlockToDiskInBatch(PersistentTable *table, P int child_blocksWritten = childTable->getBlocksWritten(); int64_t child_bytesWritten = childTable->getBytesWritten(); - for(int i = 0; i < num_blocks; i++) - { + for(int i = 0; i < num_blocks; i++) { // VOLT_INFO("Printing parent's LRU chain"); // this->printLRUChain(table, 4, true); // VOLT_INFO("Printing child's LRU chain"); @@ -733,8 +737,8 @@ bool AntiCacheEvictionManager::evictBlockToDiskInBatch(PersistentTable *table, P int16_t block_id = antiCacheDB->nextBlockId(); // create a new evicted table tuple based on the schema for the source tuple - TableTuple evicted_tuple = m_evictedTable->tempTuple(); - // VOLT_DEBUG("Setting %s tuple blockId at offset %d", m_evictedTable->name().c_str(), 0); + TableTuple evicted_tuple = evictedTable->tempTuple(); + // VOLT_DEBUG("Setting %s tuple blockId at offset %d", evictedTable->name().c_str(), 0); evicted_tuple.setNValue(0, ValueFactory::getSmallIntValue(block_id)); // Set the ID for this block evicted_tuple.setNValue(1, ValueFactory::getIntegerValue(0)); // set the tuple offset of this block @@ -839,10 +843,10 @@ bool AntiCacheEvictionManager::evictBlockToDiskInBatch(PersistentTable *table, P evicted_tuple.setNValue(0, ValueFactory::getSmallIntValue(block_id)); evicted_tuple.setNValue(1, ValueFactory::getIntegerValue(num_tuples_evicted)); evicted_tuple.setEvictedTrue(); - //VOLT_INFO("EvictedTuple: %s", evicted_tuple.debug(m_evictedTable->name()).c_str()); + //VOLT_INFO("EvictedTuple: %s", evicted_tuple.debug(evictedTable->name()).c_str()); // Then add it to this table's EvictedTable - const void* evicted_tuple_address = static_cast(m_evictedTable)->insertEvictedTuple(evicted_tuple); + const void* evicted_tuple_address = static_cast(evictedTable)->insertEvictedTuple(evicted_tuple); // Change all of the indexes to point to our new evicted tuple table->setEntryToNewAddressForAllIndexes(&tuple, evicted_tuple_address); @@ -973,7 +977,7 @@ bool AntiCacheEvictionManager::evictBlockToDiskInBatch(PersistentTable *table, P // block_id, table->name().c_str(), // num_tuples_evicted, m_bytesEvicted, tuple_length); // VOLT_INFO("%s EvictedTable [origCount:%ld / newCount:%ld]", -// name().c_str(), (long)origEvictedTableSize, (long)m_evictedTable->activeTupleCount()); +// name().c_str(), (long)origEvictedTableSize, (long)evictedTable->activeTupleCount()); // #endif } else { // VOLT_WARN("No tuples were evicted from %s", table->name().c_str()); @@ -1062,16 +1066,15 @@ bool AntiCacheEvictionManager::readEvictedBlock(PersistentTable *table, int16_t AntiCacheDB* antiCacheDB = table->getAntiCacheDB(); - try - { + try { AntiCacheBlock value = antiCacheDB->readBlock(table->name(), block_id); // allocate the memory for this block VOLT_INFO("block size is %ld - table Name %s", value.getSize(), table->name().c_str()); - char* unevicted_tuples = new char[value.getSize()]; + char* unevicted_tuples = new char[value.getSize()]; memcpy(unevicted_tuples, value.getData(), value.getSize()); - VOLT_INFO("*****************block id ************** %d", block_id); + VOLT_INFO("*****************block id ************** %d", block_id); ReferenceSerializeInput in(unevicted_tuples, 10485760); // Read in all the meta-data @@ -1251,6 +1254,67 @@ table->clearUnevictedBlocks(); return true; } +// ----------------------------------------- +// Evicted Access Tracking Methods +// ----------------------------------------- + +void AntiCacheEvictionManager::recordEvictedAccess(catalog::Table* catalogTable, TableTuple *tuple) { + // Create an evicted tuple from the current tuple address + // NOTE: This is necessary because the original table tuple and the evicted tuple + // do not have the same schema + m_evicted_tuple->move(tuple->address()); + + VOLT_DEBUG(stderr, "Recording evicted tuple access: %s\n", m_evicted_tuple->debug(catalogTable->name()).c_str()); + + // Determine the block id and tuple offset in the block using the EvictedTable tuple + int16_t block_id = peeker.peekSmallInt(m_evicted_tuple->getNValue(0)); + int32_t tuple_id = peeker.peekInteger(m_evicted_tuple->getNValue(1)); + + // Updated internal tracking info + m_evicted_tables.push_back(catalogTable); + m_evicted_block_ids.push_back(block_id); + m_evicted_offsets.push_back(tuple_id); + +} + +void AntiCacheEvictionManager::throwEvictedAccessException(int partition_id) { + // Do we really want to remove all the non-unique blockIds here? + m_evicted_block_ids.unique(); + + int num_block_ids = static_cast(m_evicted_block_ids.size()); + assert(num_block_ids > 0); + + VOLT_DEBUG("%d evicted blocks to read.", num_block_ids); + + int16_t* block_ids = new int16_t[num_block_ids]; + int32_t* tuple_ids = new int32_t[num_block_ids]; + + // copy the block ids into an array + int i = 0; + for(list::iterator itr = m_evicted_block_ids.begin(); itr != m_evicted_block_ids.end(); ++itr) { + block_ids[i++] = *itr; + VOLT_INFO("Marking block %d as being needed for uneviction", *itr); + } + + // copy the tuple offsets into an array + i = 0; + for(list::iterator itr = m_evicted_offsets.begin(); itr != m_evicted_offsets.end(); ++itr) { + tuple_ids[i++] = *itr; + } + + // HACK + catalog::Table *catalogTable = m_evicted_tables.front(); + + fprintf(stderr, "EVICTED ACCESS FROM %s\n", catalogTable->name().c_str()); + + // Do we really want to throw this here? + // FIXME We need to support multiple tables in the exception data + VOLT_INFO("Throwing EvictedTupleAccessException for table %s (%d)", catalogTable->name().c_str(), catalogTable->relativeIndex()); + throw EvictedTupleAccessException(catalogTable->relativeIndex(), num_block_ids, block_ids, tuple_ids, partition_id); +} + + + // ----------------------------------------- // Debugging Unility Methods // ----------------------------------------- diff --git a/src/ee/anticache/AntiCacheEvictionManager.h b/src/ee/anticache/AntiCacheEvictionManager.h index febf73b6bd..b581e55df8 100644 --- a/src/ee/anticache/AntiCacheEvictionManager.h +++ b/src/ee/anticache/AntiCacheEvictionManager.h @@ -27,10 +27,15 @@ #ifndef ANTICACHEEVICTIONMANAGER_H #define ANTICACHEEVICTIONMANAGER_H +#include "catalog/table.h" #include "storage/TupleIterator.h" #include "anticache/EvictionIterator.h" #include "common/tabletuple.h" #include "execution/VoltDBEngine.h" +#include "common/NValue.hpp" +#include "common/ValuePeeker.hpp" + +#include namespace voltdb { @@ -57,6 +62,21 @@ class AntiCacheEvictionManager { bool readEvictedBlock(PersistentTable *table, int16_t block_id, int32_t tuple_offset); //int numTuplesInEvictionList(); + // ----------------------------------------- + // Evicted Access Tracking Methods + // ----------------------------------------- + + inline void initEvictedAccessTracker() { + m_evicted_tables.clear(); + m_evicted_block_ids.clear(); + m_evicted_offsets.clear(); + } + inline bool hasEvictedAccesses() const { + return (m_evicted_block_ids.empty() == false); + } + void recordEvictedAccess(catalog::Table* catalogTable, TableTuple *tuple); + void throwEvictedAccessException(int partition_id); + protected: void initEvictResultTable(); Table *m_evictResultTable; @@ -71,6 +91,14 @@ class AntiCacheEvictionManager { void printLRUChain(PersistentTable* table, int max, bool forward); char *itoa(uint32_t i); + // Used at runtime to track what evicted tuples we touch and throw an exception + ValuePeeker peeker; + TableTuple* m_evicted_tuple; + + std::list m_evicted_tables; + std::list m_evicted_block_ids; + std::list m_evicted_offsets; + }; // AntiCacheEvictionManager class diff --git a/src/ee/common/tabletuple.h b/src/ee/common/tabletuple.h index 2558a2d1f5..33fd87cdd5 100644 --- a/src/ee/common/tabletuple.h +++ b/src/ee/common/tabletuple.h @@ -90,10 +90,11 @@ namespace voltdb { #else #define TUPLE_HEADER_SIZE 1 #endif - + #define DELETED_MASK 1 #define DIRTY_MASK 2 -#define EVICTED_MASK 4 +#define MIGRATED_MASK 4 +#define EVICTED_MASK 8 class TableColumn; diff --git a/src/ee/execution/VoltDBEngine.cpp b/src/ee/execution/VoltDBEngine.cpp index 161498a2b8..e447347737 100644 --- a/src/ee/execution/VoltDBEngine.cpp +++ b/src/ee/execution/VoltDBEngine.cpp @@ -207,18 +207,18 @@ VoltDBEngine::~VoltDBEngine() { typedef pair CDPair; BOOST_FOREACH (CDPair cdPair, m_catalogDelegates){ - delete cdPair.second; -} + delete cdPair.second; + } m_catalogDelegates.clear(); BOOST_FOREACH (TIDPair tidPair, m_snapshottingTables){ - tidPair.second->decrementRefcount(); -} + tidPair.second->decrementRefcount(); + } m_snapshottingTables.clear(); BOOST_FOREACH (TIDPair tidPair, m_exportingTables){ - tidPair.second->decrementRefcount(); -} + tidPair.second->decrementRefcount(); + } m_exportingTables.clear(); delete m_topend; @@ -331,7 +331,7 @@ int VoltDBEngine::executeQuery(int64_t planfragmentId, m_executorContext->getTrackerManager(); tracker = trackerMgr->getTracker(txnId); } - + // PAVLO: If we see a SendPlanNode with the "fake" flag set to true, // then we won't really execute it and instead will send back the // number of tuples that we modified @@ -2057,6 +2057,12 @@ int VoltDBEngine::antiCacheMergeBlocks(int32_t tableId) { return (retval); } +void VoltDBEngine::antiCacheResetEvictedTupleTracker() { + // Anti-Cache Evicted Tuple Tracking + AntiCacheEvictionManager* eviction_manager = m_executorContext->getAntiCacheEvictionManager(); + eviction_manager->initEvictedAccessTracker(); +} + #else void VoltDBEngine::antiCacheInitialize(std::string dbDir, long blockSize) const { diff --git a/src/ee/execution/VoltDBEngine.h b/src/ee/execution/VoltDBEngine.h index 392e8eb88f..a7b44b18e3 100644 --- a/src/ee/execution/VoltDBEngine.h +++ b/src/ee/execution/VoltDBEngine.h @@ -141,7 +141,7 @@ class __attribute__((visibility("default"))) VoltDBEngine { } VoltDBEngine(Topend *topend, LogProxy *logProxy); - + bool initialize( int32_t clusterIndex, int32_t siteId, @@ -297,12 +297,13 @@ class __attribute__((visibility("default"))) VoltDBEngine { // ------------------------------------------------- void antiCacheInitialize(std::string dbDir, long blockSize) const; -#ifdef ANTICACHE - int antiCacheReadBlocks(int32_t tableId, int numBlocks, int16_t blockIds[], int32_t tupleOffsets[]); - int antiCacheEvictBlock(int32_t tableId, long blockSize, int numBlocks); - int antiCacheEvictBlockInBatch(int32_t tableId, int32_t childTableId, long blockSize, int numBlocks); - int antiCacheMergeBlocks(int32_t tableId); -#endif + #ifdef ANTICACHE + int antiCacheReadBlocks(int32_t tableId, int numBlocks, int16_t blockIds[], int32_t tupleOffsets[]); + int antiCacheEvictBlock(int32_t tableId, long blockSize, int numBlocks); + int antiCacheEvictBlockInBatch(int32_t tableId, int32_t childTableId, long blockSize, int numBlocks); + int antiCacheMergeBlocks(int32_t tableId); + void antiCacheResetEvictedTupleTracker(); + #endif // ------------------------------------------------- @@ -315,27 +316,27 @@ class __attribute__((visibility("default"))) VoltDBEngine { void ARIESInitialize(std::string dbDir, std::string logFile) ; std::string getARIESDir(){ - return m_ARIESDir; + return m_ARIESDir; } void setARIESDir(std::string dbDir){ - m_ARIESDir = dbDir; + m_ARIESDir = dbDir; } std::string getARIESFile() { - return m_ARIESFile; + return m_ARIESFile; } void setARIESFile(std::string logFile) { - m_ARIESFile = logFile; + m_ARIESFile = logFile; } bool isARIESEnabled() { - return m_ARIESEnabled; + return m_ARIESEnabled; } void setARIESEnabled(bool status) { - m_ARIESEnabled = status; + m_ARIESEnabled = status; } @@ -448,7 +449,7 @@ class __attribute__((visibility("default"))) VoltDBEngine { */ void processRecoveryMessage(RecoveryProtoMsg *message); -#ifdef ARIES + #ifdef ARIES // do aries recovery - startup work. void doAriesRecovery(char *logData, size_t length, int64_t replay_txnid); @@ -461,7 +462,7 @@ class __attribute__((visibility("default"))) VoltDBEngine { size_t getArieslogBufferLength(); void rewindArieslogBuffer(); -#endif + #endif /** * Perform an action on behalf of Export. @@ -600,7 +601,7 @@ class __attribute__((visibility("default"))) VoltDBEngine { std::string m_ARIESDir ; std::string m_ARIESFile ; - bool m_isRecovering; // are we currently recovering? + bool m_isRecovering; // are we currently recovering? int64_t m_batchFragmentIdsContainer[MAX_BATCH_COUNT]; /** PAVLO **/ @@ -666,11 +667,11 @@ inline void VoltDBEngine::resetReusedResultOutputBuffer(const size_t headerSize) *reinterpret_cast(m_exceptionBuffer) = voltdb::VOLT_EE_EXCEPTION_TYPE_NONE; //#ifdef ARIES - // XXX: I don't see function being called anywhere else beside when exceptions are thrown, - // not sure if this initialization even ever happens unless a serializeexception is thrown. - m_arieslogOutput.initializeWithPosition(m_arieslogBuffer, - m_arieslogBufferCapacity, headerSize); - //#endif + // XXX: I don't see function being called anywhere else beside when exceptions are thrown, + // not sure if this initialization even ever happens unless a serializeexception is thrown. + m_arieslogOutput.initializeWithPosition(m_arieslogBuffer, + m_arieslogBufferCapacity, headerSize); + //#endif } void VoltDBEngine::releaseUndoToken(int64_t undoToken){ @@ -691,7 +692,7 @@ void VoltDBEngine::releaseUndoToken(int64_t undoToken){ VOLT_WARN("Undo Token: %ld", m_currentUndoQuantum->getUndoToken()); if(table != NULL){ - //VOLT_WARN("Syncing Table %s",table->name().c_str()); + //VOLT_WARN("Syncing Table %s",table->name().c_str()); /*Pool* pool = table->getPool(); if(pool != NULL) MMAPMemoryManager* m_pool_manager = pool->getPoolManager(); diff --git a/src/ee/executors/abstractexecutor.cpp b/src/ee/executors/abstractexecutor.cpp index ea99c0ed6b..9f08641240 100644 --- a/src/ee/executors/abstractexecutor.cpp +++ b/src/ee/executors/abstractexecutor.cpp @@ -62,6 +62,8 @@ namespace voltdb { bool AbstractExecutor::init(VoltDBEngine *engine, const catalog::Database* catalog_db, int* tempTableMemoryInBytes) { assert (abstract_node); + executor_context = engine->getExecutorContext(); + // // Grab the input tables directly from this node's children // diff --git a/src/ee/executors/abstractexecutor.h b/src/ee/executors/abstractexecutor.h index c008adf999..24ce3e9551 100644 --- a/src/ee/executors/abstractexecutor.h +++ b/src/ee/executors/abstractexecutor.h @@ -49,6 +49,7 @@ #include #include "common/common.h" #include "common/valuevector.h" +#include "common/executorcontext.hpp" #include "storage/table.h" #include "storage/temptable.h" #include "storage/ReadWriteTracker.h" @@ -58,6 +59,7 @@ namespace voltdb { class VoltDBEngine; +class ExecutorContext; class ReadWriteTracker; /** @@ -118,6 +120,7 @@ class AbstractExecutor { // execution engine owns the plannode allocation. AbstractPlanNode* abstract_node; TempTable *tmp_output_table; + ExecutorContext *executor_context; // cache to avoid runtime virtual function call bool needs_outputtable_clear_cached; diff --git a/src/ee/executors/deleteexecutor.cpp b/src/ee/executors/deleteexecutor.cpp index be834f615e..38ad4c7642 100644 --- a/src/ee/executors/deleteexecutor.cpp +++ b/src/ee/executors/deleteexecutor.cpp @@ -101,7 +101,7 @@ bool DeleteExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *trac // count the truncated tuples as deleted m_engine->m_tuplesModified += m_inputTable->activeTupleCount(); -#ifdef ARIES + #ifdef ARIES if(m_engine->isARIESEnabled()){ // no need of persistency check, m_targetTable is // always persistent for deletes @@ -142,7 +142,7 @@ bool DeleteExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *trac logrecord = NULL; } -#endif + #endif //m_engine->context().incrementTuples(m_targetTable->activeTupleCount()); // actually delete all the tuples @@ -171,7 +171,7 @@ bool DeleteExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *trac tracker->markTupleWritten(m_targetTable, &m_targetTuple); } -#ifdef ARIES + #ifdef ARIES if(m_engine->isARIESEnabled()){ // no need of persistency check, m_targetTable is // always persistent for deletes @@ -246,7 +246,7 @@ bool DeleteExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *trac } } -#endif + #endif // Delete from target table if (!m_targetTable->deleteTuple(m_targetTuple, true)) { diff --git a/src/ee/executors/indexscanexecutor.cpp b/src/ee/executors/indexscanexecutor.cpp index 4e233daaac..e61631cf9d 100644 --- a/src/ee/executors/indexscanexecutor.cpp +++ b/src/ee/executors/indexscanexecutor.cpp @@ -67,11 +67,7 @@ #include "storage/persistenttable.h" #ifdef ANTICACHE -#include "anticache/EvictedTupleAccessException.h" -#include "common/NValue.hpp" -#include "common/ValuePeeker.hpp" -#include -#include +#include "anticache/AntiCacheEvictionManager.h" #endif using namespace voltdb; @@ -508,24 +504,11 @@ bool IndexScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *t return false; } + // Anti-Cache Variables #ifdef ANTICACHE - // anti-cache variables - //EvictedTable* m_evictedTable = static_cast (m_targetTable->getEvictedTable()); - list evicted_block_ids; - list evicted_offsets; - - ValuePeeker peeker; - //TableTuple m_evicted_tuple; - - TableTuple* m_evicted_tuple = NULL; - - if (m_targetTable->getEvictedTable() != NULL) - m_evicted_tuple = new TableTuple(m_targetTable->getEvictedTable()->schema()); - - int16_t block_id; - int32_t tuple_id; - #endif - + AntiCacheEvictionManager* eviction_manager = m_targetTable->m_executorContext->getAntiCacheEvictionManager(); + bool hasEvictedTable = (m_targetTable->getEvictedTable() != NULL); + #endif // // We have to different nextValue() methods for different lookup types @@ -545,23 +528,16 @@ bool IndexScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *t #ifdef ANTICACHE // We are pointing to an entry for an evicted tuple if (m_tuple.isEvicted()) { - VOLT_INFO("Tuple in index scan is evicted %s", m_targetTable->name().c_str()); - if (m_evicted_tuple == NULL) { - VOLT_INFO("Evicted Tuple found in table without EvictedTable!"); - } else { - // create an evicted tuple from the current tuple address - // NOTE: This is necessary because the original table tuple and the evicted tuple do not have the same schema - m_evicted_tuple->move(m_tuple.address()); - - // determine the block id and tuple offset in the block using the EvictedTable tuple - block_id = peeker.peekSmallInt(m_evicted_tuple->getNValue(0)); - tuple_id = peeker.peekInteger(m_evicted_tuple->getNValue(1)); + VOLT_INFO("Tuple in index scan is evicted %s", m_targetTable->name().c_str()); - evicted_block_ids.push_back(block_id); - evicted_offsets.push_back(tuple_id); - } - }else{ - VOLT_INFO("yay! tuple is in memory"); + // Tell the EvictionManager's internal tracker that we touched this mofo + eviction_manager->recordEvictedAccess(m_catalogTable, &m_tuple); + + // Pavlo: 2014-07-09 + // If the tuple is evicted, then we can't continue with the rest of stuff below us. + // There is nothing else we can do with it (i.e., check expressions). + // I don't know why this wasn't here in the first place? + continue; } #endif @@ -569,8 +545,7 @@ bool IndexScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *t // First check whether the end_expression is now false // if (end_expression != NULL && - end_expression->eval(&m_tuple, NULL).isFalse()) - { + end_expression->eval(&m_tuple, NULL).isFalse()) { VOLT_DEBUG("End Expression evaluated to false, stopping scan"); break; } @@ -578,27 +553,31 @@ bool IndexScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *t // Then apply our post-predicate to do further filtering // if (post_expression == NULL || - post_expression->eval(&m_tuple, NULL).isTrue()) - { + post_expression->eval(&m_tuple, NULL).isTrue()) { + + #ifdef ANTICACHE + if (hasEvictedTable) { + // update the tuple in the LRU eviction chain + eviction_manager->updateTuple(m_targetTable, &m_tuple, false); + } + #endif + // // Inline Distinct // - if (m_distinctNode != NULL) - { + if (m_distinctNode != NULL) { NValue value = m_tuple.getNValue(m_distinctColumn); // insert returns a pair. // Don't want to continue if insert failed (value // was already present). - if (m_distinctValueSet.insert(value).second == false) - { + if (m_distinctValueSet.insert(value).second == false) { continue; } } // // Inline Aggregate // - if (m_aggregateNode != NULL) - { + if (m_aggregateNode != NULL) { // search for a min or max value. // m_aggregateCompareValue is either "greater-than" or // "less-than". @@ -607,44 +586,34 @@ bool IndexScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *t m_tuple.getNValue(m_aggregateColumnIdx).op_lessThan(aggregate_value).isTrue() : m_tuple.getNValue(m_aggregateColumnIdx).op_greaterThan(aggregate_value).isTrue()) { - aggregate_value = - m_tuple.getNValue(m_aggregateColumnIdx); + aggregate_value = m_tuple.getNValue(m_aggregateColumnIdx); aggregate_tuple_address = m_tuple.address(); aggregate_isset = true; } - // - // Inline Projection - // Project (or replace) values from input tuple - // - } - else if (m_projectionNode != NULL) - { + // + // Inline Projection + // Project (or replace) values from input tuple + // + } else if (m_projectionNode != NULL) { TableTuple &temp_tuple = m_outputTable->tempTuple(); - if (m_projectionAllTupleArray != NULL) - { + if (m_projectionAllTupleArray != NULL) { VOLT_DEBUG("sweet, all tuples"); - for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) - { + for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) { temp_tuple.setNValue(ctr, m_tuple.getNValue(m_projectionAllTupleArray[ctr])); } - } - else - { - for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) - { + } else { + for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) { temp_tuple.setNValue(ctr, m_projectionExpressions[ctr]->eval(&m_tuple, NULL)); } } m_outputTable->insertTupleNonVirtual(temp_tuple); tuples_written++; - } - else - // - // Straight Insert - // - { + // + // Straight Insert + // + } else { // // Try to put the tuple into our output table // @@ -652,111 +621,65 @@ bool IndexScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *t tuples_written++; } -#ifdef ANTICACHE - if(m_targetTable->getEvictedTable() != NULL) - { - if(!m_tuple.isEvicted()) - { - // update the tuple in the LRU eviction chain - AntiCacheEvictionManager* eviction_manager = m_targetTable->m_executorContext->getAntiCacheEvictionManager(); - eviction_manager->updateTuple(m_targetTable, &m_tuple, false); - } - } -#endif - - // // INLINE LIMIT // - if (m_limitNode != NULL && tuples_written >= m_limitSize) - { + if (m_limitNode != NULL && tuples_written >= m_limitSize) { VOLT_DEBUG("Hit limit of %d tuples. Halting scan", tuples_written); break; } } - } + } // WHILE // // Inline Aggregate // - if (m_aggregateNode != NULL && aggregate_isset) - { + if (m_aggregateNode != NULL && aggregate_isset) { m_tuple.move(aggregate_tuple_address); // // Inline Projection // - if (m_projectionNode != NULL) - { + if (m_projectionNode != NULL) { TableTuple &temp_tuple = m_outputTable->tempTuple(); - if (m_projectionAllTupleArray != NULL) - { - for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) - { + if (m_projectionAllTupleArray != NULL) { + for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) { temp_tuple.setNValue(ctr, m_tuple.getNValue(m_projectionAllTupleArray[ctr])); } - } - else - { - for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) - { + } else { + for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) { temp_tuple.setNValue(ctr, m_projectionExpressions[ctr]->eval(&m_tuple, NULL)); } } m_outputTable->insertTupleNonVirtual(temp_tuple); - } - else + #ifdef ANTICACHE + if (hasEvictedTable) { + // update the tuple in the LRU eviction chain + eviction_manager->updateTuple(m_targetTable, &m_tuple, false); + } + #endif // // Straight Insert // - { + } else { m_outputTable->insertTupleNonVirtual(m_tuple); + #ifdef ANTICACHE + if (hasEvictedTable) { + // update the tuple in the LRU eviction chain + eviction_manager->updateTuple(m_targetTable, &m_tuple, false); + } + #endif } } -#ifdef ANTICACHE - if (m_evicted_tuple != NULL) - delete m_evicted_tuple; - + #ifdef ANTICACHE // throw exception indicating evicted blocks are needed - if (evicted_block_ids.size() > 0) - { - evicted_block_ids.unique(); - - int num_block_ids = static_cast(evicted_block_ids.size()); - - assert(num_block_ids > 0); - VOLT_DEBUG("%d evicted blocks to read.", num_block_ids); - - int16_t* block_ids = new int16_t[num_block_ids]; - int32_t* tuple_ids = new int32_t[num_block_ids]; - -// VOLT_INFO("%d evicted block ids.", num_block_ids); - - // copy the block ids into an array - int i = 0; - for(list::iterator itr = evicted_block_ids.begin(); itr != evicted_block_ids.end(); ++itr, ++i) - { - block_ids[i] = *itr; - VOLT_INFO("Unevicting block %d", *itr); - } - - // copy the tuple offsets into an array - i = 0; - for(list::iterator itr = evicted_offsets.begin(); itr != evicted_offsets.end(); ++itr, ++i) - { - tuple_ids[i] = *itr; - } - - evicted_block_ids.clear(); - - VOLT_INFO("Throwing EvictedTupleAccessException for table %s (%d)", m_catalogTable->name().c_str(), m_catalogTable->relativeIndex()); - - int32_t partition_id = m_targetTable->m_executorContext->getPartitionId(); - throw EvictedTupleAccessException(m_catalogTable->relativeIndex(), num_block_ids, block_ids, tuple_ids, partition_id); + if (eviction_manager->hasEvictedAccesses()) { + int32_t partition_id = executor_context->getPartitionId(); + eviction_manager->throwEvictedAccessException(partition_id); } -#endif + #endif VOLT_DEBUG ("Index Scanned :\n %s", m_outputTable->debug().c_str()); return true; diff --git a/src/ee/executors/nestloopindexexecutor.cpp b/src/ee/executors/nestloopindexexecutor.cpp index d7d5e9c59e..c11aeeaab9 100644 --- a/src/ee/executors/nestloopindexexecutor.cpp +++ b/src/ee/executors/nestloopindexexecutor.cpp @@ -60,6 +60,10 @@ #include "storage/tableiterator.h" #include "storage/tablefactory.h" +#ifdef ANTICACHE +#include "anticache/AntiCacheEvictionManager.h" +#endif + using namespace voltdb; bool NestLoopIndexExecutor::p_init(AbstractPlanNode* abstract_node, @@ -169,6 +173,7 @@ bool NestLoopIndexExecutor::p_init(AbstractPlanNode* abstract_node, inner_table = dynamic_cast(inline_node->getTargetTable()); assert(inner_table); + inner_catalogTable = catalog_db->tables().get(inner_table->name()); assert(node->getInputTables().size() == 1); outer_table = node->getInputTables()[0]; @@ -246,6 +251,12 @@ bool NestLoopIndexExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracke post_expression->substitute(params); VOLT_TRACE("Post Expression:\n%s", post_expression->debug(true).c_str()); } + + // Anti-Cache Variables + #ifdef ANTICACHE + AntiCacheEvictionManager* eviction_manager = executor_context->getAntiCacheEvictionManager(); + bool hasEvictedTable = (inner_table->getEvictedTable() != NULL); + #endif // // OUTER TABLE ITERATION @@ -262,7 +273,7 @@ bool NestLoopIndexExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracke VOLT_TRACE("outer_tuple:%s", outer_tuple.debug(outer_table->name()).c_str()); outer_table->updateTupleAccessCount(); - + // // Now use the outer table tuple to construct the search key // against the inner table @@ -317,14 +328,30 @@ bool NestLoopIndexExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracke { match = true; inner_table->updateTupleAccessCount(); + + // Anti-Cache Evicted Tuple Tracking + #ifdef ANTICACHE + // We are pointing to an entry for an evicted tuple + if (inner_tuple.isEvicted()) { + VOLT_INFO("Tuple in NestLoopIndexScan is evicted %s", inner_catalogTable->name().c_str()); + + // Tell the EvictionManager's internal tracker that we touched this mofo + eviction_manager->recordEvictedAccess(inner_catalogTable, &inner_tuple); + + // Pavlo: 2014-07-09 + // If the tuple is evicted, then we can't continue with the rest of stuff below us. + // There is nothing else we can do with it (i.e., check expressions). + // I don't know why this wasn't here in the first place? + continue; + } + #endif VOLT_TRACE("inner_tuple:%s", inner_tuple.debug(inner_table->name()).c_str()); // // Append the inner values to the end of our join tuple // - for (int col_ctr = 0; col_ctr < num_of_inner_cols; ++col_ctr) - { + for (int col_ctr = 0; col_ctr < num_of_inner_cols; ++col_ctr) { join_tuple.setNValue(col_ctr + num_of_outer_cols, inner_tuple.getNValue(col_ctr)); } @@ -335,8 +362,7 @@ bool NestLoopIndexExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracke // First check whether the end_expression is now false // if (end_expression != NULL && - end_expression->eval(&join_tuple, NULL).isFalse()) - { + end_expression->eval(&join_tuple, NULL).isFalse()) { VOLT_TRACE("End Expression evaluated to false, stopping scan"); break; } @@ -344,16 +370,22 @@ bool NestLoopIndexExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracke // Then apply our post-predicate to do further filtering // if (post_expression == NULL || - post_expression->eval(&join_tuple, NULL).isTrue()) - { + post_expression->eval(&join_tuple, NULL).isTrue()) { // // Try to put the tuple into our output table // VOLT_TRACE("MATCH: %s", join_tuple.debug(output_table->name()).c_str()); output_table->insertTupleNonVirtual(join_tuple); + + #ifdef ANTICACHE + if (hasEvictedTable) { + // update the tuple in the LRU eviction chain + eviction_manager->updateTuple(inner_table, &inner_tuple, false); + } + #endif } - } + } // WHILE // // Left Outer Join @@ -362,8 +394,7 @@ bool NestLoopIndexExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracke // // Append NULLs to the end of our join tuple // - for (int col_ctr = 0; col_ctr < num_of_inner_cols; ++col_ctr) - { + for (int col_ctr = 0; col_ctr < num_of_inner_cols; ++col_ctr) { const int index = col_ctr + num_of_outer_cols; NValue value = join_tuple.getNValue(index); value.setNull(); @@ -371,7 +402,15 @@ bool NestLoopIndexExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracke } output_table->insertTupleNonVirtual(join_tuple); } + } // WHILE + + #ifdef ANTICACHE + // throw exception indicating evicted blocks are needed + if (eviction_manager->hasEvictedAccesses()) { + int32_t partition_id = executor_context->getPartitionId(); + eviction_manager->throwEvictedAccessException(partition_id); } + #endif VOLT_TRACE ("result table:\n %s", output_table->debug().c_str()); return (true); diff --git a/src/ee/executors/nestloopindexexecutor.h b/src/ee/executors/nestloopindexexecutor.h index 7718e800a3..bbd7d31c8f 100644 --- a/src/ee/executors/nestloopindexexecutor.h +++ b/src/ee/executors/nestloopindexexecutor.h @@ -49,6 +49,7 @@ #include "common/common.h" #include "common/valuevector.h" #include "common/tabletuple.h" +#include "catalog/table.h" #include "expressions/abstractexpression.h" #include "executors/abstractexecutor.h" @@ -97,6 +98,7 @@ class NestLoopIndexExecutor : public AbstractExecutor IndexLookupType m_lookupType; TempTable* output_table; PersistentTable* inner_table; + catalog::Table* inner_catalogTable; TableIndex *index; TableTuple index_values; Table* outer_table; diff --git a/src/ee/executors/seqscanexecutor.cpp b/src/ee/executors/seqscanexecutor.cpp index f8d7f1737e..1eafe94b3d 100644 --- a/src/ee/executors/seqscanexecutor.cpp +++ b/src/ee/executors/seqscanexecutor.cpp @@ -54,10 +54,15 @@ #include "plannodes/projectionnode.h" #include "plannodes/limitnode.h" #include "storage/table.h" +#include "storage/persistenttable.h" #include "storage/temptable.h" #include "storage/tablefactory.h" #include "storage/tableiterator.h" +#ifdef ANTICACHE +#include "anticache/AntiCacheEvictionManager.h" +#endif + using namespace voltdb; bool SeqScanExecutor::p_init(AbstractPlanNode *abstract_node, @@ -69,6 +74,8 @@ bool SeqScanExecutor::p_init(AbstractPlanNode *abstract_node, assert(node); assert(node->getTargetTable()); + m_catalogTable = catalog_db->tables().get(node->getTargetTable()->name()); + // // NESTED PROJECTION // @@ -130,7 +137,7 @@ bool SeqScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *tra assert(node); Table* output_table = node->getOutputTable(); assert(output_table); - Table* target_table = dynamic_cast(node->getTargetTable()); + PersistentTable* target_table = static_cast(node->getTargetTable()); assert(target_table); //cout << "SeqScanExecutor: node id" << node->getPlanNodeId() << endl; VOLT_TRACE("Sequential Scanning table :\n %s", @@ -181,9 +188,7 @@ bool SeqScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *tra // at the TargetTable. Therefore, there is nothing we more we need // to do here // - if (node->getPredicate() != NULL || projection_node != NULL || - limit_node != NULL) - { + if (node->getPredicate() != NULL || projection_node != NULL || limit_node != NULL) { // // Just walk through the table using our iterator and apply // the predicate to each tuple. For each tuple that satisfies @@ -194,37 +199,57 @@ bool SeqScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *tra AbstractExpression *predicate = node->getPredicate(); VOLT_TRACE("SCAN PREDICATE A:\n%s\n", predicate->debug(true).c_str()); - if (predicate) - { + if (predicate) { predicate->substitute(params); assert(predicate != NULL); VOLT_TRACE("SCAN PREDICATE B:\n%s\n", predicate->debug(true).c_str()); } + + // Anti-Cache Variables + #ifdef ANTICACHE + AntiCacheEvictionManager* eviction_manager = executor_context->getAntiCacheEvictionManager(); + bool hasEvictedTable = (target_table->getEvictedTable() != NULL); + #endif int tuple_ctr = 0; - while (iterator.next(tuple)) - { + while (iterator.next(tuple)) { + target_table->updateTupleAccessCount(); + // Read/Write Set Tracking if (tracker != NULL) { tracker->markTupleRead(target_table, &tuple); } - target_table->updateTupleAccessCount(); + // Anti-Cache Evicted Tuple Tracking + #ifdef ANTICACHE + // We are pointing to an entry for an evicted tuple + if (tuple.isEvicted()) { + VOLT_INFO("Tuple in index scan is evicted %s", m_catalogTable->name().c_str()); + + // Tell the EvictionManager's internal tracker that we touched this mofo + eviction_manager->recordEvictedAccess(m_catalogTable, &tuple); + + // Pavlo: 2014-07-09 + // If the tuple is evicted, then we can't continue with the rest of stuff below us. + // There is nothing else we can do with it (i.e., check expressions). + // I don't know why this wasn't here in the first place? + continue; + } + #endif + VOLT_TRACE("INPUT TUPLE: %s, %d/%d\n", tuple.debug(target_table->name()).c_str(), tuple_ctr, (int)target_table->activeTupleCount()); // // For each tuple we need to evaluate it against our predicate // - if (predicate == NULL || predicate->eval(&tuple, NULL).isTrue()) - { + if (predicate == NULL || predicate->eval(&tuple, NULL).isTrue()) { // // Nested Projection // Project (or replace) values from input tuple // - if (projection_node != NULL) - { + if (projection_node != NULL) { TableTuple &temp_tuple = output_table->tempTuple(); for (int ctr = 0; ctr < num_of_columns; ctr++) { @@ -241,9 +266,7 @@ bool SeqScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *tra output_table->name().c_str()); return false; } - } - else - { + } else { // // Insert the tuple into our output table // @@ -256,12 +279,27 @@ bool SeqScanExecutor::p_execute(const NValueArray ¶ms, ReadWriteTracker *tra } } ++tuple_ctr; + + #ifdef ANTICACHE + if (hasEvictedTable) { + // update the tuple in the LRU eviction chain + eviction_manager->updateTuple(target_table, &tuple, false); + } + #endif + // Check whether we have gone past our limit if (limit >= 0 && tuple_ctr >= limit) { break; } } + } // WHILE + #ifdef ANTICACHE + // throw exception indicating evicted blocks are needed + if (eviction_manager->hasEvictedAccesses()) { + int32_t partition_id = executor_context->getPartitionId(); + eviction_manager->throwEvictedAccessException(partition_id); } + #endif } VOLT_TRACE("\n%s\n", output_table->debug().c_str()); VOLT_TRACE("Finished Seq scanning"); diff --git a/src/ee/executors/seqscanexecutor.h b/src/ee/executors/seqscanexecutor.h index 801d442048..8d3202f3cf 100644 --- a/src/ee/executors/seqscanexecutor.h +++ b/src/ee/executors/seqscanexecutor.h @@ -49,6 +49,7 @@ #include "common/common.h" #include "common/valuevector.h" #include "executors/abstractexecutor.h" +#include "catalog/table.h" namespace voltdb { @@ -65,6 +66,8 @@ namespace voltdb const catalog::Database* catalog_db, int* tempTableMemoryInBytes); bool p_execute(const NValueArray& params, ReadWriteTracker *tracker); bool needsOutputTableClear(); + + catalog::Table* m_catalogTable; }; } diff --git a/src/ee/storage/TableCatalogDelegate.cpp b/src/ee/storage/TableCatalogDelegate.cpp index c8c0608abd..e0a2a2949a 100644 --- a/src/ee/storage/TableCatalogDelegate.cpp +++ b/src/ee/storage/TableCatalogDelegate.cpp @@ -314,7 +314,7 @@ TableCatalogDelegate::init(ExecutorContext *executorContext, dynamic_cast(m_table)->setEvictedTable(evicted_table); dynamic_cast(m_table)->setBatchEvicted(catalogTable.batchEvicted()); } else { - VOLT_WARN("Not creating EvictedTable for table '%s'", catalogTable.name().c_str()); + VOLT_DEBUG("Not creating EvictedTable for table '%s'", catalogTable.name().c_str()); } #endif diff --git a/src/ee/storage/persistenttable.cpp b/src/ee/storage/persistenttable.cpp index 1f80e01c43..16b170f500 100644 --- a/src/ee/storage/persistenttable.cpp +++ b/src/ee/storage/persistenttable.cpp @@ -181,7 +181,7 @@ PersistentTable::~PersistentTable() { if (m_indexes) delete[] m_indexes; #ifdef ANTICACHE - if (m_evictedTable) delete m_evictedTable; +// if (m_evictedTable) delete m_evictedTable; #endif // note this class has ownership of the views, even if they diff --git a/src/ee/voltdbjni.cpp b/src/ee/voltdbjni.cpp index 160b3064ef..ba2b58167b 100644 --- a/src/ee/voltdbjni.cpp +++ b/src/ee/voltdbjni.cpp @@ -574,6 +574,11 @@ SHAREDLIB_JNIEXPORT jint JNICALL Java_org_voltdb_jni_ExecutionEngine_nativeExecu updateJNILogProxy(engine); //JNIEnv pointer can change between calls, must be updated engine->setUndoToken(undoToken); engine->resetReusedResultOutputBuffer(); + + #ifdef ANTICACHE + engine->antiCacheResetEvictedTupleTracker(); + #endif + NValueArray ¶ms = engine->getParameterContainer(); Pool *stringPool = engine->getStringPool(); const int paramcnt = deserializeParameterSet(engine->getParameterBuffer(), engine->getParameterBufferCapacity(), params, engine->getStringPool()); @@ -627,6 +632,10 @@ Java_org_voltdb_jni_ExecutionEngine_nativeExecuteCustomPlanFragment ( string cppplan = str; env->ReleaseStringUTFChars(plan, str); + #ifdef ANTICACHE + engine->antiCacheResetEvictedTupleTracker(); + #endif + // execute engine->setUsedParamcnt(0); retval = engine->executePlanFragment(cppplan, outputDependencyId, @@ -667,6 +676,11 @@ SHAREDLIB_JNIEXPORT jint JNICALL Java_org_voltdb_jni_ExecutionEngine_nativeExecu try { updateJNILogProxy(engine); //JNIEnv pointer can change between calls, must be updated engine->resetReusedResultOutputBuffer(); + + #ifdef ANTICACHE + engine->antiCacheResetEvictedTupleTracker(); + #endif + engine->setUndoToken(undoToken); static_cast(engine->getTopend())->updateJNIEnv(env); Pool *stringPool = engine->getStringPool(); diff --git a/src/frontend/edu/brown/hstore/AntiCacheManager.java b/src/frontend/edu/brown/hstore/AntiCacheManager.java index 1829a30d65..19a99308b1 100644 --- a/src/frontend/edu/brown/hstore/AntiCacheManager.java +++ b/src/frontend/edu/brown/hstore/AntiCacheManager.java @@ -19,7 +19,6 @@ import org.voltdb.StoredProcedureInvocation; import org.voltdb.VoltSystemProcedure; import org.voltdb.VoltTable; -import org.voltdb.catalog.Column; import org.voltdb.catalog.Database; import org.voltdb.catalog.Table; import org.voltdb.exceptions.EvictedTupleAccessException; @@ -33,10 +32,8 @@ import com.google.protobuf.RpcCallback; import edu.brown.catalog.CatalogUtil; -import edu.brown.hstore.Hstoreservice.HStoreService; import edu.brown.hstore.Hstoreservice.Status; import edu.brown.hstore.Hstoreservice.UnevictDataResponse; -import edu.brown.hstore.callbacks.LocalInitQueueCallback; import edu.brown.hstore.conf.HStoreConf; import edu.brown.hstore.internal.UtilityWorkMessage.TableStatsRequestMessage; import edu.brown.hstore.txns.AbstractTransaction; @@ -276,21 +273,22 @@ public Runnable getMemoryMonitorThread() { protected void processingCallback(QueueEntry next) { assert(next.ts.isInitialized()) : String.format("Unexpected uninitialized transaction handle: %s", next); - if(next.partition != next.ts.getBasePartition()) { // distributed txn - LOG.info(String.format("The base partition for %s is %d but we want to fetch a block for partition %d: %s", - next.ts, next.ts.getBasePartition(), next.partition, next)); + if (next.partition != next.ts.getBasePartition()) { // distributed txn + LOG.warn(String.format("The base partition for %s is %d but we want to fetch a block for partition %d: %s", + next.ts, next.ts.getBasePartition(), next.partition, next)); // if we are the remote site then we should go ahead and continue processing // if no then we should simply requeue the entry? } - LOG.debug("Processing " + next); + if (debug.val) + LOG.debug("Processing " + next); // We need to get the EE handle for the partition that this txn // needs to have read in some blocks from disk PartitionExecutor executor = hstore_site.getPartitionExecutor(next.partition); ExecutionEngine ee = executor.getExecutionEngine(); - boolean merge_needed = true; + // boolean merge_needed = true; // We can now tell it to read in the blocks that this txn needs // Note that we are doing this without checking whether another txn is already @@ -306,17 +304,19 @@ protected void processingCallback(QueueEntry next) { if (hstore_conf.site.anticache_profiling) this.profilers[next.partition].retrieval_time.start(); try { - LOG.debug(String.format("Asking EE to read in evicted blocks from table %s on partition %d: %s", - next.catalog_tbl.getName(), next.partition, Arrays.toString(next.block_ids))); + if (debug.val) + LOG.debug(String.format("Asking EE to read in evicted blocks from table %s on partition %d: %s", + next.catalog_tbl.getName(), next.partition, Arrays.toString(next.block_ids))); ee.antiCacheReadBlocks(next.catalog_tbl, next.block_ids, next.tuple_offsets); - LOG.debug(String.format("Finished reading blocks from partition %d", - next.partition)); + if (debug.val) + LOG.debug(String.format("Finished reading blocks from partition %d", + next.partition)); } catch (SerializableException ex) { LOG.info("Caught unexpected SerializableException while reading anti-cache block.", ex); - merge_needed = false; + // merge_needed = false; } finally { if (hstore_conf.site.anticache_profiling) this.profilers[next.partition].retrieval_time.stopIfStarted(); @@ -340,7 +340,7 @@ protected void processingCallback(QueueEntry next) { if (debug.val) LOG.debug("restartin on local"); this.hstore_site.transactionInit(next.ts); - }else{ + } else { ee.antiCacheMergeBlocks(next.catalog_tbl); RemoteTransaction ts = (RemoteTransaction) next.ts; RpcCallback callback = ts.getUnevictCallback(); @@ -352,8 +352,6 @@ protected void processingCallback(QueueEntry next) { callback.run(builder.build()); } - - // this.hstore_site.transactionReject(next.ts, Status.ABORT_GRACEFUL); } @Override @@ -855,7 +853,7 @@ protected void updatePartitionStats(VoltTable vt) { vt.advanceRow(); int partition = (int) vt.getLong("PARTITION_ID"); stats = this.partitionStats[partition]; - long oldSizeKb = stats.sizeKb; + // long oldSizeKb = stats.sizeKb; stats.reset(); do { diff --git a/src/frontend/edu/brown/hstore/HStoreCoordinator.java b/src/frontend/edu/brown/hstore/HStoreCoordinator.java index 9afa526b72..ff136cb99c 100644 --- a/src/frontend/edu/brown/hstore/HStoreCoordinator.java +++ b/src/frontend/edu/brown/hstore/HStoreCoordinator.java @@ -265,14 +265,14 @@ public void run(UnevictDataResponse response) { HStoreThreadManager.formatSiteName(local_site_id), response.getStatus())); long oldTxnId = response.getTransactionId(); - int partition = response.getPartitionId(); - + // int partition = response.getPartitionId(); LocalTransaction ts = hstore_site.getTransaction(oldTxnId); assert(response.getSenderSite() != local_site_id); hstore_site.getTransactionInitializer().resetTransactionId(ts, ts.getBasePartition()); - LOG.info(String.format("transaction %d is being restarted", ts.getTransactionId())); + if (debug.val) + LOG.debug(String.format("transaction %d is being restarted", ts.getTransactionId())); LocalInitQueueCallback initCallback = (LocalInitQueueCallback)ts.getInitCallback(); hstore_site.getCoordinator().transactionInit(ts, initCallback); } @@ -581,9 +581,10 @@ protected void initCluster() { RpcCallback callback = new RpcCallback() { @Override public void run(InitializeResponse parameter) { - if (debug.val) LOG.debug(String.format("Initialization Response: %s / %s", - HStoreThreadManager.formatSiteName(parameter.getSenderSite()), - parameter.getStatus())); + if (debug.val) + LOG.debug(String.format("Initialization Response: %s / %s", + HStoreThreadManager.formatSiteName(parameter.getSenderSite()), + parameter.getStatus())); latch.countDown(); } }; @@ -684,8 +685,9 @@ public void transactionRedirect(RpcController controller, TransactionRedirectReq // We need to create a wrapper callback so that we can get the output that // HStoreSite wants to send to the client and forward // it back to whomever told us about this txn - if (debug.val) LOG.debug(String.format("Received redirected transaction request from HStoreSite %s", - HStoreThreadManager.formatSiteName(request.getSenderSite()))); + if (debug.val) + LOG.debug(String.format("Received redirected transaction request from HStoreSite %s", + HStoreThreadManager.formatSiteName(request.getSenderSite()))); ByteBuffer serializedRequest = request.getWork().asReadOnlyByteBuffer(); TransactionRedirectResponseCallback callback = null; try { @@ -722,10 +724,11 @@ public void sendData(RpcController controller, SendDataRequest request, RpcCallb @Override public void initialize(RpcController controller, InitializeRequest request, RpcCallback done) { - if (debug.val) LOG.debug(String.format("Received %s from HStoreSite %s [instanceId=%d]", - request.getClass().getSimpleName(), - HStoreThreadManager.formatSiteName(request.getSenderSite()), - request.getInstanceId())); + if (debug.val) + LOG.debug(String.format("Received %s from HStoreSite %s [instanceId=%d]", + request.getClass().getSimpleName(), + HStoreThreadManager.formatSiteName(request.getSenderSite()), + request.getInstanceId())); hstore_site.setInstanceId(request.getInstanceId()); InitializeResponse response = InitializeResponse.newBuilder() @@ -766,7 +769,8 @@ public void shutdownPrepare(RpcController controller, ShutdownPrepareRequest req @Override public void shutdown(RpcController controller, ShutdownRequest request, RpcCallback done) { String originName = HStoreThreadManager.formatSiteName(request.getSenderSite()); - if (debug.val) LOG.warn(String.format("Got %s from %s", request.getClass().getSimpleName(), originName)); + if (debug.val) + LOG.warn(String.format("Got %s from %s", request.getClass().getSimpleName(), originName)); LOG.warn(String.format("Shutting down %s [status=%d]", hstore_site.getSiteName(), request.getExitStatus())); @@ -782,7 +786,9 @@ public void shutdown(RpcController controller, ShutdownRequest request, RpcCallb @Override public void heartbeat(RpcController controller, HeartbeatRequest request, RpcCallback done) { - LOG.info(String.format("heartbeat from %d at %d^^^^^^^^^^", request.getSenderSite(), local_site_id)); + if (debug.val) + LOG.debug(String.format("heartbeat from %d at %d^^^^^^^^^^", + request.getSenderSite(), local_site_id)); HeartbeatResponse.Builder builder = HeartbeatResponse.newBuilder() .setSenderSite(local_site_id) .setStatus(Status.OK); @@ -1367,11 +1373,13 @@ public void sendUnevictDataMessage(int remote_site_id, LocalTransaction txn, int UnevictDataRequest request = builder.build(); try { this.channels[remote_site_id].unevictData(new ProtoRpcController(), request, this.unevictCallback); - LOG.info(String.format("Sent unevict message request to remote hstore site %d from base site %d", remote_site_id, this.hstore_site.getSiteId())); - if (trace.val) + if (trace.val) { + LOG.trace(String.format("Sent unevict message request to remote hstore site %d from base site %d", + remote_site_id, this.hstore_site.getSiteId())); LOG.trace(String.format("Sent %s to %s", request.getClass().getSimpleName(), HStoreThreadManager.formatSiteName(remote_site_id))); + } } catch (RuntimeException ex) { // Silently ignore these errors... ex.printStackTrace(); diff --git a/src/frontend/edu/brown/hstore/HStoreSite.java b/src/frontend/edu/brown/hstore/HStoreSite.java index 184ea06e4a..6813e62cec 100644 --- a/src/frontend/edu/brown/hstore/HStoreSite.java +++ b/src/frontend/edu/brown/hstore/HStoreSite.java @@ -2691,11 +2691,9 @@ else if (orig_ts.getRestartCounter() <= 2) { // FIXME Table evicted_table = error.getTable(this.catalogContext.database); new_ts.setPendingError(error, false); - //if (debug.val) - LOG.info(String.format("Added aborted txn to %s queue. Unevicting %d blocks from %s (%d).", + if (debug.val) + LOG.debug(String.format("Added aborted txn to %s queue. Unevicting %d blocks from %s (%d).", AntiCacheManager.class.getSimpleName(), block_ids.length, evicted_table.getName(), evicted_table.getRelativeIndex())); - //LOG.info(String.format("Added aborted txn to %s queue.", - // AntiCacheManager.class.getSimpleName())); if(orig_ts.getBasePartition()!=error.getPartitionId() && !this.isLocalPartition(error.getPartitionId())){ new_ts.setOldTransactionId(orig_ts.getTransactionId()); diff --git a/src/frontend/edu/brown/hstore/PartitionExecutor.java b/src/frontend/edu/brown/hstore/PartitionExecutor.java index e8a1750d96..395e2a24e7 100644 --- a/src/frontend/edu/brown/hstore/PartitionExecutor.java +++ b/src/frontend/edu/brown/hstore/PartitionExecutor.java @@ -2314,11 +2314,9 @@ private void processWorkResult(LocalTransaction ts, WorkResult result) { if (debug.val) LOG.error(String.format("%s - Got error from partition %d in %s", ts, result.getPartitionId(), result.getClass().getSimpleName()), error); - LOG.info(String.format("%s - Got error from partition %d in %s at partition %d", - ts, result.getPartitionId(), result.getClass().getSimpleName(), this.partitionId), error); if (error instanceof EvictedTupleAccessException){ EvictedTupleAccessException evta = (EvictedTupleAccessException) error; - LOG.info(String.format("Evicted tuple access exception error has partition id set as %d", evta.getPartitionId())); + LOG.error(String.format("Evicted tuple access exception error has partition id set as %d", evta.getPartitionId())); } ts.setPendingError(error, true); } diff --git a/src/frontend/org/voltdb/VoltProcedure.java b/src/frontend/org/voltdb/VoltProcedure.java index 49e790c8be..f6d256c9a4 100644 --- a/src/frontend/org/voltdb/VoltProcedure.java +++ b/src/frontend/org/voltdb/VoltProcedure.java @@ -574,7 +574,8 @@ public final ClientResponseImpl call(LocalTransaction txnState, Object... paramL try { // ANTI-CACHE TABLE MERGE if (hstore_conf.site.anticache_enable && txnState.hasAntiCacheMergeTable()) { - LOG.info("Merging blocks for anticache table."); + if (debug.val) + LOG.debug("Merging blocks for anticache table."); if (hstore_conf.site.anticache_profiling) { this.hstore_site.getAntiCacheManager() diff --git a/tests/frontend/org/voltdb/regressionsuites/TestAntiCacheSuite.java b/tests/frontend/org/voltdb/regressionsuites/TestAntiCacheSuite.java index fa66beaa0f..0eeaf6c64e 100644 --- a/tests/frontend/org/voltdb/regressionsuites/TestAntiCacheSuite.java +++ b/tests/frontend/org/voltdb/regressionsuites/TestAntiCacheSuite.java @@ -37,6 +37,7 @@ public class TestAntiCacheSuite extends RegressionSuite { private static final String PREFIX = "anticache"; private static final int NOTIFY_TIMEOUT = 2000; // ms + private static final int NUM_VOTES = 100; /** * Constructor needed for JUnit. Should just pass on parameters to superclass. @@ -127,6 +128,38 @@ private Map evictData(Client client) throws Exception { return (m); } + + private void checkEvictedAccess(String procName, Object params[], int expected) throws Exception { + Client client = this.getClient(); + this.initializeDatabase(client); + this.loadVotes(client, NUM_VOTES); + int num_evicts = 5; + for (int i = 0; i < num_evicts; i++) { + this.evictData(client); + } // FOR + + // Now force the system to fetch the block back in + // long expected = 1; + ClientResponse cresponse = client.callProcedure(procName, params); + assertEquals(cresponse.toString(), Status.OK, cresponse.getStatus()); + assertEquals(cresponse.toString(), 1, cresponse.getResults().length); + VoltTable result = cresponse.getResults()[0]; + // result.advanceRow(); + // assertEquals(cresponse.toString(), expected, result.getRowCount()); + + // Our stats should now come back with one evicted access + cresponse = client.callProcedure(VoltSystemProcedure.procCallName(EvictedAccessHistory.class)); + assertEquals(cresponse.toString(), Status.OK, cresponse.getStatus()); + assertEquals(cresponse.toString(), 1, cresponse.getResults().length); + result = cresponse.getResults()[0]; + // assertEquals(1, result.getRowCount()); + System.err.println(VoltTableUtil.format(result)); + + while (result.advanceRow()) { + assertEquals(procName, result.getString("PROCEDURE")); + } // WHILE + } + // -------------------------------------------------------------------------------------------- // TEST CASES // -------------------------------------------------------------------------------------------- @@ -215,39 +248,27 @@ public void testEvictHistory() throws Exception { } /** - * testEvictedAccessHistory + * testEvictedAccessSeqScan */ - public void testEvictedAccessHistory() throws Exception { - Client client = this.getClient(); - this.initializeDatabase(client); - this.loadVotes(client, 100); - int num_evicts = 5; - for (int i = 0; i < num_evicts; i++) { - this.evictData(client); - } // FOR - - // Now force the system to fetch the block back in - long expected = 1; - String procName = "GetVote"; - Object params[] = { expected }; - ClientResponse cresponse = client.callProcedure(procName, params); - assertEquals(cresponse.toString(), Status.OK, cresponse.getStatus()); - assertEquals(cresponse.toString(), 1, cresponse.getResults().length); - VoltTable result = cresponse.getResults()[0]; - result.advanceRow(); - assertEquals(cresponse.toString(), expected, result.getLong(0)); - - // Our stats should now come back with one evicted access - cresponse = client.callProcedure(VoltSystemProcedure.procCallName(EvictedAccessHistory.class)); - assertEquals(cresponse.toString(), Status.OK, cresponse.getStatus()); - assertEquals(cresponse.toString(), 1, cresponse.getResults().length); - result = cresponse.getResults()[0]; - // assertEquals(1, result.getRowCount()); - System.err.println(VoltTableUtil.format(result)); - - while (result.advanceRow()) { - assertEquals(procName, result.getString("PROCEDURE")); - } // WHILE + public void testEvictedAccessSeqScan() throws Exception { + Object params[] = { }; + this.checkEvictedAccess("GetAllVotes", params, NUM_VOTES); + } + + /** + * testEvictedAccessIndexScan + */ + public void testEvictedAccessIndexScan() throws Exception { + Object params[] = { 1 }; + this.checkEvictedAccess("GetVote", params, 1); + } + + /** + * testEvictedAccessIndexJoin + */ + public void testEvictedAccessIndexJoin() throws Exception { + Object params[] = { 1 }; + this.checkEvictedAccess("GetVoteJoin", params, 1); } public static Test suite() { @@ -267,6 +288,15 @@ public static Test suite() { project.markTableEvictable(VoterConstants.TABLENAME_VOTES); project.addStmtProcedure("GetVote", "SELECT * FROM " + VoterConstants.TABLENAME_VOTES + " WHERE vote_id = ?"); + project.addStmtProcedure("GetAllVotes", + "SELECT * FROM " + VoterConstants.TABLENAME_VOTES); + project.addStmtProcedure("GetVoteJoin", + String.format("SELECT phone_number, contestant_number FROM %s, %s " + + " WHERE vote_id = ? " + + " AND %s.contestant_number = %s.contestant_number", + VoterConstants.TABLENAME_VOTES, VoterConstants.TABLENAME_CONTESTANTS, + VoterConstants.TABLENAME_VOTES, VoterConstants.TABLENAME_CONTESTANTS)); + boolean success; /////////////////////////////////////////////////////////////