windows-nt/Source/XPSP1/NT/inetsrv/query/apps/cidump/cidump.cxx
2020-09-26 16:20:57 +08:00

805 lines
27 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation 1997-1998
//
// File: cidump.cxx
//
// Contents: CI catalog dump utility
//
// History: 09-Apr-97 SitaramR Created
//
//----------------------------------------------------------------------------
#define _OLE32_
#define __QUERY__
extern "C"
{
#include <nt.h>
#include <ntioapi.h>
#include <ntrtl.h>
#include <nturtl.h>
}
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <imagehlp.h>
#include <lmcons.h>
#define _DCOM_
#define _CAIROSTG_
#include <cidebnot.h>
#include <cierror.h>
#define OLEDBVER 0x0250 // enable ICommandTree interface
#include <oleext.h>
#include <oledberr.h>
#include <oledb.h>
#include <query.h>
#include <stgprop.h>
#include <filter.h>
#include <filterr.h>
#include <vquery.hxx>
#include <restrict.hxx>
//
// Base services
//
#include <ciexcpt.hxx>
#include <smart.hxx>
#include <tsmem.hxx>
#include <xolemem.hxx>
#include <dynarray.hxx>
#include <dynstack.hxx>
#include <dblink.hxx>
#include <cisem.hxx>
#include <thrd32.hxx>
#include <readwrit.hxx>
#include <ci.h>
//
// Debug files from
//
#include <cidebug.hxx>
#include <vqdebug.hxx>
//
// CI-specific
//
#include <align.hxx>
#include <memser.hxx>
#include <memdeser.hxx>
#include <tgrow.hxx>
#include <funypath.hxx>
#include <params.hxx>
#include <key.hxx>
#include <keyarray.hxx>
#include <irest.hxx>
#include <cursor.hxx>
#include <idxids.hxx>
#include <dberror.hxx>
// property-related macros and includes
#include <propapi.h>
#include <propstm.hxx>
extern UNICODECALLOUTS UnicodeCallouts;
#define DebugTrace( x, y, z )
#ifdef PROPASSERTMSG
#undef PROPASSERTMSG
#endif
#define PROPASSERTMSG( x, y )
#include <rcstrmhd.hxx>
#include <xact.hxx>
#include <pidxtbl.hxx>
#include "cistore.hxx"
#include "physidx.hxx"
#include "pcomp.hxx"
#include "cidir.hxx"
DECLARE_INFOLEVEL(ci)
//DECLARE_INFOLEVEL(vq)
//extern BOOL ExceptDllMain( HANDLE hDll, DWORD dwReason, LPVOID lpReserved );
unsigned fVerbose = 0; // Verbose mode dumps all keys, wids and occurrences
unsigned fStats = 0; // Just dump wid/occ counts.
unsigned fFullStats = 0; // Just dump wid/occ counts.
unsigned fKeys = 0; // Key info
unsigned fDistribution = 0; // Key distribution info
unsigned fOccurrences = 0; // Occurrence distribution info
extern "C" GUID CLSID_CTextIFilter = CLSID_TextIFilter;
DWORD Bytes( BitOffset & boff )
{
return ( boff.Page() * CI_PAGE_SIZE ) + ( ( boff.Offset() + 7 ) / 8 );
}
ULONGLONG BitDistance( BitOffset & b1, BitOffset & b2 )
{
ULONGLONG bA = ((ULONGLONG) b1.Page() * (ULONGLONG) ( CI_PAGE_SIZE * 8) ) + b1.Offset();
ULONGLONG bB = ((ULONGLONG) b2.Page() * (ULONGLONG) ( CI_PAGE_SIZE * 8) ) + b2.Offset();
return ( bB - bA );
}
//+---------------------------------------------------------------------------
//
// Function: LocaleToCodepage
//
// Purpose: Returns a codepage from a locale
//
// Arguments: [lcid] -- Locale
//
// History: 09-Apr-97 SitaramR Created
//
//----------------------------------------------------------------------------
ULONG LocaleToCodepage( LCID lcid )
{
const BUFFER_LENGTH = 10;
WCHAR wcsCodePage[BUFFER_LENGTH];
int cwc = GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE, wcsCodePage, BUFFER_LENGTH );
//
// If error, return Ansi code page
//
if ( cwc == 0 )
{
ciDebugOut(( DEB_ERROR, "GetLocaleInfoW for lcid %d returned %d\n", lcid, GetLastError() ));
return CP_ACP;
}
return wcstoul( wcsCodePage, 0 , 10 );
}
void Usage()
{
printf( "Usage: cidump <catalog path> [-e indexid] [-d] [-s] [-f] [-v] [-w workid]\n"
" -d : Distribution of keys in documents (key, wid, occ)\n"
" -e : Exclude this index\n"
" -k : Print keys with #files, #occ, pid, size\n"
" -s : Stats only\n"
" -f : Full Stats only (for all keys)\n"
" -v : Verbose (full occurrence information)\n"
" -w : Data for this workid only\n\n"
"Example: cidump e:\\testdump\\catalog.wci\n" );
}
void DumpDirectoryKey( unsigned i, CDirectoryKey & Key )
{
BitOffset bo;
Key.Offset( bo );
printf( " key %d cb 0x%x, PropId 0x%x, opage 0x%x, obits 0x%x\n",
i,
Key.Count(),
Key.PropId(),
bo.Page(),
bo.Offset() );
} //DumpDirectoryKey
//+---------------------------------------------------------------------------
//
// Function: main
//
// Purpose: Main dump routine
//
// History: 09-Apr-97 SitaramR Created
// 02-Nov-98 KLam Passed disk space to leave to CiStorage
//
//----------------------------------------------------------------------------
int __cdecl main( int argc, char * argv[] )
{
char * pszCatDir = argv[1];
WORKID widTarget = 0xFFFFFFFF;
INDEXID aExclude[100];
unsigned cExclude = 0;
if ( argc < 2 )
{
Usage();
return 0;
}
for ( int i = 1; i < argc; i++ )
{
if ( argv[i][0] == '-' )
{
switch ( argv[i][1] )
{
case 'e':
case 'E':
i++;
aExclude[cExclude] = strtoul( argv[i], 0, 16 );
cExclude++;
break;
case 's':
case 'S':
fStats = 1;
break;
case 'd':
case 'D':
fDistribution = 1;
break;
case 'f':
case 'F':
fFullStats = 1;
break;
case 'k':
case 'K':
fKeys = 1;
break;
case 'o':
case 'O':
fOccurrences = 1;
break;
case 'v':
case 'V':
fVerbose = 1;
break;
case 'w':
case 'W':
i++;
widTarget = strtoul( argv[i], 0, 10 );
break;
default:
Usage();
return 0;
}
}
else
pszCatDir = argv[i];
}
if ( fKeys )
{
fFullStats = 0;
fStats = 0;
fVerbose = 0;
}
if ( fDistribution )
{
fFullStats = 0;
fStats = 0;
fVerbose = 0;
fKeys = 0;
fOccurrences = 0;
}
if ( fOccurrences )
{
fFullStats = 0;
fStats = 0;
fVerbose = 0;
fKeys = 0;
fDistribution = 0;
}
if ( (pszCatDir[0] != '\\' || pszCatDir[1] != '\\') &&
(pszCatDir[0] == '\0' || pszCatDir[1] != ':' || pszCatDir[2] != '\\') )
{
printf("Use full path name for catalog path!\n\n");
Usage();
return 1;
}
WCHAR wszCatDir[MAX_PATH];
LocaleToCodepage( GetSystemDefaultLCID() );
ULONG cwcActual = MultiByteToWideChar( LocaleToCodepage( GetSystemDefaultLCID() ),
0,
pszCatDir,
strlen( pszCatDir ) + 1,
wszCatDir,
MAX_PATH );
//ExceptDllMain( 0, DLL_PROCESS_ATTACH, 0 );
//
// Keep stats on where we are when we die...
//
CIndexRecord recCrash;
CKeyBuf keyCrash;
BitOffset boffCrash;
ULONG maxOccCounts = 1024;
TRY
{
ULONGLONG * aOccCounts = new ULONGLONG[ maxOccCounts ];
ULONGLONG * acbOccCounts = new ULONGLONG[ maxOccCounts ];
CTransaction xact;
XPtr<CiStorage> xStorage( new CiStorage( wszCatDir,
*((ICiCAdviseStatus *)0),
CI_MIN_DISK_SPACE_TO_LEAVE_DEFAULT ) );
XPtr<PIndexTable> xIndexTable( xStorage->QueryIndexTable( xact ) );
SIndexTabIter xIndexIter( xIndexTable->QueryIterator() );
if ( xIndexIter->Begin() )
{
CIndexRecord record;
while ( xIndexIter->NextRecord( record ) )
{
if ( record.Type() == itMaster || record.Type() == itShadow )
{
//
// Do we want to skip this one?
//
for ( unsigned i = 0; i < cExclude; i++ )
{
if ( aExclude[i] == record.Iid() )
break;
}
if ( i < cExclude )
continue;
recCrash = record;
boffCrash.Init( 0, 0 );
if ( !fKeys && !fDistribution && !fOccurrences )
{
if ( record.Type() == itMaster )
printf( "Index master: " );
else
printf( "Index shadow: " );
printf( "Object id = 0x%x, Index id = 0x%x, MaxWorkid = 0x%x\n",
record.ObjectId(),
record.Iid(),
record.MaxWorkId() );
}
ULONG maxWid = record.MaxWorkId();
SStorageObject xStorageObj( xStorage->QueryObject( record.ObjectId() ) );
PMmStream * pStream = xStorage->QueryExistingIndexStream( xStorageObj.GetObj(),
PStorage::eOpenForRead );
XPtr<PMmStream> xStream( pStream );
CPhysIndex *pPhysIndex = new CPhysIndex ( *xStorage.GetPointer(),
xStorageObj.GetObj(),
record.ObjectId(),
PStorage::eOpenForRead,
xStream );
Win4Assert( 0 == xStream.GetPointer() );
XPtr<CPhysIndex> xPhysIndex( pPhysIndex );
CiDirectory *pDir = (CiDirectory *) xStorage->QueryExistingDirectory( xStorageObj.GetObj(),
PStorage::eOpenForRead );
XPtr<CiDirectory> xDir( pDir);
unsigned cLevel1 = xDir->Level1Count();
unsigned cLevel2 = xDir->Level2Count();
if ( !fKeys && !fDistribution && !fOccurrences )
{
printf( "directory has %d level 1 and %d level 2 keys\n",
cLevel1, cLevel2 );
if ( fVerbose )
{
for ( unsigned i = 0; i < cLevel1; i++ )
DumpDirectoryKey( i, xDir->GetLevel1Key( i ) );
for ( i = 0; i < cLevel2; i++ )
DumpDirectoryKey( i, xDir->GetLevel2Key( i ) );
}
}
ULONGLONG cOccInIndex = 0;
ULONGLONG cWidsWithOneOcc = 0;
ULONGLONG cWidsWith5OrLessOcc = 0;
ULONGLONG cWidsWithOcc = 0;
ULONG cKeysWithOneWid = 0;
ULONG cKeysInIndex = 0;
ULONG cbMinimumKey = 100000;
ULONG cbMaximumKey = 0;
ULONGLONG cBitsForOcc = 0;
ULONGLONG cBitsForWid = 0;
ULONGLONG cBitsForKey = 0;
ULONG cKeysInMoreThanHalfWids = 0;
ULONG cOccMinOverall = 0xffffffff;
ULONG cOccMaxOverall = 0;
ZeroMemory( aOccCounts, sizeof( ULONGLONG ) * maxOccCounts );
ZeroMemory( acbOccCounts, sizeof( ULONGLONG ) * maxOccCounts );
CPersDeComp *pDecomp = new CPersDeComp( *xDir.GetPointer(),
record.Iid(),
*xPhysIndex.GetPointer(),
record.MaxWorkId(),
TRUE,
TRUE );
XPtr<CPersDeComp> xDecomp( pDecomp );
const CKeyBuf *pKey;
BitOffset off;
xDecomp->GetOffset( off );
BitOffset boffBefore;
boffBefore.Init( 0, 0 );
for ( pKey = xDecomp->GetKey();
pKey != NULL;
pKey = xDecomp->GetNextKey() )
{
BitOffset boAfterKey;
xDecomp->GetOffset( boAfterKey );
cBitsForKey += BitDistance( boffBefore, boAfterKey );
cKeysInIndex++;
keyCrash = *pKey;
xDecomp->GetOffset( boffCrash );
BOOL fFirst = TRUE;
unsigned cWid = 0;
unsigned cOccTotal = 0;
unsigned cOccMin = 0xFFFFFFFF;
unsigned cOccMax = 0;
BitOffset boBeforeWid;
xDecomp->GetOffset( boBeforeWid );
if ( fDistribution )
printf( "%ws", pKey->GetStr() );
for ( WORKID wid = xDecomp->WorkId();
wid != widInvalid;
wid = xDecomp->NextWorkId() )
{
BitOffset boAfterWid;
xDecomp->GetOffset( boAfterWid );
cBitsForWid += BitDistance( boBeforeWid, boAfterWid );
cWidsWithOcc++;
xDecomp->GetOffset( boffCrash );
cWid++;
if ( fFirst )
{
if ( fVerbose || fFullStats || wid == widTarget )
{
printf( " Key size = 0x%x, pid = 0x%x, buffer = %ws, "
"near page %u (0x%x), bit offset %u (0x%x) --> File offset 0x%x\n",
pKey->Count(),
pKey->Pid(),
pKey->GetStr(),
boffCrash.Page(), boffCrash.Page(),
boffCrash.Offset(), boffCrash.Offset(),
boffCrash.Page() * CI_PAGE_SIZE + (boffCrash.Offset() + 7)/8 );
if ( !fKeys )
fFirst = FALSE;
}
}
if ( (fVerbose && 0 == widTarget) ||
wid == widTarget )
printf( "\t wid = 0x%x, MaxOcc = 0x%x, OccCount = 0x%x, "
"near page %u (0x%x), bit offset %u (0x%x) --> File offset 0x%x, "
"\n\t Occurrences = ",
wid,
xDecomp->MaxOccurrence(),
xDecomp->OccurrenceCount(),
boffCrash.Page(), boffCrash.Page(),
boffCrash.Offset(), boffCrash.Offset(),
boffCrash.Page() * CI_PAGE_SIZE + (boffCrash.Offset() + 7)/8 );
unsigned cOcc = 0;
BitOffset bo1;
xDecomp->GetOffset( bo1 );
for ( OCCURRENCE occ = xDecomp->Occurrence();
occ != OCC_INVALID;
occ = xDecomp->NextOccurrence() )
{
xDecomp->GetOffset( boffCrash );
cOcc++;
if ( (fVerbose && 0 == widTarget) ||
wid == widTarget )
printf( "0x%x ", occ );
}
if ( cOcc >= maxOccCounts )
{
ULONG newMax = cOcc * 2;
ULONGLONG *a1 = new ULONGLONG[ newMax ];
ULONGLONG *a2 = new ULONGLONG[ newMax ];
ZeroMemory( a1, sizeof( ULONGLONG ) * newMax );
ZeroMemory( a2, sizeof( ULONGLONG ) * newMax );
RtlCopyMemory( a1, aOccCounts, sizeof( ULONGLONG ) * maxOccCounts );
RtlCopyMemory( a2, acbOccCounts, sizeof( ULONGLONG ) * maxOccCounts );
delete [] aOccCounts;
delete [] acbOccCounts;
aOccCounts = a1;
acbOccCounts = a2;
maxOccCounts = newMax;
}
#if 0
if ( cOcc >= 500 )
{
printf( "cocc %d in wid %d, pid %#x, len %d, %ws\n",
cOcc, wid, pKey->Pid(),
pKey->StrLen(),
pKey->GetStr() );
printf( " cb %d: ", pKey->Count() );
BYTE const * pb = pKey->GetBuf();
for ( ULONG i = 0; i < pKey->Count(); i++ )
printf( " %#x", pb[i] );
printf( "\n" );
}
#endif
BitOffset bo2;
xDecomp->GetOffset( bo2 );
ULONG cDelta = (ULONG) BitDistance( bo1, bo2 );
cBitsForOcc += cDelta;
aOccCounts[ cOcc ]++;
acbOccCounts[ cOcc ] += cDelta;
// if ( fOccurrences )
// printf( "%d, %d\n", cOcc, cDelta );
cOccInIndex += cOcc;
if ( 1 == cOcc )
cWidsWithOneOcc++;
if ( cOcc <= 5 )
cWidsWith5OrLessOcc++;
if ( (fVerbose && 0 == widTarget) ||
wid == widTarget )
printf( "\n" );
cOccTotal += cOcc;
if ( cOcc > cOccMax )
cOccMax = cOcc;
if ( cOcc < cOccMin )
cOccMin = cOcc;
xDecomp->GetOffset( boBeforeWid );
}
if ( 1 == cWid )
cKeysWithOneWid++;
if ( cWid >= ( maxWid/2 ) )
{
printf( "key with >= half wids (%u):\n", cWid );
printf( " pid %#x, len %d, %ws\n",
pKey->Pid(),
pKey->StrLen(),
pKey->GetStr() );
printf( " cb %d: ", pKey->Count() );
BYTE const * pb = pKey->GetBuf();
for ( ULONG i = 0; i < pKey->Count(); i++ )
printf( " %#x", pb[i] );
printf( "\n" );
cKeysInMoreThanHalfWids++;
}
BitOffset boffAfter;
xDecomp->GetOffset( boffAfter );
DWORD b = Bytes( boffAfter ) - Bytes( boffBefore );
if ( b < cbMinimumKey )
cbMinimumKey = b;
if ( b > cbMaximumKey )
cbMaximumKey = b;
// Print this data:
// # of files with the key
// # of occurrences of key in all files
// property id
// # of bytes taken by this key in the index
// string form of the key
//
if ( fKeys )
printf( "%7u %10u %4u %7u %ws\n",
cWid,
cOccTotal,
pKey->Pid(),
b,
pKey->GetStr() );
boffBefore = boffAfter;
if ( cOccMin < cOccMinOverall )
cOccMinOverall = cOccMin;
if ( cOccMax > cOccMaxOverall )
cOccMaxOverall = cOccMax;
if ( fFullStats )
printf( "%u Workid(s), Total Occ = %u, Min Occ = %u, Max Occ = %u\n",
cWid, cOccTotal, cOccMin, cOccMax );
if ( fDistribution )
printf( "! %d! %d\n", cWid, cOccTotal );
}
BitOffset boEnd;
xDecomp->GetOffset( boEnd );
BitOffset boStart;
if ( fOccurrences )
for ( ULONG i = 0; i <= cOccMaxOverall; i++ )
{
printf( "%I64u, ", aOccCounts[ i ] );
printf( "%I64u\n", acbOccCounts[ i ] / 8 );
}
if ( !fDistribution && !fKeys )
{
printf( "cWidsWithOcc %I64u\n", cWidsWithOcc );
printf( "bytes in index: %I64u\n", BitDistance( boStart, boEnd ) / 8 );
printf( "max workid %d\n", maxWid );
printf( "cKeysInIndex: %d\n", cKeysInIndex );
printf( "cOccInIndex %I64u\n", cOccInIndex );
printf( "cWidsWithOneOcc %I64u\n", cWidsWithOneOcc );
printf( "cWidsWith5OrLessOcc %I64u\n", cWidsWith5OrLessOcc );
printf( "cKeysWithOneWid %d\n", cKeysWithOneWid );
printf( "cKeysInMoreThanHalfWids %d\n", cKeysInMoreThanHalfWids );
printf( "cOccMaxOverall %d\n", cOccMaxOverall );
printf( "cOccMinOverall %d\n", cOccMinOverall );
printf( "maximum key bytes %d\n", cbMaximumKey );
printf( "minimum key bytes %d\n", cbMinimumKey );
printf( "bytes for occ data: %I64u\n", ( cBitsForOcc / 8 ) );
printf( "bytes for key data: %I64u\n", ( cBitsForKey / 8 ) );
printf( "bytes for wid data: %I64u\n", ( cBitsForWid / 8 ) );
printf( "total for o+k+w data: %I64u\n", ( cBitsForOcc/8 + cBitsForKey/8 + cBitsForWid/8 ) );
}
}
else if ( !fKeys && !fDistribution && !fOccurrences )
{
switch ( record.Type() )
{
case itZombie:
printf( "Zombie: " );
break;
case itDeleted:
printf( "Deleted: " );
break;
case itPartition:
printf( "Partition: " );
break;
case itChangeLog:
printf( "ChangeLog: " );
break;
case itFreshLog:
printf( "FreshLog: " );
break;
case itPhraseLat:
printf( "Phrase Lat: " );
break;
case itKeyList:
printf( "Key List: " );
break;
case itMMLog:
printf( "MM Log: " );
break;
case itNewMaster:
printf( "New Master: " );
break;
case itMMKeyList:
printf( "MM Key List: " );
break;
} // switch
printf( "Object id = 0x%x, Index id = 0x%x, MaxWorkid = 0x%x\n",
record.ObjectId(),
record.Iid(),
record.MaxWorkId() );
} // if
} // while
} // if
else
printf( "0 records found in index table\n" );
delete [] aOccCounts;
delete [] acbOccCounts;
}
CATCH( CException, e )
{
if ( HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) == e.GetErrorCode() )
{
printf("Sharing violation -- Is cisvc running?\n");
}
else
{
printf( "Caught exception 0x%x in %s 0x%x\n",
e.GetErrorCode(),
( recCrash.Type() == itMaster ) ? "master index" : "shadow index",
recCrash.Iid() );
printf( "\tProcessing key: %ws (pid = 0x%x)\n", keyCrash.GetStr(), keyCrash.Pid() );
printf( "\tNear page %u (0x%x), bit offset %u (0x%x) --> File offset 0x%x\n",
boffCrash.Page(), boffCrash.Page(),
boffCrash.Offset(), boffCrash.Offset(),
boffCrash.Page() * CI_PAGE_SIZE + (boffCrash.Offset() + 7)/8 );
}
}
END_CATCH
return 0;
}