void CSphIndex_VLN::DebugDumpHitlist ( FILE * fp, const char * sKeyword, bool bID )
{
WITH_QWORD ( this, false, Qword, DumpHitlist<Qword> ( fp, sKeyword, bID ) );
}
#define WITH_QWORD(INDEX, NO_SEEK, NAME, ACTION) \
{ \
CSphIndex_VLN * pIndex = (CSphIndex_VLN *)INDEX; \
DWORD uInlineHits = pIndex->m_tSettings.m_eHitFormat==SPH_HIT_FORMAT_INLINE; \
DWORD uInlineDocinfo = pIndex->m_tSettings.m_eDocinfo==SPH_DOCINFO_INLINE; \
\
switch ( ( uInlineHits<<1 ) | uInlineDocinfo ) \
{ \
case 0: { typedef DiskIndexQword_c < false, false, NO_SEEK > NAME; ACTION; break; } \
case 1: { typedef DiskIndexQword_c < false, true, NO_SEEK > NAME; ACTION; break; } \
case 2: { typedef DiskIndexQword_c < true, false, NO_SEEK > NAME; ACTION; break; } \
case 3: { typedef DiskIndexQword_c < true, true, NO_SEEK > NAME; ACTION; break; } \
default: \
sphDie ( "INTERNAL ERROR: impossible qword settings" ); \
} \
}
DiskIndexQword_c < false, true, NO_SEEK > NAME;
template < class Qword >
void CSphIndex_VLN::DumpHitlist ( FILE * fp, const char * sKeyword, bool bID )
{
// get keyword id
SphWordID_t uWordID = 0;
BYTE * sTok = NULL;
if ( !bID )
{
CSphString sBuf ( sKeyword );
m_pTokenizer->SetBuffer ( (BYTE*)sBuf.cstr(), strlen ( sBuf.cstr() ) );
sTok = m_pTokenizer->GetToken();
if ( !sTok )
sphDie ( "keyword=%s, no token (too short?)", sKeyword );
uWordID = m_pDict->GetWordID ( sTok );
if ( !uWordID )
sphDie ( "keyword=%s, tok=%s, no wordid (stopped?)", sKeyword, sTok );
fprintf ( fp, "keyword=%s, tok=%s, wordid="UINT64_FMT"\n", sKeyword, sTok, uint64_t(uWordID) );
} else
{
uWordID = (SphWordID_t) strtoull ( sKeyword, NULL, 10 );
if ( !uWordID )
sphDie ( "failed to convert keyword=%s to id (must be integer)", sKeyword );
fprintf ( fp, "wordid="UINT64_FMT"\n", uint64_t(uWordID) );
}
// open files
CSphAutofile tDoclist, tHitlist, tWordlist;
if ( tDoclist.Open ( GetIndexFileName("spd"), SPH_O_READ, m_sLastError ) < 0 )
sphDie ( "failed to open doclist: %s", m_sLastError.cstr() );
if ( tHitlist.Open ( GetIndexFileName ( m_uVersion>=3 ? "spp" : "spd" ), SPH_O_READ, m_sLastError ) < 0 )
sphDie ( "failed to open hitlist: %s", m_sLastError.cstr() );
if ( tWordlist.Open ( GetIndexFileName ( "spi" ), SPH_O_READ, m_sLastError ) < 0 )
sphDie ( "failed to open wordlist: %s", m_sLastError.cstr() );
// aim
DiskIndexQwordSetup_c tTermSetup ( tDoclist, tHitlist, tWordlist, m_bPreloadWordlist ? 0 : m_tWordlist.m_iMaxChunk );
tTermSetup.m_pDict = m_pDict;
tTermSetup.m_pIndex = this;
tTermSetup.m_eDocinfo = m_tSettings.m_eDocinfo;
tTermSetup.m_tMin.Clone ( *m_pMin, m_tSchema.GetRowSize() );
tTermSetup.m_bSetupReaders = true;
Qword tKeyword ( false, false );
tKeyword.m_tDoc.m_iDocID = m_pMin->m_iDocID;
tKeyword.m_iWordID = uWordID;
tKeyword.m_sWord = sKeyword;
tKeyword.m_sDictWord = (const char *)sTok;
if ( !tTermSetup.QwordSetup ( &tKeyword ) )
sphDie ( "failed to setup keyword" );
int iSize = m_tSchema.GetRowSize();
CSphVector<CSphRowitem> dAttrs ( iSize );
// press play on tape
for ( ;; )
{
tKeyword.GetNextDoc ( iSize ? &dAttrs[0] : NULL );
if ( !tKeyword.m_tDoc.m_iDocID )
break;
tKeyword.SeekHitlist ( tKeyword.m_iHitlistPos );
int iHits = 0;
if ( tKeyword.m_bHasHitlist )
for ( Hitpos_t uHit = tKeyword.GetNextHit(); uHit!=EMPTY_HIT; uHit = tKeyword.GetNextHit() )
{
fprintf ( fp, "doc="DOCID_FMT", hit=0x%08x\n", tKeyword.m_tDoc.m_iDocID, uHit ); // FIXME?
iHits++;
}
if ( !iHits )
{
uint64_t uOff = tKeyword.m_iHitlistPos;
fprintf ( fp, "doc="DOCID_FMT", NO HITS, inline=%d, off="UINT64_FMT"\n",
tKeyword.m_tDoc.m_iDocID, (int)(uOff>>63), (uOff<<1)>>1 );
}
}
}
/// query word from the searcher's point of view
template < bool INLINE_HITS, bool INLINE_DOCINFO, bool DISABLE_HITLIST_SEEK >
class DiskIndexQword_c : public DiskIndexQwordTraits_c
{
public:
explicit DiskIndexQword_c ( bool bUseMinibuffer, bool bExcluded )
: DiskIndexQwordTraits_c ( bUseMinibuffer, bExcluded )
{
}
virtual void Reset ()
{
m_uHitPosition = 0;
m_uHitState = 0;
m_rdDoclist.Reset ();
m_rdHitlist.Reset ();
ISphQword::Reset();
m_iHitPos = EMPTY_HIT;
m_iInlineAttrs = 0;
}
void GetHitlistEntry ()
{
assert ( !m_bHitlistOver );
DWORD iDelta = m_rdHitlist.UnzipInt ();
if ( iDelta )
{
m_iHitPos += iDelta;
} else
{
m_iHitPos = EMPTY_HIT;
#ifndef NDEBUG
m_bHitlistOver = true;
#endif
}
}
virtual void CollectHitMask()
{
SeekHitlist ( m_iHitlistPos );
for ( Hitpos_t uHit = GetNextHit(); uHit!=EMPTY_HIT; uHit = GetNextHit() )
m_dFields.Set ( HITMAN::GetField ( uHit ) );
m_bAllFieldsKnown = true;
}
virtual const CSphMatch & GetNextDoc ( DWORD * pDocinfo )
{
SphDocID_t iDelta = m_rdDoclist.UnzipDocid();
if ( iDelta )
{
m_bAllFieldsKnown = false;
m_tDoc.m_iDocID += iDelta;
if ( INLINE_DOCINFO )
{
assert ( pDocinfo );
for ( int i=0; i<m_iInlineAttrs; i++ )
pDocinfo[i] = m_rdDoclist.UnzipInt() + m_pInlineFixup[i];
}
if ( INLINE_HITS )
{
m_uMatchHits = m_rdDoclist.UnzipInt();
const DWORD uFirst = m_rdDoclist.UnzipInt();
if ( m_uMatchHits==1 )
{
const DWORD uField = m_rdDoclist.UnzipInt(); // field and end marker
m_iHitlistPos = uFirst | ( uField << 23 ) | ( U64C(1)<<63 );
m_dFields.Unset();
m_dFields.Set ( uField >> 1 );
m_bAllFieldsKnown = true;
} else
{
m_dFields.Assign32 ( uFirst );
m_uHitPosition += m_rdDoclist.UnzipOffset();
m_iHitlistPos = m_uHitPosition;
}
} else
{
SphOffset_t iDeltaPos = m_rdDoclist.UnzipOffset();
assert ( iDeltaPos>=0 );
m_iHitlistPos += iDeltaPos;
m_dFields.Assign32 ( m_rdDoclist.UnzipInt() );
m_uMatchHits = m_rdDoclist.UnzipInt();
}
} else
{
m_tDoc.m_iDocID = 0;
}
return m_tDoc;
}
virtual void SeekHitlist ( SphOffset_t uOff )
{
if ( uOff >> 63 )
{
m_uHitState = 1;
m_uInlinedHit = (DWORD)uOff; // truncate high dword(截断高的dword)
} else
{
m_uHitState = 0;
m_iHitPos = EMPTY_HIT;
if ( DISABLE_HITLIST_SEEK )
assert ( m_rdHitlist.GetPos()==uOff ); // make sure we're where caller thinks we are.
else
m_rdHitlist.SeekTo ( uOff, READ_NO_SIZE_HINT );
}
#ifndef NDEBUG
m_bHitlistOver = false;
#endif
}
virtual Hitpos_t GetNextHit ()
{
assert ( m_bHasHitlist );
switch ( m_uHitState )
{
case 0: // read hit from hitlist
GetHitlistEntry ();
return m_iHitPos;
case 1: // return inlined hit
m_uHitState = 2;
return m_uInlinedHit;
case 2: // return end-of-hitlist marker after inlined hit
#ifndef NDEBUG
m_bHitlistOver = true;
#endif
m_uHitState = 0;
return EMPTY_HIT;
}
sphDie ( "INTERNAL ERROR: impossible hit emitter state" );
return EMPTY_HIT;
}
};