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.
397 lines
9.5 KiB
397 lines
9.5 KiB
// ILStore ILMod
|
|
|
|
#include "pdbimpl.h"
|
|
#include "ilsimpl.h"
|
|
#include "ptr.h"
|
|
|
|
ILM::ILM(ILS* pils_)
|
|
{
|
|
pils = pils_;
|
|
pstream = 0;
|
|
write = FALSE;
|
|
}
|
|
|
|
ILM::~ILM() {
|
|
// ensure proper cleanup
|
|
assert(pstream == 0);
|
|
}
|
|
|
|
BOOL ILM::open(Stream* pstream_, BOOL write_) {
|
|
pstream = pstream_;
|
|
write = write_;
|
|
assert(pstream);
|
|
|
|
CB cb = pstream->QueryCb();
|
|
return (cb == 0 && init()) || (cb > 0 && reload());
|
|
}
|
|
|
|
BOOL ILM::release() {
|
|
assert(pstream);
|
|
|
|
BOOL OK = TRUE;
|
|
if (write)
|
|
OK &= save();
|
|
OK &= pstream->Release();
|
|
pstream = 0;
|
|
delete this;
|
|
return OK;
|
|
}
|
|
|
|
// first time initialization
|
|
BOOL ILM::init() {
|
|
return pool.init(pstream, 0);
|
|
}
|
|
|
|
// Save the ILM state to pstream.
|
|
//
|
|
// This is a bit complicated. The stream starts with some number of pages
|
|
// of ILPool StreamImage backing store, and is then followed by the
|
|
// serialization of the ILM state including other ILPool state. Finally
|
|
// we append 'cbPool', indicating both the size of the ILPool store and
|
|
// the starting offset of the ILM state serialization.
|
|
BOOL ILM::save() {
|
|
assert(pstream);
|
|
|
|
if (trace((trILM, "ILM::save() ")))
|
|
traceMapKtRilu();
|
|
|
|
// Save a record consisting of mapKtRilu, mapKeyILVer, pool, and cbPool.
|
|
Buffer buf;
|
|
if (!mapKtRilu.save(&buf))
|
|
return FALSE;
|
|
traceOnly(CB cbMap1 = buf.Size());
|
|
|
|
if (!mapKeyILVer.save(&buf))
|
|
return FALSE;
|
|
traceOnly(CB cbMap2 = buf.Size());
|
|
|
|
CB cbPool = cbNil;
|
|
if (!pool.save(&buf, &cbPool))
|
|
return FALSE;
|
|
traceOnly(CB cbPool2 = buf.Size());
|
|
|
|
if (!buf.Append((PB)&cbPool, sizeof cbPool))
|
|
return FALSE;
|
|
|
|
trace((trSave, "ILM::save(); cbPool=%d cbMap1=%d cbMap2=%d cbPool2=%d cbTotal=%d\n",
|
|
cbPool, cbMap1, cbMap2 - cbMap1, cbPool2 - cbMap2, cbPool + buf.Size()));
|
|
return pstream->Truncate(cbPool) && pstream->Append(buf.Start(), buf.Size());
|
|
}
|
|
|
|
// Reload the ILM state. See ILM::save comments for the ILM state format.
|
|
BOOL ILM::reload() {
|
|
assert(pstream);
|
|
|
|
Buffer buf;
|
|
PB pb;
|
|
|
|
// First read cbPool from the end of the stream; this indicates
|
|
// the stream offset of the rest of the ILM state.
|
|
CB cbPool = cbNil;
|
|
CB cbStream = pstream->QueryCb();
|
|
if (cbStream < sizeof(cbPool) ||
|
|
!pstream->Read2(cbStream - sizeof(cbPool), &cbPool, sizeof(cbPool)))
|
|
goto fail;
|
|
|
|
// Read the ILM state which follows the ILPool stream image state.
|
|
{
|
|
CB cbState = cbStream - cbPool;
|
|
if (cbState < 0 ||
|
|
!buf.Reserve(cbState, &pb) ||
|
|
!pstream->Read2(cbPool, pb, cbState))
|
|
goto fail;
|
|
}
|
|
|
|
// Reinitialize the ILPool StreamImage.
|
|
if (!pool.init(pstream, cbPool))
|
|
goto fail;
|
|
|
|
// Deserialize ILM state.
|
|
if (!mapKtRilu.reload(&pb) ||
|
|
!mapKeyILVer.reload(&pb) ||
|
|
!pool.reload(&pb))
|
|
goto fail;
|
|
|
|
// Check we're back to cbPool.
|
|
{
|
|
CB cbPool2 = *((CB*&)pb)++;
|
|
if (cbPool2 != cbPool || pb != buf.End())
|
|
return FALSE;
|
|
}
|
|
|
|
trace((trILM, "ILM::reload() "));
|
|
traceMapKtRilu();
|
|
return TRUE;
|
|
|
|
fail:
|
|
trace((trILM, "ILM::reload() fails\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
#pragma inline_depth(0)
|
|
void ILM::traceMapKtRilu()
|
|
{
|
|
trace((trILM, "{\n"));
|
|
EnumMap<KT,RILU,HcKt> e(mapKtRilu);
|
|
while (e.next()) {
|
|
KT kt;
|
|
RILU rilu;
|
|
e.get(&kt, &rilu);
|
|
trace((trILM, "\tkt=(%d,%d) rilu=(%d, %d, %x)\n", kt.key, kt.ilstype, rilu.ilspace, rilu.off, rilu.sig));
|
|
}
|
|
trace((trILM, "}\n"));
|
|
}
|
|
#pragma inline_depth()
|
|
|
|
// Reinitialize this ILM to its pristine, no IL contents state.
|
|
BOOL ILM::reset() {
|
|
// Release any shared ILU reference this module may have made, then reset
|
|
// the non-shared pool and the existing key->ILU mapping.
|
|
EnumMap<KT,RILU,HcKt> e(mapKtRilu);
|
|
while (e.next()) {
|
|
KT kt;
|
|
RILU rilu;
|
|
e.get(&kt, &rilu);
|
|
if (rilu.ilspace != ilspaceShared)
|
|
continue;
|
|
|
|
// fetch the referenced ILU
|
|
ILU* pilu = piluForRilu(rilu);
|
|
if (!pilu)
|
|
return FALSE;
|
|
|
|
// remove the ILU from this pool
|
|
if (!pils->poolShared.remove(pilu, rilu.off))
|
|
return FALSE;
|
|
}
|
|
|
|
mapKtRilu.reset();
|
|
pool.reset();
|
|
return TRUE;
|
|
}
|
|
|
|
// Get the IL version no. for the given key.
|
|
BOOL ILM::getILVer(KEY key, OUT ILVer *pilver) {
|
|
dassert(pilver);
|
|
|
|
return mapKeyILVer.map(key, pilver);
|
|
}
|
|
|
|
// Note that the IL for the given key has changed, by incrementing
|
|
// its IL version number. But do not exceed ilverMax!
|
|
BOOL ILM::noteILChanged(KEY key) {
|
|
ILVer* pilver;
|
|
if (mapKeyILVer.map(key, &pilver)) {
|
|
if (*pilver < ilverMax)
|
|
++*pilver;
|
|
return TRUE;
|
|
} else {
|
|
ILVer ilver = ilverNew;
|
|
return mapKeyILVer.add(key, ilver);
|
|
}
|
|
}
|
|
|
|
// Get the IL for the given (key, ilstype) pair into *pbuf,
|
|
// its signature into *psig.
|
|
BOOL ILM::getIL(KEY key, ILSType ilstype, OUT Buf *pbuf, OUT SIG* psig) {
|
|
trace((trILM, "ILM::getIL(key=%d, ilst=%d, ) ", key, ilstype));
|
|
|
|
// map the (key, ilstype) pair to an ILU ref
|
|
KT kt = _KT(key, ilstype);
|
|
RILU rilu;
|
|
if (!mapKtRilu.map(kt, &rilu)) {
|
|
trace((trILM, "fails (map)\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// fetch the referenced ILU
|
|
ILU* pilu = piluForRilu(rilu);
|
|
if (!pilu) {
|
|
trace((trILM, "fails (piluForRilu)\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// set the out parameters
|
|
if (pbuf)
|
|
*pbuf = Buf(pilu->rgb, pilu->cb);
|
|
if (psig)
|
|
*psig = pilu->sig;
|
|
|
|
trace((trILM, "succeeds, buf=(%x, %d), sig=%x\n", pilu->rgb, pilu->cb, pilu->sig));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL ILM::getAllIL(ILSType ilstype, OUT Buf* pbuf) {
|
|
trace((trILM, "ILM::getAllIL(ilst=%d, ) ",ilstype));
|
|
bufAllIL.Reset();
|
|
|
|
EnumMap<KT,RILU,HcKt> e(mapKtRilu);
|
|
while (e.next()) {
|
|
KT kt;
|
|
RILU rilu;
|
|
e.get(&kt, &rilu);
|
|
if (kt.ilstype == ilstype) {
|
|
ILU* pilu = piluForRilu(rilu);
|
|
if (!pilu) {
|
|
trace((trILM, "fails (piluForRilu)\n"));
|
|
return FALSE;
|
|
}
|
|
if (!bufAllIL.Append(pilu->rgb, pilu->cb)) {
|
|
trace((trILM, "fails (bufAllIL.Append)\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
*pbuf = Buf(bufAllIL.Start(), bufAllIL.Size());
|
|
return TRUE;
|
|
}
|
|
|
|
// Put the IL in buf at (key, ilstype); ilspace is a hint as to the preferred
|
|
// space to keep the IL (per module or shared).
|
|
BOOL ILM::putIL(KEY key, ILSType ilstype, Buf buf, ILSpace ilspace) {
|
|
trace((trILM, "ILM::putIL(key=%d, ilst=%d, buf=(%x, %d), ilsp=%d, ) ",
|
|
key, ilstype, buf.pb, buf.cb, ilspace));
|
|
|
|
// map the (key, ilstype) pair to an ILU ref, if it already exists
|
|
KT kt = _KT(key, ilstype);
|
|
RILU rilu;
|
|
SIG sig = SigForPbCb(buf.pb, buf.cb, (SIG)-1);
|
|
if (mapKtRilu.map(kt, &rilu)) {
|
|
if (rilu.ilspace == ilspace && rilu.sig == sig) {
|
|
// ILU already exists and has the same signature; don't update it,
|
|
// assume it is identical and early out.
|
|
trace((trILM, "succeeds (no change)\n"));
|
|
return TRUE;
|
|
}
|
|
// ILU exists but has different ILSpace or signature; update it.
|
|
if (!mapKtRilu.remove(kt)) {
|
|
trace((trILM, "fails (1)\n"));
|
|
return FALSE;
|
|
}
|
|
ILPool* ppoolPrev = ilpoolForILSpace(rilu.ilspace);
|
|
ILU* piluPrev = piluForRilu(rilu);
|
|
if (!ppoolPrev || !piluPrev || !ppoolPrev->remove(piluPrev, rilu.off)) {
|
|
trace((trILM, "fails (2)\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// trivially an empty buffer requires no state
|
|
if (buf.cb == 0) {
|
|
trace((trILM, "succeeds (empty buffer)\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
// add the ILU to the specified pool; determine its offset within that pool
|
|
ILPool *ppool = ilpoolForILSpace(ilspace);
|
|
OFF off;
|
|
if (!ppool || !ppool->add(buf, sig, &off)) {
|
|
trace((trILM, "fails (3)\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// establish a mapping to it from kt
|
|
rilu = _RILU(ilspace, off, sig);
|
|
if (mapKtRilu.add(kt, rilu)) {
|
|
trace((trILM, "succeeds, rilu=(%d, %d, %x)\n", ilspace, off, sig));
|
|
|
|
// REVIEW. Whether or not changing the IL constitutes an ILChange
|
|
// should be a "getILSType()" settable ilstype property.
|
|
if (ilstype == ilstypeEX || ilstype == ilstypeSY || ilstype == ilstypeIN)
|
|
return noteILChanged(key);
|
|
else
|
|
return TRUE;
|
|
} else {
|
|
trace((trILM, "fails (4)\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Delete any IL for this (key, ilstype) from this module's map and from the
|
|
// ILPool. Return TRUE if all is well.
|
|
//
|
|
BOOL ILM::deleteIL(KEY key, ILSType ilstype) {
|
|
KT kt = _KT(key, ilstype);
|
|
RILU rilu;
|
|
if (mapKtRilu.mapThenRemove(kt, &rilu)) {
|
|
ILPool* ppool = ilpoolForILSpace(rilu.ilspace);
|
|
ILU* pilu = piluForRilu(rilu);
|
|
return ppool && pilu && ppool->remove(pilu, rilu.off);
|
|
} else
|
|
return TRUE;
|
|
}
|
|
|
|
inline ILU* ILM::piluForRilu(const RILU& rilu) {
|
|
// fetch the referenced ILPool
|
|
ILPool* ppool = ilpoolForILSpace(rilu.ilspace);
|
|
if (!ppool)
|
|
return 0;
|
|
|
|
// fetch the referenced ILU from that pool
|
|
ILU* pilu;
|
|
return ppool->loadILU(rilu.off, &pilu) ? pilu : 0;
|
|
}
|
|
|
|
inline ILPool* ILM::ilpoolForILSpace(ILSpace ilspace) {
|
|
switch (ilspace) {
|
|
case ilspaceMod:
|
|
return &pool;
|
|
case ilspaceShared:
|
|
return &pils->poolShared;
|
|
default:
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL ILM::getEnumILKT(OUT EnumKeyType** ppenum) {
|
|
return !!(*ppenum = new EnumKT(mapKtRilu));
|
|
}
|
|
|
|
BOOL ILM::getInfo( OUT CB *pcStreamSz, OUT CB *pcTotalILU,
|
|
OUT ULONG *pnumberOfILU, OUT CB *pcTotShILU, OUT ULONG *pNumSharedILU ) {
|
|
#ifdef _DEBUG
|
|
if( pcStreamSz ) *pcStreamSz = pstream->QueryCb();
|
|
EnumKeyType* peKeyType;
|
|
KEY key;
|
|
ILSType ilt;
|
|
ILSpace ils;
|
|
Buf buf;
|
|
SIG sig;
|
|
ULONG uILU, uShILU;
|
|
CB size, sizeSh;
|
|
size = sizeSh = uILU = uShILU = 0;
|
|
|
|
if( getEnumILKT( &peKeyType ) ) {
|
|
peKeyType->reset();
|
|
while( peKeyType->next() ) {
|
|
peKeyType->get(&key, &ilt, &ils);
|
|
if( ils == ilspaceMod ) {
|
|
if(getIL(key, ilt, &buf, &sig)) {
|
|
uILU++;
|
|
size += buf.cb;
|
|
}
|
|
} else if( ils == ilspaceShared ) {
|
|
if(getIL(key, ilt, &buf, &sig)) {
|
|
uShILU++;
|
|
sizeSh += buf.cb;
|
|
}
|
|
}
|
|
}
|
|
peKeyType->release();
|
|
}
|
|
|
|
ULONG uILU2, uDupILU;
|
|
CB size2, dupSize;
|
|
pool.getInfo( &size2, &uILU2, &dupSize, &uDupILU);
|
|
|
|
if(pcTotalILU) *pcTotalILU = size2;
|
|
if(pnumberOfILU) *pnumberOfILU = uILU2;
|
|
if(pcTotShILU) *pcTotShILU = sizeSh;
|
|
if(pNumSharedILU) *pNumSharedILU = uShILU;
|
|
return ((size == dupSize) && (uILU == uDupILU));
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|