home *** CD-ROM | disk | FTP | other *** search
- // rootrefs.hpp
- //
- // Created 10/06/98
- //
- // (C)Copyright 1998-1999 Microsoft Corporation, All rights reserved.
- //
-
- #ifndef __ROOTREFS_HPP__
- #define __ROOTREFS_HPP__
-
- #include "ids.hpp"
-
-
- class RootReferencesRecorder
- {
- struct RootRecord
- {
- ID rootid;
- unsigned nrefs;
- ObjectID refs[1];
- };
-
- struct RecordsPage
- {
- size_t size;
- RecordsPage *next;
- RootRecord records[1];
- };
-
- RecordsPage *pages;
- RootRecord *lastrecord;
- #ifdef DEBUG
- unsigned pagecount;
- #endif
-
- // BUGBUG
- #define OS_PAGE_SIZE 4096
- #define INITIAL_REFS_PER_PAGE ((OS_PAGE_SIZE-sizeof(RecordsPage)+sizeof(ObjectID))/sizeof(ObjectID))
-
-
- RootRecord *GetNewRootRecord (ID root, unsigned nrefs, ObjectID **pstop)
- {
- RootRecord *rec = NULL;
-
- size_t size = sizeof(RecordsPage)+(nrefs-1)*sizeof(ObjectID);
- #ifndef DEBUG
- size = ((size + OS_PAGE_SIZE - 1) & ~(OS_PAGE_SIZE-1));
- #endif
- // TODO wastes 15 uncommitted pages
- RecordsPage *newpage = (RecordsPage*)VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- if (newpage != NULL)
- {
- newpage->size = size;
-
- rec = &newpage->records[0];
-
- rec->rootid = root;
- rec->nrefs = 0;
-
- newpage->next = pages;
- pages = newpage;
-
- #ifdef DEBUG
- pagecount++;
- ASSERT(pagecount < 1000);
- #endif
-
- lastrecord = rec;
-
- *pstop = (ObjectID*)((BYTE*)newpage+size);
- }
-
- return rec;
- }
-
- RootRecord *GetRootRecord (ID root, ObjectID **pstop)
- {
- if (lastrecord != NULL)
- {
- ObjectID *stop = (ObjectID*)((BYTE*)pages+pages->size);
-
- ASSERT((BYTE*)lastrecord >= (BYTE*)pages && (BYTE*)lastrecord + sizeof(RootRecord) <= (BYTE*)stop);
-
- if (lastrecord->rootid == root)
- {
- *pstop = stop;
- return lastrecord;
- }
-
- BYTE *lastend = (BYTE*)&lastrecord->refs[lastrecord->nrefs];
-
- if (lastend + sizeof(RootRecord) < (BYTE*)stop)
- {
- lastrecord = (RootRecord*)lastend;
- lastrecord->rootid = root;
- lastrecord->nrefs = 0;
- *pstop = stop;
- return lastrecord;
- }
- }
-
- return GetNewRootRecord(root, INITIAL_REFS_PER_PAGE, pstop);
- }
-
- BOOL RecordReferences (RootRecord *rec, ObjectID *stop, unsigned *pnrefs, const ObjectID **prefs)
- {
- const ObjectID *refs = *prefs;
- unsigned nrefs = *pnrefs;
-
- ObjectID *dest = &rec->refs[rec->nrefs];
-
- unsigned ntocopy = min(nrefs, (unsigned)(stop - dest));
-
- CopyMemory(dest, refs, ntocopy*sizeof(ObjectID));
-
- rec->nrefs += ntocopy;
- *pnrefs = nrefs - ntocopy;
- *prefs = refs + ntocopy;
-
- return TRUE;
- }
-
- public:
-
- RootReferencesRecorder ()
- {
- pages = NULL;
- lastrecord = NULL;
- #ifdef DEBUG
- pagecount = 0;
- #endif
- }
-
- ~RootReferencesRecorder ()
- {
- Reset();
- }
-
- BOOL AddRootReferences (ID root, unsigned nrefs, const ObjectID *refs)
- {
- BOOL result;
-
- ObjectID *stop = NULL;
- RootRecord *rec = GetRootRecord(root, &stop);
- result = (rec != NULL);
- if (result)
- {
- for (;;)
- {
- result = RecordReferences(rec, stop, &nrefs, &refs);
- if (!result || !nrefs)
- break;
-
- rec = GetNewRootRecord(root, nrefs, &stop);
- result = (rec != NULL);
- if (!result)
- break;
- }
- }
-
- return result;
- }
-
- typedef int IterateProc (ID rootid, ObjectID refid, PVOID token);
-
- int Iterate (IterateProc *cb, PVOID token)
- {
- int result = 1;
-
- RecordsPage *page = pages;
- while (page != NULL)
- {
- RootRecord *rec = &page->records[0];
-
- for (;;)
- {
- ID rootid = rec->rootid;
- if (rootid == NULL)
- break;
-
- ObjectID *id = &rec->refs[0];
- ObjectID *stop = id + rec->nrefs;
-
- while (id < stop)
- {
- result = (*cb)(rootid, *id, token);
- if (result <= 0)
- break;
- id++;
- }
-
- if ((BYTE*)stop == (BYTE*)page+page->size)
- break;
- rec = (RootRecord*)stop;
- }
-
- page = page->next;
- }
-
- return result;
- }
-
- typedef int IterateRootsProc (ID rootid, PVOID token);
-
- int IterateRoots (IterateRootsProc *cb, PVOID token)
- {
- int result = 1;
-
- RecordsPage *page = pages;
- while (page != NULL)
- {
- RootRecord *rec = &page->records[0];
-
- for (;;)
- {
- ID rootid = rec->rootid;
- if (rootid == NULL)
- break;
-
- ObjectID *id = &rec->refs[0];
- ObjectID *stop = id + rec->nrefs;
-
- result = (*cb)(rootid, token);
- if (result <= 0)
- break;
-
- if ((BYTE*)stop == (BYTE*)page+page->size)
- break;
- rec = (RootRecord*)stop;
- }
-
- page = page->next;
- }
-
- return result;
- }
-
- VOID Reset ()
- {
- RecordsPage *page = pages;
- while (page != NULL)
- {
- RecordsPage *trash = page;
- page = page->next;
- EVAL(VirtualFree(trash, trash->size, MEM_DECOMMIT));
- EVAL(VirtualFree(trash, 0, MEM_RELEASE));
- }
- pages = NULL;
- lastrecord = NULL;
- #ifdef DEBUG
- pagecount = 0;
- #endif
- }
- };
-
-
- #endif /* __ROOTREFS_HPP__ */
-
-