static void print_symbol_info (FILE *fp, HASHTAB *symtab, int i) { fprintf (fp, "%3d %p (%3d) %s\n", i, KEYINFO (symtab, i), KEYLEN (symtab, i), KEYSTR (symtab, i)); }
// . return false if blocked, true otherwise // . sets g_errno on error // . this one is also called by RdbMerge to dump lists bool RdbDump::dumpList ( RdbList *list , int32_t niceness , bool recall ) { // if we had a write error and are being recalled... if ( recall ) { m_offset -= m_bytesToWrite; goto recallskip; } // assume we don't hack the list m_hacked = false; m_hacked12 = false; // save ptr to list... why? m_list = list; // nothing to do if list is empty if ( m_list->isEmpty() ) return true; // we're now in dump mode again m_isDumping = true; //#ifdef GBSANITYCHECK // don't check list if we're dumping an unordered list from tree! if ( g_conf.m_verifyWrites && m_orderedDump ) { m_list->checkList_r ( false /*removedNegRecs?*/ ); // print list stats // log("dump: sk=%s ",KEYSTR(m_list->m_startKey,m_ks)); // log("dump: ek=%s ",KEYSTR(m_list->m_endKey,m_ks)); } //#endif // before calling RdbMap::addList(), always reset list ptr // since we no longer call this in RdbMap::addList() so we don't // mess up the possible HACK below m_list->resetListPtr(); // . SANITY CHECK // . ensure first key is >= last key added to the map map if ( m_offset > 0 && m_map ) { //key_t k = m_list->getCurrentKey(); char k[MAX_KEY_BYTES]; m_list->getCurrentKey(k); //key_t lastKey = m_map->getLastKey (); // m_lastKey char lastKey[MAX_KEY_BYTES]; m_map->getLastKey(lastKey); //char *lastKey = m_map->getLastKey(); //if ( k <= lastKey ) { if ( KEYCMP(k,lastKey,m_ks)<=0 ) { log(LOG_LOGIC,"db: Dumping list key out of order. " //"lastKey.n1=%"XINT32" n0=%"XINT64" k.n1=%"XINT32" n0=%"XINT64"", //lastKey.n1,lastKey.n0,k.n1,k.n0); "lastKey=%s k=%s", KEYSTR(lastKey,m_ks), KEYSTR(k,m_ks)); g_errno = EBADENGINEER; //return true; char *xx = NULL; *xx = 0; } } if ( g_conf.m_verifyWrites ) { char rdbId = 0; if ( m_rdb ) rdbId = m_rdb->m_rdbId; m_list->checkList_r(false,false,rdbId);//RDB_POSDB); m_list->resetListPtr(); } // HACK! POSDB if ( m_ks == 18 && m_orderedDump && m_offset > 0 ) { char k[MAX_KEY_BYTES]; m_list->getCurrentKey(k); // . same top 6 bytes as last key we added? // . if so, we should only add 6 bytes from this key, not 12 // so on disk it is compressed consistently if ( memcmp ( (k ) + (m_ks-12) , (m_prevLastKey ) + (m_ks-12) , 12 ) == 0 ) { char tmp[MAX_KEY_BYTES]; char *p = m_list->getList(); // swap high 12 bytes with low 6 bytes for first key gbmemcpy ( tmp , p , m_ks-12 ); gbmemcpy ( p , p + (m_ks-12) , 12 ); gbmemcpy ( p + 12, tmp , m_ks-12 ); // big hack here m_list->m_list = p + 12; m_list->m_listPtr = p + 12; m_list->m_listPtrLo = p ; m_list->m_listPtrHi = p + 6; m_list->m_listSize -= 12 ; // turn on both bits to indicate double compression *(p+12) |= 0x06; m_hacked12 = true; } } // . HACK // . if we're doing an ordered dump then hack the list's first 12 byte // key to make it a 6 byte iff the last key we dumped last time // shares the same top 6 bytes as the first key of this list // . this way we maintain compression consistency on the disk // so IndexTable.cpp can expect all 6 byte keys for the same termid // and RdbList::checkList_r() can expect the half bits to always be // on when they can be on // . IMPORTANT: calling m_list->resetListPtr() will mess this HACK up!! if ( m_useHalfKeys && m_orderedDump && m_offset > 0 && ! m_hacked12 ) { //key_t k = m_list->getCurrentKey(); char k[MAX_KEY_BYTES]; m_list->getCurrentKey(k); // . same top 6 bytes as last key we added? // . if so, we should only add 6 bytes from this key, not 12 // so on disk it is compressed consistently //if ( memcmp ( ((char *)&k ) + 6 , // ((char *)&m_prevLastKey ) + 6 , 6 ) == 0 ) { if ( memcmp ( (k ) + (m_ks-6) , (m_prevLastKey ) + (m_ks-6) , 6 ) == 0 ) { m_hacked = true; //char tmp[6]; char tmp[MAX_KEY_BYTES]; char *p = m_list->getList(); //gbmemcpy ( tmp , p , 6 ); //gbmemcpy ( p , p + 6 , 6 ); //gbmemcpy ( p + 6 , tmp , 6 ); gbmemcpy ( tmp , p , m_ks-6 ); gbmemcpy ( p , p + (m_ks-6) , 6 ); gbmemcpy ( p + 6 , tmp , m_ks-6 ); // big hack here m_list->m_list = p + 6; m_list->m_listPtr = p + 6; // make this work for POSDB, too m_list->m_listPtrLo = p + 6 + 6; m_list->m_listPtrHi = p ; m_list->m_listSize -= 6 ; // hack on the half bit, too *(p+6) |= 0x02; } } // update old last key //m_prevLastKey = m_list->getLastKey(); m_list->getLastKey(m_prevLastKey); // now write it to disk m_buf = m_list->getList (); m_bytesToWrite = m_list->getListSize(); //#ifdef GBSANITYCHECK //if (m_list->getListSize()!=m_list->getListEnd() - m_list->getList()){ // log("RdbDump::dumpList: major problem here!"); // sleep(50000); //} //#endif recallskip: // make sure we have enough mem to add to map after a successful // dump up here, otherwise, if we write it and fail to add to map // the map is not in sync if we core thereafter if ( m_addToMap && m_map && ! m_map->prealloc ( m_list ) ) { log("db: Failed to prealloc list into map: %s.", mstrerror(g_errno)); // g_errno should be set to something if that failed if ( ! g_errno ) { char *xx = NULL; *xx = 0; } return true; } // tab to the old offset int64_t offset = m_offset; // might as well update the offset now, even before write is done m_offset += m_bytesToWrite ; // write thread is out m_writing = true; //m_bytesWritten = 0; // sanity check //log("dump: writing %"INT32" bytes at offset %"INT64"",m_bytesToWrite,offset); // . if we're called by RdbMerge directly use m_callback/m_state // . otherwise, use doneWritingWrapper() which will call dumpTree() // . BigFile::write() return 0 if blocked,-1 on error,>0 on completion // . it also sets g_errno on error bool isDone = m_file->write ( m_buf , m_bytesToWrite , offset , &m_fstate , this , doneWritingWrapper , niceness ); // debug msg //log("RdbDump dumped %"INT32" bytes, done=%"INT32"\n", // m_bytesToWrite,isDone); // return false if it blocked if ( ! isDone ) return false; // done writing m_writing = false; // return true on error if ( g_errno ) return true; // . delete list from tree, incorporate list into cache, add to map // . returns false if blocked, true otherwise, sets g_errno on error // . will only block in calling updateTfndb() return doneDumpingList ( true ); }