mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
11 KiB
308 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
resume.c
|
|
|
|
Abstract:
|
|
|
|
Module for dealing with resume keys used in enumerations.
|
|
|
|
Author:
|
|
|
|
Vladimir Z. Vulovic (vladimv) 19 - November - 1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "local.h"
|
|
#include "rpldb.h"
|
|
#include "db.h"
|
|
#include "config.h"
|
|
#include "database.h"
|
|
#define RPLRESUME_ALLOCATE
|
|
#include "resume.h"
|
|
#undef RPLRESUME_ALLOCATE
|
|
|
|
#ifdef RPL_DEBUG
|
|
|
|
VOID ResumeList(
|
|
IN PRPL_SESSION pSession,
|
|
IN PCHAR String
|
|
)
|
|
{
|
|
WCHAR ResumeValue[ 20];
|
|
DWORD NameSize;
|
|
JET_ERR ForJetError;
|
|
DWORD ResumeHandle;
|
|
DWORD ServerHandle;
|
|
|
|
Call( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle));
|
|
|
|
//
|
|
// We could skip JetMove, but if we do so, we need to modify error
|
|
// testing for the first JetRetrieveColumn() call (it would return
|
|
// JET_errNoCurrentRecord for the empty table).
|
|
//
|
|
|
|
for ( ForJetError = JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveFirst, 0);
|
|
ForJetError == JET_errSuccess;
|
|
ForJetError = JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveNext, 0)) {
|
|
Call( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ RESUME_ResumeHandle].ColumnId,
|
|
&ResumeHandle, sizeof( ResumeHandle), &NameSize, 0, NULL));
|
|
Call( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ RESUME_ResumeValue].ColumnId,
|
|
ResumeValue, sizeof( ResumeValue), &NameSize, 0, NULL));
|
|
Call( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ RESUME_ServerHandle].ColumnId,
|
|
&ServerHandle, sizeof( ServerHandle), &NameSize, 0, NULL));
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_RESUME, (
|
|
"%s ResumeH=0x%x,Value=%ws,ServerH=0x%x",
|
|
String, ResumeHandle, ResumeValue, ServerHandle));
|
|
}
|
|
}
|
|
#endif // RPL_DEBUG
|
|
|
|
|
|
DWORD ResumeCreateTable( OUT PRPL_SESSION pSession)
|
|
/*++
|
|
Table gets created, then closed. The reason we do not keep the table
|
|
open is that creator of a table holds exclusive access to that table
|
|
until he/she closes the table. This would prevent other threads from
|
|
using the table.
|
|
--*/
|
|
{
|
|
JET_COLUMNDEF ColumnDef;
|
|
JET_ERR JetError;
|
|
DWORD index;
|
|
DWORD Offset;
|
|
CHAR IndexKey[ 255];
|
|
|
|
JetError = JetCreateTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME,
|
|
RESUME_TABLE_PAGE_COUNT, RESUME_TABLE_DENSITY, &pSession->ResumeTableId);
|
|
if ( JetError == JET_errTableDuplicate) {
|
|
//
|
|
// This would happend only if last time we did not shutdown properly
|
|
// so ResumeTable never got deleted.
|
|
//
|
|
CallM( JetDeleteTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME));
|
|
JetError = JetCreateTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME,
|
|
RESUME_TABLE_PAGE_COUNT, RESUME_TABLE_DENSITY, &pSession->ResumeTableId);
|
|
}
|
|
if ( JetError != JET_errSuccess) {
|
|
return( MapJetError( JetError));
|
|
}
|
|
|
|
//
|
|
// Create columns. First initalize fields that do not change between
|
|
// addition of columns.
|
|
//
|
|
ColumnDef.cbStruct = sizeof(ColumnDef);
|
|
ColumnDef.columnid = 0;
|
|
ColumnDef.wCountry = 1;
|
|
ColumnDef.langid = 0x0409; // USA english
|
|
ColumnDef.cp = 1200; // UNICODE codepage
|
|
ColumnDef.wCollate = 0;
|
|
ColumnDef.cbMax = 0;
|
|
|
|
for ( index = 0; index < RESUME_TABLE_LENGTH; index++) {
|
|
|
|
ColumnDef.coltyp = ResumeTable[ index].ColumnType;
|
|
//
|
|
// All columns are variable length, but resume handle is autoincrement
|
|
// as well.
|
|
//
|
|
ColumnDef.grbit = (index==RESUME_ResumeHandle) ?
|
|
JET_bitColumnAutoincrement : 0;
|
|
|
|
CallM( JetAddColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ index].ColumnName, &ColumnDef,
|
|
NULL, 0, &ResumeTable[ index].ColumnId));
|
|
}
|
|
|
|
//
|
|
// We need resume handle as an index, so that at Enum() time we quickly
|
|
// find resume value for a given resume handle. Beging primary index,
|
|
// this index is also unique.
|
|
//
|
|
Offset = AddKey( IndexKey, '+', ResumeTable[ RESUME_ResumeHandle].ColumnName);
|
|
IndexKey[ Offset++] = '\0';
|
|
CallM( JetCreateIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle,
|
|
JET_bitIndexPrimary, IndexKey, Offset, 50));
|
|
|
|
//
|
|
// We need server handle as an index, so that at Close() time we quickly
|
|
// enumerate all resume keys for a given server handle, then delete them.
|
|
// This index is NOT unique since we can have a number of resume handles
|
|
// per client.
|
|
//
|
|
Offset = AddKey( IndexKey, '+', ResumeTable[ RESUME_ServerHandle].ColumnName);
|
|
IndexKey[ Offset++] = '\0';
|
|
CallM( JetCreateIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ServerHandle,
|
|
0, IndexKey, Offset, 50));
|
|
|
|
#ifdef RPL_DEBUG
|
|
if ( RG_DebugLevel == (DWORD)(-1)) {
|
|
ResumeList( pSession, "ResumeCreateTable");
|
|
}
|
|
#endif // RPL_DEBUG
|
|
|
|
CallM( JetCloseTable( pSession->SesId, pSession->ResumeTableId));
|
|
return( ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
DWORD ResumeDeleteTable(
|
|
IN PRPL_SESSION pSession
|
|
)
|
|
{
|
|
if ( pSession->ResumeTableId != 0) {
|
|
CallM( JetCloseTable( pSession->SesId, pSession->ResumeTableId));
|
|
CallM( JetDeleteTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME));
|
|
}
|
|
return( NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL ResumeKeyGet(
|
|
IN PRPL_SESSION pSession,
|
|
IN DWORD ResumeHandle,
|
|
OUT PVOID ResumeValue,
|
|
IN OUT PDWORD pResumeSize
|
|
)
|
|
{
|
|
DWORD DataSize;
|
|
#ifdef RPL_DEBUG_NEVER
|
|
if ( RG_DebugLevel == (DWORD)(-1)) {
|
|
ResumeList( pSession, "++ResumeKeyGet");
|
|
}
|
|
#endif // RPL_DEBUG_NEVER
|
|
CallB( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle));
|
|
CallB( JetMakeKey( pSession->SesId, pSession->ResumeTableId, &ResumeHandle,
|
|
sizeof( ResumeHandle), JET_bitNewKey));
|
|
CallB( JetSeek( pSession->SesId, pSession->ResumeTableId, JET_bitSeekEQ));
|
|
CallB( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ RESUME_ResumeValue].ColumnId, ResumeValue,
|
|
*pResumeSize, &DataSize, 0, NULL));
|
|
if ( DataSize > *pResumeSize) {
|
|
RplDump( ++RG_Assert, ( "DataSize=%d", DataSize));
|
|
return( FALSE);
|
|
}
|
|
*pResumeSize = DataSize;
|
|
return( TRUE);
|
|
}
|
|
|
|
|
|
BOOL ResumeKeySet(
|
|
IN PRPL_SESSION pSession,
|
|
IN DWORD ServerHandle,
|
|
IN PVOID ResumeValue,
|
|
IN DWORD ResumeSize,
|
|
OUT PDWORD pResumeHandle
|
|
)
|
|
{
|
|
DWORD DataSize;
|
|
|
|
*pResumeHandle = 0; // just in case we fail below
|
|
|
|
#ifdef RPL_DEBUG
|
|
if ( RG_DebugLevel == (DWORD)(-1)) {
|
|
ResumeList( pSession, "++ResumeKeySet");
|
|
}
|
|
#endif // RPL_DEBUG
|
|
|
|
CallB( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle));
|
|
#if 0
|
|
//
|
|
// We do NOT call JetMove() here, because in the case of an empty table
|
|
// it returns error JET_errNoCurrentRecord. Also, if JetMove() is used
|
|
// here, then ordering of elements in the table is such that ResumePrune()
|
|
// function deletes only the OLDEST record for a given server handle.
|
|
//
|
|
CallB( JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveLast, 0));
|
|
#endif
|
|
CallB( JetPrepareUpdate( pSession->SesId, pSession->ResumeTableId, JET_prepInsert));
|
|
CallB( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ RESUME_ResumeHandle].ColumnId, pResumeHandle,
|
|
sizeof( *pResumeHandle), &DataSize, JET_bitRetrieveCopy, NULL));
|
|
if ( DataSize != sizeof( *pResumeHandle) || *pResumeHandle == 0) {
|
|
RplDump( ++RG_Assert, ( "DataSize=%d", DataSize));
|
|
return( FALSE);
|
|
}
|
|
CallB( JetSetColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ RESUME_ResumeValue].ColumnId, ResumeValue,
|
|
ResumeSize, 0, NULL));
|
|
CallB( JetSetColumn( pSession->SesId, pSession->ResumeTableId,
|
|
ResumeTable[ RESUME_ServerHandle].ColumnId, &ServerHandle,
|
|
sizeof( ServerHandle), 0, NULL));
|
|
CallB( JetUpdate( pSession->SesId, pSession->ResumeTableId, NULL, 0, NULL));
|
|
#ifdef RPL_DEBUG
|
|
if ( RG_DebugLevel & RPL_DEBUG_RESUME) {
|
|
WCHAR ValueBuffer[ 32];
|
|
DWORD Length;
|
|
PWCHAR Value;
|
|
Length = wcslen( (PWCHAR)ResumeValue);
|
|
if ( (Length + 1) * sizeof(WCHAR) < ResumeSize) {
|
|
wcscpy( ValueBuffer, (PWCHAR)ResumeValue);
|
|
wcscat( ValueBuffer, L"!");
|
|
wcscat( ValueBuffer, (PWCHAR)ResumeValue + Length + 1);
|
|
Value = ValueBuffer;
|
|
} else {
|
|
Value = (PWCHAR)ResumeValue;
|
|
}
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_RESUME, (
|
|
"ResumeKeySet: Handle=0x%x, Value=%.20ws", *pResumeHandle, Value));
|
|
}
|
|
#endif // RPL_DEBUG
|
|
return( TRUE);
|
|
}
|
|
|
|
|
|
VOID ResumePrune(
|
|
IN PRPL_SESSION pSession,
|
|
IN DWORD ServerHandle
|
|
)
|
|
/*++
|
|
This function returns no errors, since failure to delete old resume handles
|
|
is not considered fatal (and there is very little we can do about this).
|
|
--*/
|
|
{
|
|
JET_ERR JetError;
|
|
|
|
#ifdef RPL_DEBUG
|
|
if ( RG_DebugLevel == (DWORD)(-1)) {
|
|
ResumeList( pSession, "++ResumePrune");
|
|
}
|
|
#endif // RPL_DEBUG
|
|
CallR( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ServerHandle));
|
|
CallR( JetMakeKey( pSession->SesId, pSession->ResumeTableId, &ServerHandle,
|
|
sizeof( ServerHandle), JET_bitNewKey));
|
|
#ifdef NOT_YET
|
|
JetError = JetSeek( pSession->SesId, pSession->ResumeTableId, JET_bitSeekEQ);
|
|
#else
|
|
JetError = JetSeek( pSession->SesId, pSession->ResumeTableId, JET_bitSeekEQ | JET_bitSetIndexRange);
|
|
#endif
|
|
if ( JetError == JET_errSuccess) {
|
|
#ifdef NOT_YET
|
|
CallR( JetMakeKey( pSession->SesId, pSession->ResumeTableId, &ServerHandle,
|
|
sizeof( ServerHandle), JET_bitNewKey));
|
|
CallR( JetSetIndexRange( pSession->SesId, pSession->ResumeTableId,
|
|
JET_bitRangeInclusive | JET_bitRangeUpperLimit));
|
|
#endif
|
|
do {
|
|
Call( JetDelete( pSession->SesId, pSession->ResumeTableId));
|
|
JetError = JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveNext, 0);
|
|
} while ( JetError == JET_errSuccess);
|
|
}
|
|
#ifdef RPL_DEBUG
|
|
if ( RG_DebugLevel == (DWORD)(-1)) {
|
|
ResumeList( pSession, "--ResumePrune");
|
|
}
|
|
#endif // RPL_DEBUG
|
|
}
|
|
|