Ascertaining the distribution of data pages

Below is an example of an IBEBlock which scans a database file and retrieves some useful information about the distribution of database pages. You can also find this block in the \Blocks\Samples\DB Pages Statistics directory.

   execute ibeblock (DBFileName varchar(1000) comment 'Path to database file')
   returns (
     PageType varchar(100) comment 'Page Type',
     PageCount integer comment 'Page Count',
     PagePercent numeric(15,2) comment 'Page %',
     PageMb numeric(15,2) comment 'Size, Mb')
   as
   begin
     TimeStart = ibec_GetTickCount();
     iPageIndex = 0;
     aPages = ibec_Array(0,0,0,0,0,0,0,0,0,0,0);
     aPageTypes = ibec_Array('Unused', 'Database Header', 'Page Inventory Page', 'Transaction Inventory Page', 'Pointer Page',
                             'Data Page', 'Index Root Page', 'Index Page', 'Blob Data Page', 'Generator Page', 'Write Ahead Log');

     aBitMasks = ibec_Array(1, 2, 4, 8, 16, 32, 64, 128);

     fs = ibec_fs_OpenFile(DBFileName, __fmOpenRead + __fmShareDenyNone);
     if (fs is null) then
       Exit;
     try
       ibec_fs_Seek(fs, 16, __soFromBeginning);

       iPageSize = ibec_fs_ReadWord(fs);
       iPageSizeSub20 = iPageSize - 20;

       ibec_fs_Seek(fs, iPageSize + 20, __soFromBeginning);
       sPIP = ibec_fs_ReadString(fs, iPageSizeSub20);
       NextPIPIndex = iPageSizeSub20 * 8 - 1;

       ibec_fs_Seek(fs, 0, __soFromBeginning);
       while (not ibec_fs_Eof(fs)) do
       begin
         if (ibec_mod(iPageIndex, 100) = 0) then
         begin
           TimeSpent = ibec_Div(ibec_GetTickCount() - TimeStart, 1000);
           iSpeed = ibec_IIF((iPageIndex = 0) or (TimeSpent = 0), 0, ((iPageSize / 1024) * iPageIndex) / 1024 / TimeSpent);
           ibec_Progress(iPageIndex || '  :  ' || TimeSpent || '  :  ' || iSpeed || ' Mb/s');
         end;
         iVal = ibec_fs_ReadByte(fs);

         iPIPBytePos = ibec_mod(ibec_div(iPageIndex, 8), iPageSizeSub20) + 1;
         iPIPBitMaskIdx = ibec_mod(iPageIndex, 8);
         if (iPIPBitMaskIdx = 0) then
           iPIPByte = ibec_Ord(ibec_Copy(sPIP, iPIPBytePos, 1));
         iPIPBitMask = aBitMasks[iPIPBitMaskIdx];
         IsUsed = (ibec_and(iPIPBitMask, iPIPByte) = 0);

         if (IsUsed) then
           aPages[iVal] = aPages[iVal] + 1;
         else
           aPages[0] = aPages[0] + 1;

         if (iPageIndex = NextPIPIndex) then
         begin
           ibec_fs_Seek(fs, 19, __soFromCurrent);
           sPIP = ibec_fs_ReadString(fs, iPageSizeSub20);
           NextPIPIndex = NextPIPIndex + iPageSizeSub20 * 8;
         end;

         iPageIndex = iPageIndex + 1;
         ibec_fs_Seek(fs, iPageIndex * iPageSize, __soFromBeginning);
       end;

       PageType = 'Total Pages';
       PageCount = iPageIndex;
       PagePercent = 100;
       PageMb = (PageCount * (iPageSize / 1024)) / 1024;
       suspend;

       foreach (aPages as PageCnt key Idx skip nulls) do
       begin
         PageType = aPageTypes[Idx];
         PageCount = PageCnt;
         PagePercent = (PageCnt/iPageIndex) * 100;
         PageMb = (PageCount * (iPageSize / 1024)) / 1024;
         suspend;
       end
     finally
       ibec_fs_CloseFile(fs);
     end
   end 

<< Accessing the input and return parameters when executing in a batch file | IBEBlock | >>