⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abspage.pas

📁 Absolute Database 是来替代BDE[Borland数据库引擎]的用于Delphi 和 C++ Builder 开发用的数据库引擎. 它小巧, 高速, 健壮, 易于使用. 它能直接编译进
💻 PAS
📖 第 1 页 / 共 3 页
字号:
// 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 + -