📄 abspage.pas
字号:
// Set length of array to specified size
//------------------------------------------------------------------------------
procedure TABSSortedPageList.SetSize(newSize: integer);
begin
if (newSize = 0) then
begin
ItemCount := 0;
allocItemCount := 0;
KeyItems := nil;
ValueItems := nil;
Exit;
end;
if (newSize > allocItemCount) then
begin
AllocBy := AllocBy * 2;
if (AllocBy > MaxAllocBy) then
AllocBy := MaxAllocBy;
if (allocItemCount + AllocBy > newSize) then
allocItemCount := allocItemCount + AllocBy
else
allocItemCount := newSize;
SetLength(KeyItems,allocItemCount);
SetLength(ValueItems,allocItemCount);
end
else
if (newSize < ItemCount) then
if (allocItemCount-newSize > deAllocBy) then
begin
deAllocBy := deAllocBy * 2;
if (deAllocBy > MaxAllocBy) then
deAllocBy := MaxAllocBy;
SetLength(KeyItems,newSize);
SetLength(ValueItems,newSize);
allocItemCount := newSize;
end;
ItemCount := newSize;
end;//SetSize
////////////////////////////////////////////////////////////////////////////////
//
// TABSPageManager
//
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
// lock
//------------------------------------------------------------------------------
procedure TABSPageManager.Lock;
begin
EnterCriticalSection(FCSect);
end;// Lock
//------------------------------------------------------------------------------
// unlock
//------------------------------------------------------------------------------
procedure TABSPageManager.Unlock;
begin
LeaveCriticalSection(FCSect);
end;// Unlock
//------------------------------------------------------------------------------
// AddNewSession
//------------------------------------------------------------------------------
function TABSPageManager.AddNewSession(SessionID: TABSSessionID): Integer;
var
n: Integer;
begin
n := Length(FSessions);
SetLength(FSessions, n+1);
FSessions[n].SessionID := SessionID;
FSessions[n].DirtyPages := TABSSortedPageList.Create;
FSessions[n].AddedPageNumbers := TABSPagesArray.Create;
FSessions[n].RemovedPageNumbers := TABSPagesArray.Create;
Result := n;
end;// AddNewSession
//------------------------------------------------------------------------------
// FindSession
//------------------------------------------------------------------------------
function TABSPageManager.FindSession(SessionID: TABSSessionID; var SessionNo: Integer): Boolean;
var
i: Integer;
begin
Result := False;
for i := 0 to Length(FSessions)-1 do
if (FSessions[i].SessionID = SessionID) then
begin
Result := True;
SessionNo := i;
break;
end;
end;// FindSession
//------------------------------------------------------------------------------
// FindPage
//------------------------------------------------------------------------------
function TABSPageManager.FindPage(Pages: TABSSortedPageList; PageNo: TABSPageNo; var Page: TABSPage): Boolean;
begin
Page := nil;
Result := False;
if (Pages <> nil) then
begin
Page := TABSPage(Pages.Find(PageNo));
Result := (Page <> nil);
end;
end;// FindPage
//------------------------------------------------------------------------------
// return page count
//------------------------------------------------------------------------------
function TABSPageManager.GetPageCount: TABSPageNo;
begin
Result := FPageCount;
end; // GetPageCount
//------------------------------------------------------------------------------
// IsSafeNotToSyncPage
//------------------------------------------------------------------------------
function TABSPageManager.IsSafeNotToSyncPage(SessionID: TABSSessionID; Page: TABSPage): Boolean;
begin
Result := False;
// override in TABSDiskPageManager
end;// IsSafeNotToSyncPage
//------------------------------------------------------------------------------
// UpdatePageTableState
//------------------------------------------------------------------------------
procedure TABSPageManager.UpdatePageTableState(SessionID: TABSSessionID; Page: TABSPage);
begin
// override in TABSDiskPageManager
end;// UpdatePageTableState
//------------------------------------------------------------------------------
// RemovePageIfExists
//------------------------------------------------------------------------------
procedure TABSPageManager.RemovePageIfExists(Pages: TABSSortedPageList; PageNo: TABSPageNo);
var
Page: TABSPage;
begin
if (FindPage(Pages, PageNo, Page)) then
begin
Pages.Delete(PageNo);
Page.Free;
end;
end;// RemovePageIfExists
//------------------------------------------------------------------------------
// LoadFromStream
//------------------------------------------------------------------------------
procedure TABSPageManager.LoadFromStream(Stream: TStream);
begin
;
end; // LoadFromStream
//------------------------------------------------------------------------------
// SaveToStream
//------------------------------------------------------------------------------
procedure TABSPageManager.SaveToStream(Stream: TStream);
begin
;
end; // SaveToStream
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
constructor TABSPageManager.Create;
begin
InitializeCriticalSection(FCSect);
FCacheCapacity := min(1000, (MemoryManager.GetFreeMemorySize div 65536));
FSharedPages := TABSSortedPageList.Create;
FMultiUser := False;
end;// Create
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
destructor TABSPageManager.Destroy;
var
i: Integer;
begin
for i := 0 to Length(FSessions)-1 do
begin
if (FSessions[i].DirtyPages.Count > 0) then
raise EABSException.Create(20097, ErrorAUncommitedPages);
FSessions[i].DirtyPages.Free;
FSessions[i].AddedPageNumbers.Free;
FSessions[i].RemovedPageNumbers.Free;
end;
for i := 0 to FSharedPages.Count-1 do
FSharedPages.ValueItems[i].Page.Free;
FSharedPages.Free;
DeleteCriticalSection(FCSect);
end;// Destroy
//------------------------------------------------------------------------------
// AddPage
//------------------------------------------------------------------------------
function TABSPageManager.AddPage(SessionID: TABSSessionID; PageType: TABSPageTypeID): TABSPage;
var
SessionNo: Integer;
begin
if (not FindSession(SessionID, SessionNo)) then
SessionNo := AddNewSession(SessionID);
Result := TABSPage.Create(Self);
InternalAddPage(Result);
if (Result.PageNo = INVALID_PAGE_NO) then
raise EABSException.Create(20064, ErrorAInvalidPageNo);
Result.UseCount := Result.UseCount + 1;
Result.IsDirty := True;
Result.Reloaded := False;
if (Result.PageHeaderSize > 0) then
begin
Result.PageHeader^.PageType := PageType;
Result.PageHeader^.State := Random(MaxInt div 2);
end;
Result.ParentList := FSessions[SessionNo].DirtyPages;
Result.SessionID := SessionID;
{$IFDEF FILE_SERVER_VERSION}
// check for delete of page by another user
if (FSharedPages.Find(Result.PageNo) <> nil) then
FSharedPages.Delete(Result.PageNo);
{$ENDIF}
FSessions[SessionNo].DirtyPages.Insert(Result);
FSessions[SessionNo].AddedPageNumbers.Append(Result.PageNo);
end;// AddPage
//------------------------------------------------------------------------------
// RemovePage
//------------------------------------------------------------------------------
procedure TABSPageManager.RemovePage(SessionID: TABSSessionID; PageNo: TABSPageNo);
var
SessionNo: Integer;
begin
if (not FindSession(SessionID, SessionNo)) then
SessionNo := AddNewSession(SessionID);
FSessions[SessionNo].RemovedPageNumbers.Append(PageNo);
end;// RemovePage
//------------------------------------------------------------------------------
// GetPage
//------------------------------------------------------------------------------
function TABSPageManager.GetPage(SessionID: TABSSessionID; PageNo: TABSPageNo;
PageType: TABSPageTypeID; SynchronizeAllowed: Boolean = True): TABSPage;
var
SessionNo: Integer;
begin
if (SessionID = INVALID_SESSION_ID) then
raise EABSException.Create(20186, ErrorAInvalidSessionID);
if (not FindSession(SessionID, SessionNo)) then
SessionNo := AddNewSession(SessionID);
if (not (FindPage(FSessions[SessionNo].DirtyPages, PageNo, Result))) then
begin
if (FindPage(FSharedPages, PageNo, Result)) then
begin
if (SynchronizeAllowed and
not IsSafeNotToSyncPage(SessionID, Result)) then
begin
Result.Synchronize;
UpdatePageTableState(SessionID, Result);
end;
end
else
begin
Result := TABSPage.Create(Self);
Result.PageNo := PageNo;
Result.SessionID := SessionID;
FSharedPages.Insert(Result);
InternalReadPage(Result);
if ((Result.PageHeaderSize > 0) and (PageType <> ptAnyPage) and
(Result.PageHeader^.PageType <> PageType)) then
raise EABSException.Create(20153, ErrorAInvalidPageType, [PageType, Result.PageHeader^.PageType]);
UpdatePageTableState(SessionID, Result);
end;
Result.ParentList := FSharedPages;
end;
if ((Result.UseCount > 0) and (Result.SessionID <> SessionID)) then
raise EABSException.Create(20090, ErrorAPageIsUsedByOtherSession);
Result.SessionID := SessionID;
Result.UseCount := TABSPage(Result).UseCount + 1;
end;// GetPage
//------------------------------------------------------------------------------
// PutPage
//------------------------------------------------------------------------------
procedure TABSPageManager.PutPage(aPage: TABSPage);
var
SessionNo: Integer;
PageToRelease: TABSPage;
begin
{$IFDEF DEBUG_PAGES}
if (aPage.PageNo = INVALID_PAGE_NO) then
raise EABSException.Create(20065, ErrorAInvalidPageNo);
if ((aPage.PageHeaderSize > 0) and
(aPage.PageHeader^.PageType > ptLastType)) then
raise EABSException.Create(20154, ErrorAInvalidPage);
if (aPage.UseCount < 1) then
raise EABSException.Create(20163, ErrorAInvalidPageUseCount);
if (aPage.ParentList.Find(aPage.PageNo) = nil) then
raise EABSException.Create(20040, ErrorAUsedPageWasReleased);
{$ENDIF}
aPage.UseCount := aPage.UseCount - 1;
if (aPage.UseCount = 0) then
aPage.Reloaded := False;
// apply LRU cache (last items are more recently used) and dirty page move
if ((aPage.UseCount = 0) and (aPage.ParentList = FSharedPages)) then
begin
if (aPage.IsDirty) then
begin
FSharedPages.Delete(aPage.PageNo);
if (not FindSession(aPage.SessionID, SessionNo)) then
SessionNo := AddNewSession(aPage.SessionID);
FSessions[SessionNo].DirtyPages.Insert(aPage);
aPage.ParentList := FSessions[SessionNo].DirtyPages;
end
else
FSharedPages.UpdateLRU(aPage);
end;
if (aPage.ParentList = FSharedPages) then
// if cache overflow remove first unused pages
if (FSharedPages.Count > FCacheCapacity) then
begin
PageToRelease := FSharedPages.FirstByLRU;
while (PageToRelease <> nil) do
begin
if (PageToRelease.UseCount = 0) then
begin
FSharedPages.Delete(PageToRelease.PageNo);
PageToRelease.Free;
if (FSharedPages.Count <= FCacheCapacity) then
break;
end;
PageToRelease := FSharedPages.NextByLRU;
end;
end;
end;// PutPage
//------------------------------------------------------------------------------
// ApplyChanges
//------------------------------------------------------------------------------
procedure TABSPageManager.ApplyChanges(SessionID: TABSSessionID);
var
SessionNo: Integer;
i: Integer;
Page: TABSPage;
begin
for i:=0 to FSharedPages.Count-1 do
begin
Page := FSharedPages.ValueItems[i].Page;
if ((Page.SessionID = SessionID) and (Page.UseCount > 0)) then
raise EABSException.Create(20152, ErrorASomePagesAreNotReleased);
end;
if (FindSession(SessionID, SessionNo)) then
begin
// free removed pages
for i := 0 to FSessions[SessionNo].RemovedPageNumbers.ItemCount-1 do
begin
InternalRemovePage(FSessions[SessionNo].RemovedPageNumbers.Items[i]);
RemovePageIfExists(FSessions[SessionNo].DirtyPages,
FSessions[SessionNo].RemovedPageNumbers.Items[i]);
RemovePageIfExists(FSharedPages,
FSessions[SessionNo].RemovedPageNumbers.Items[i]);
end;
FSessions[SessionNo].RemovedPageNumbers.SetSize(0);
FSessions[SessionNo].AddedPageNumbers.SetSize(0);
// save dirty pages
for i := 0 to FSessions[SessionNo].DirtyPages.Count-1 do
begin
Page := FSessions[SessionNo].DirtyPages.ValueItems[i].Page;
if (not Page.IsDirty) then
raise EABSException.Create(20085, ErrorAInvalidDirtyPage);
if (Page.UseCount > 0) then
raise EABSException.Create(20086, ErrorACannotWriteUsedPage);
InternalWritePage(Page);
Page.IsDirty := False;
// move dirty page to shared pages list
if (FSharedPages.Count < FCacheCapacity) then
FSharedPages.Insert(Page)
else
Page.Free;
end;
FSessions[SessionNo].DirtyPages.Clear;
end;
end;// ApplyChanges
//------------------------------------------------------------------------------
// CancelChanges
//------------------------------------------------------------------------------
procedure TABSPageManager.CancelChanges(SessionID: TABSSessionID);
var
SessionNo: Integer;
i: Integer;
Page: TABSPage;
begin
if (FindSession(SessionID, SessionNo)) then
begin
// free dirty pages
for i := 0 to FSessions[SessionNo].DirtyPages.Count-1 do
begin
Page := FSessions[SessionNo].DirtyPages.ValueItems[i].Page;
if (not Page.IsDirty) then
raise EABSException.Create(20087, ErrorAInvalidIndexPage);
if (Page.UseCount > 0) then
raise EABSException.Create(20088, ErrorACannotRemoveUsedPage);
Page.Free;
end;
FSessions[SessionNo].DirtyPages.Clear;
// free added pages
for i := 0 to FSessions[SessionNo].AddedPageNumbers.ItemCount-1 do
InternalRemovePage(FSessions[SessionNo].AddedPageNumbers.Items[i]);
FSessions[SessionNo].RemovedPageNumbers.SetSize(0);
FSessions[SessionNo].AddedPageNumbers.SetSize(0);
end;
end;// CancelChanges
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -