Skip to content

Commit 88213af

Browse files
authored
Merge pull request #6 from formeo/feature/refactoring
huge refactoring
2 parents 6b44c46 + 4fca3d1 commit 88213af

6 files changed

Lines changed: 90 additions & 61 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,5 @@ __recovery/
6464

6565
# Castalia statistics file (since XE7 Castalia is distributed with Delphi)
6666
*.stat
67+
* .idea
68+
*

FirebirdRepairBase.dpr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ uses
1515
uPageAnalyzer in 'uPageAnalyzer.pas',
1616
uBtreePage in 'uBtreePage.pas',
1717
uDatabaseStats in 'uDatabaseStats.pas',
18-
uFlagManager in 'uFlagManager.pas';
18+
uFlagManager in 'uFlagManager.pas',
19+
uRecordParser in 'uRecordParser.pas';
1920

2021
{$R *.res}
2122

FirebirdRepairBase.dproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
<DCCReference Include="uBtreePage.pas"/>
123123
<DCCReference Include="uDatabaseStats.pas"/>
124124
<DCCReference Include="uFlagManager.pas"/>
125+
<DCCReference Include="uRecordParser.pas"/>
125126
<BuildConfiguration Include="Base">
126127
<Key>Base</Key>
127128
</BuildConfiguration>

main.pas

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ interface
55
uses
66
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
77
Dialogs, StdCtrls, FileCtrl, ComCtrls, uStructs, DB, ExtCtrls,
8-
Menus, uCommon, uDatabase, XPMan, uDataPage, Grids, DBGrids, DBClient,
8+
Menus, uCommon, XPMan, uDataPage, Grids, DBGrids, DBClient,
99
DBCtrls, Spin, Vcl.Buttons,
10-
uPageAnalyzer, uDatabaseStats, uFlagManager;
10+
uPageAnalyzer, uDatabaseStats, uFlagManager, StrUtils;
1111

1212
type
1313
TfrmMain = class(TForm)
@@ -200,6 +200,7 @@ procedure TfrmMain.btnReWriteClick(Sender: TObject);
200200
PageInfo: TPageInfo;
201201
NewPageBuffer: TBytes;
202202
FileStream: TFileStream;
203+
ModifiedHeader: TPag; // --- ÄÎÁÀÂËÅÍÎ ---
203204
begin
204205
// ReWriting page - ÂÍÈÌÀÍÈÅ: Ýòî ÎÏÀÑÍÀß îïåðàöèÿ!
205206
if Application.MessageBox('Do You Want to Rewrite Database Page? THIS IS DANGEROUS!',
@@ -214,10 +215,18 @@ procedure TfrmMain.btnReWriteClick(Sender: TObject);
214215
PageInfo := FPageAnalyzer.GetPageInfo(PageNum);
215216
NewPageBuffer := Copy(PageInfo.Buffer); // Êîïèðóåì òåêóùèé áóôåð
216217

217-
// Ìîäèôèöèðóåì çàãîëîâîê â áóôåðå
218-
TPag(NewPageBuffer[0]).pag_checksum := UShort(NewChecksum);
218+
// --- ÈÑÏÐÀÂËÅÍÈÅ: Èñïîëüçóåì Move äëÿ áåçîïàñíîãî êîïèðîâàíèÿ è èçìåíåíèÿ çàãîëîâêà ---
219+
// Ñêîïèðóåì ñòàíäàðòíûé çàãîëîâîê èç áóôåðà â ëîêàëüíóþ ïåðåìåííóþ
220+
Move(NewPageBuffer[0], ModifiedHeader, SizeOf(TPag));
221+
222+
// Èçìåíèì ïîëÿ â ëîêàëüíîé ïåðåìåííîé
223+
ModifiedHeader.pag_checksum := UShort(NewChecksum);
219224
if (NewType >= 0) and (NewType <= $FF) then // Ïðîâåðÿåì äèàïàçîí
220-
TPag(NewPageBuffer[0]).pag_type := SChar(NewType);
225+
ModifiedHeader.pag_type := SChar(NewType);
226+
227+
// Ñêîïèðóåì èçìåí¸ííóþ ëîêàëüíóþ ïåðåìåííóþ îáðàòíî â áóôåð
228+
Move(ModifiedHeader, NewPageBuffer[0], SizeOf(TPag));
229+
// --- ÊÎÍÅÖ ÈÑÏÐÀÂËÅÍÈß ---
221230

222231
// Çàïèñûâàåì èçìåí¸ííûé áóôåð îáðàòíî â ôàéë
223232
FileStream := TFileStream.Create(FPageAnalyzer.FileName, fmOpenReadWrite or fmShareExclusive);
@@ -290,20 +299,19 @@ procedure TfrmMain.btnGetHeaderFlagsClick(Sender: TObject);
290299
try
291300
Flags := FFlagManager.GetFlags;
292301

293-
// Ôîðìèðóåì ñòðîêó äëÿ îòîáðàæåíèÿ (íàïðèìåð, áèíàðíîå ïðåäñòàâëåíèå èëè ïðîñòî ñïèñîê)
294-
// Äëÿ ïðîñòîòû, âûâåäåì ñïèñîê àêòèâíûõ ôëàãîâ
302+
295303
edtFlags.text := 'Active flags: ';
296304
if Flags.ActiveShadow then edtFlags.text := edtFlags.text + 'ActiveShadow, ';
297305
if Flags.ForceWrite then edtFlags.text := edtFlags.text + 'ForceWrite, ';
298306
if Flags.NoChecksums then edtFlags.text := edtFlags.text + 'NoChecksums, ';
299307
if Flags.NoReserve then edtFlags.text := edtFlags.text + 'NoReserve, ';
300308
if Flags.SqlDialect3 then edtFlags.text := edtFlags.text + 'SqlDialect3, ';
301309
if Flags.ReadOnly then edtFlags.text := edtFlags.text + 'ReadOnly, ';
302-
// Óáèðàåì ïîñëåäíþþ çàïÿòóþ
303-
if edtFlags.text.EndsWith(', ') then
304-
edtFlags.text := edtFlags.text.Remove(edtFlags.text.Length - 2);
305310

306-
// Èëè ìîæíî âûâåñòè âñå ôëàãè ñ óêàçàíèåì ñòàòóñà
311+
if EndsStr(', ', edtFlags.text) then // Èñïîëüçóåì EndsStr èç StrUtils
312+
edtFlags.text := Copy(edtFlags.text, 1, Length(edtFlags.text) - 2); // Óäàëÿåì ïîñëåäíèå 2 ñèìâîëà
313+
314+
307315
lstDBFlags.Items.Add(Format('Active Shadow: %s', [BoolToStr(Flags.ActiveShadow, True)]));
308316
lstDBFlags.Items.Add(Format('Force Write: %s', [BoolToStr(Flags.ForceWrite, True)]));
309317
lstDBFlags.Items.Add(Format('No Checksums: %s', [BoolToStr(Flags.NoChecksums, True)]));
@@ -348,28 +356,28 @@ procedure TfrmMain.checkDB;
348356
lstLog.Items.Add('Database page size: ' + IntToStr(FPageAnalyzer.PageSize));
349357
lstLog.Items.Add('Scanning pages...');
350358

351-
// Âû÷èñëÿåì ñòàòèñòèêó ÷åðåç FDatabaseStats
359+
352360
FDatabaseStats.CalculateStats;
353361

354-
// Ïîëó÷àåì ðåçóëüòàòû
362+
355363
PageStats := FDatabaseStats.PageStats;
356364
TxStats := FDatabaseStats.TransactionStats;
357365
RelStats := FDatabaseStats.RelationStats;
358366

359-
// Îáíîâëÿåì ïðîãðåññ áàð (äëÿ íàãëÿäíîñòè, õîòÿ òåïåðü ýòî áûñòðî)
367+
360368
pbDetectedPage.Min := 0;
361-
pbDetectedPage.Max := 100; // Óñëîâíî
369+
pbDetectedPage.Max := 100;
362370
pbDetectedPage.Position := 100;
363371

364-
// Âûâîäèì ðåçóëüòàòû ïîäñ÷åòà
372+
365373
lstLog.Items.Add('--- Page Type Summary ---');
366374
lstLog.Items.Add('Count Header Pages: ' + IntToStr(PageStats.HeaderPages));
367375
lstLog.Items.Add('Count Page Inventory Pages (PIP): ' + IntToStr(PageStats.PipPages));
368376
lstLog.Items.Add('Count Transaction Inventory Pages (TIP): ' + IntToStr(PageStats.TipPages));
369377
lstLog.Items.Add('Count Pointer Pages: ' + IntToStr(PageStats.PointerPages));
370378
lstLog.Items.Add('Count Data Pages: ' + IntToStr(PageStats.DataPages));
371379
lstLog.Items.Add('Count Index Root Pages: ' + IntToStr(PageStats.IndexRootPages));
372-
lstLog.Items.Add('Count Index B-Tree Pages: ' + IntToStr(PageStats.IndexBtreePages)); // Èñïðàâëåíî
380+
lstLog.Items.Add('Count Index B-Tree Pages: ' + IntToStr(PageStats.IndexBtreePages));
373381
lstLog.Items.Add('Count Blob Pages: ' + IntToStr(PageStats.BlobPages));
374382
lstLog.Items.Add('Count Generator Pages: ' + IntToStr(PageStats.GeneratorPages));
375383
lstLog.Items.Add('Count Write Ahead Log Pages: ' + IntToStr(PageStats.WalPages));
@@ -415,12 +423,10 @@ procedure TfrmMain.btnWriteFlagsClick(Sender: TObject);
415423
try
416424
NewFlags := FFlagManager.GetFlags;
417425

418-
// Îáíîâëÿåì ôëàãè â ñîîòâåòñòâèè ñ ÷åêáîêñàìè
426+
419427
NewFlags.ForceWrite := chkSetFW.Checked;
420428
NewFlags.ReadOnly := chkReadOnly.Checked;
421-
// Äîáàâüòå äðóãèå ôëàãè ïî íåîáõîäèìîñòè
422429

423-
// Óñòàíàâëèâàåì ôëàãè ÷åðåç FFlagManager
424430
FFlagManager.SetFlags(NewFlags);
425431

426432
Application.MessageBox('Header flags updated!', 'Information', MB_OK + MB_ICONINFORMATION);
@@ -452,14 +458,14 @@ procedure TfrmMain.UpdateFlagCheckboxesFromManager;
452458
end;
453459
end;
454460

455-
// tsFlagsShow - òåïåðü èñïîëüçóåò UpdateFlagCheckboxesFromManager
461+
456462
procedure TfrmMain.tsFlagsShow(Sender: TObject);
457463
begin
458-
// Îáíîâëÿåì ÷åêáîêñû ïðè ïîêàçå âêëàäêè
464+
459465
UpdateFlagCheckboxesFromManager;
460466
end;
461467

462-
// pgcServicesChange - îáíîâëÿåò MaxValue äëÿ sePosition
468+
463469
procedure TfrmMain.pgcServicesChange(Sender: TObject);
464470
begin
465471
if tsGenerateNewPage.Showing then
@@ -513,15 +519,13 @@ procedure TfrmMain.btnGotoPageClick(Sender: TObject);
513519
end;
514520

515521
btnGotoPage.Enabled := False;
516-
mmoData.Clear; // Î÷èùàåì Memo ïåðåä âûâîäîì
517-
518-
// Èñïîëüçóåì ôóíêöèþ èç uDataPage äëÿ èçâëå÷åíèÿ ôðàãìåíòîâ
522+
mmoData.Clear;
519523
PageFragments := ExtractDataFragments(PageInfo.Buffer, PageInfo.Size);
520524

521525
pbDataProgress.Min := 0;
522-
pbDataProgress.Max := Length(PageFragments) - 1; // Êîëè÷åñòâî ôðàãìåíòîâ
526+
pbDataProgress.Max := Length(PageFragments) - 1;
523527

524-
for i := 0 to High(PageFragments) do // Èñïîëüçóåì High äëÿ ìàññèâà
528+
for i := 0 to High(PageFragments) do
525529
begin
526530
pbDataProgress.Position := i;
527531
mmoData.Lines.Add('Fragment ' + IntToStr(i) + ', Offset: ' + IntToStr(PageFragments[i].Offset));

uBtreePage.pas

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
interface
44

55
uses
6-
Windows, SysUtils, uStructs;
6+
Windows, SysUtils, uStructs, Math;
77

88
const
99
pag_left = $01; // Ýòî ñàìàÿ ëåâàÿ ñòðàíèöà â óðîâíå
@@ -16,7 +16,6 @@ interface
1616
key_dupeq = $08; // Êëþ÷ ïîìå÷åí êàê äóáëèêàò (äëÿ óíèêàëüíûõ èíäåêñîâ)
1717

1818
type
19-
// Ôèêñèðîâàííàÿ ÷àñòü çàãîëîâêà B-Tree ñòðàíèöû
2019
TBtreePageHeader = packed record
2120
pag_header: TPag; // 0x00-0x0F - Ñòàíäàðòíûé çàãîëîâîê
2221
pag_next: SLong; // 0x10-0x13 - Óêàçàòåëü íà ñëåäóþùóþ ñòðàíèöó (ëèñò)
@@ -28,27 +27,31 @@ interface
2827
// pag_keys íà÷èíàåòñÿ ñ áàéòà 0x20
2928
end;
3029

31-
// Òèï äëÿ ïðåäñòàâëåíèÿ îäíîãî êëþ÷à
30+
3231
TBtreeKey = record
3332
Length: UShort;
3433
Flags: SChar;
35-
Data: TBytes; // Äàííûå êëþ÷à
36-
PageOrRecordNumber: SLong; // Äëÿ âíóòðåííèõ óçëîâ - íîìåð ñòðàíèöû, äëÿ ëèñòüåâ - íîìåð çàïèñè
34+
Data: TBytes;
35+
PageOrRecordNumber: SLong;
3736
end;
3837

39-
// Òèï äëÿ ìàññèâà êëþ÷åé
38+
4039
TBtreeKeyArray = array of TBtreeKey;
4140

42-
// Êëàññ äëÿ àíàëèçà B-Tree ñòðàíèöû
41+
4342
TBtreePageAnalyzer = class
4443
private
4544
FPageSize: Integer;
4645
FPageNumber: ULong; // Íîìåð ñàìîé B-Tree ñòðàíèöû (ïåðåäà¸òñÿ äëÿ êîíòåêñòà)
4746
FHeader: TBtreePageHeader;
4847
FPageData: TBytes; // Äàííûå âñåé ñòðàíèöû (äëÿ èçâëå÷åíèÿ êëþ÷åé)
4948

50-
// Âíóòðåííÿÿ ôóíêöèÿ äëÿ ïîëó÷åíèÿ êëþ÷à ïî ñìåùåíèþ
49+
5150
function GetKeyAtOffset(Offset: Integer): TBtreeKey;
51+
52+
function GetIsLeaf: Boolean;
53+
function GetIsRoot: Boolean;
54+
function GetIsLeftmost: Boolean;
5255
public
5356
// Êîíñòðóêòîð - ïðèíèìàåò áàéòû ñòðàíèöû, ðàçìåð ñòðàíèöû è íîìåð ñòðàíèöû
5457
constructor Create(const PageBuffer: TBytes; PageSize: Integer; PageNum: ULong);
@@ -67,11 +70,11 @@ TBtreePageAnalyzer = class
6770
// Ïîëó÷èòü íîìåð ðîäèòåëüñêîé ñòðàíèöû
6871
property ParentPage: SLong read FHeader.pag_parent;
6972
// Ýòî ëèñòîâàÿ ñòðàíèöà?
70-
property IsLeaf: Boolean read (FHeader.pag_flags and pag_leaf) <> 0;
73+
property IsLeaf: Boolean read GetIsLeaf; // Èñïîëüçóåì ìåòîä-ãåòòåð
7174
// Ýòî êîðíåâàÿ ñòðàíèöà?
72-
property IsRoot: Boolean read (FHeader.pag_flags and pag_root) <> 0;
75+
property IsRoot: Boolean read GetIsRoot; // Èñïîëüçóåì ìåòîä-ãåòòåð
7376
// Ýòî ñàìàÿ ëåâàÿ ñòðàíèöà?
74-
property IsLeftmost: Boolean read (FHeader.pag_flags and pag_left) <> 0;
77+
property IsLeftmost: Boolean read GetIsLeftmost; // Èñïîëüçóåì ìåòîä-ãåòòåð
7578

7679
end;
7780

@@ -107,32 +110,31 @@ function TBtreePageAnalyzer.GetKeyAtOffset(Offset: Integer): TBtreeKey;
107110
KeyFlags: SChar;
108111
KeyDataOffset, KeyPageOffset: Integer;
109112
begin
110-
// Ïðîâåðÿåì ãðàíèöû
113+
111114
if (Offset + 2 {key_length} + 1 {key_flags} > Length(FPageData)) then
112115
raise Exception.Create('Invalid offset for key in B-Tree page.');
113116

114-
// ×èòàåì key_length (2 áàéòà)
115117
KeyLength := PWord(@FPageData[Offset])^;
116118
Inc(Offset, 2);
117119

118-
// ×èòàåì key_flags (1 áàéò)
120+
119121
KeyFlags := PShortInt(@FPageData[Offset])^;
120122
Inc(Offset, 1);
121123

122-
// Ïðîâåðÿåì, íå âûõîäèò ëè äëèíà äàííûõ çà ïðåäåëû
124+
123125
if (Offset + KeyLength + 4 {key_page} > Length(FPageData)) then
124126
raise Exception.Create('Key length exceeds page boundary.');
125127

126-
// Êîïèðóåì key_data
128+
127129
SetLength(Result.Data, KeyLength);
128130
if KeyLength > 0 then
129131
Move(FPageData[Offset], Result.Data[0], KeyLength);
130132
Inc(Offset, KeyLength);
131133

132-
// ×èòàåì key_page (4 áàéòà)
134+
133135
Result.PageOrRecordNumber := PLongInt(@FPageData[Offset])^;
134136

135-
// Çàïîëíÿåì ïîëÿ ðåçóëüòàòà
137+
136138
Result.Length := KeyLength;
137139
Result.Flags := KeyFlags;
138140
end;
@@ -145,19 +147,32 @@ function TBtreePageAnalyzer.GetKeys: TBtreeKeyArray;
145147
begin
146148
SetLength(Keys, FHeader.pag_count);
147149

148-
// Ñìåùåíèå íà÷àëà ìàññèâà êëþ÷åé
150+
149151
CurrentOffset := SizeOf(TBtreePageHeader);
150152

151153
for i := 0 to FHeader.pag_count - 1 do
152154
begin
153155
Keys[i] := GetKeyAtOffset(CurrentOffset);
154-
155-
// Âû÷èñëÿåì ñìåùåíèå ñëåäóþùåãî êëþ÷à
156-
// key_length(2) + key_flags(1) + key_data(key_length) + key_page(4)
157156
CurrentOffset := CurrentOffset + 2 + 1 + Keys[i].Length + 4;
158157
end;
159158

160159
Result := Keys;
161160
end;
162161

162+
163+
function TBtreePageAnalyzer.GetIsLeaf: Boolean;
164+
begin
165+
Result := (FHeader.pag_flags and pag_leaf) <> 0;
166+
end;
167+
168+
function TBtreePageAnalyzer.GetIsRoot: Boolean;
169+
begin
170+
Result := (FHeader.pag_flags and pag_root) <> 0;
171+
end;
172+
173+
function TBtreePageAnalyzer.GetIsLeftmost: Boolean;
174+
begin
175+
Result := (FHeader.pag_flags and pag_left) <> 0;
176+
end;
177+
163178
end.

uDatabaseStats.pas

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -162,23 +162,27 @@ procedure TDatabaseStats.CalculateRelationStats;
162162
var
163163
PageNum: ULong;
164164
PageInfo: TPageInfo;
165-
DataPageHeader: TData_Page_Fixed_Part;
165+
DataPageHeader: TData_Page_Fixed_Part; // Òèï èç uDataPage
166166
Fragments: TRecordFragmentsArray;
167167
FoundRelation: Boolean;
168168
i, j: Integer;
169169
begin
170-
SetLength(FRelationStats, 0);
170+
// Èíèöèàëèçèðóåì ìàññèâ ñòàòèñòèêè ïî îòíîøåíèÿì
171+
SetLength(FRelationStats, 0); // Ïîêà ïóñòîé
171172

172173
for PageNum := 0 to FPageAnalyzer.GetLastPageNumber do
173174
begin
174175
PageInfo := FPageAnalyzer.GetPageInfo(PageNum);
175-
if PageInfo.Header.pag_type = pag_data then
176+
if PageInfo.Header.pag_type = pag_data then // pag_data = $05
176177
begin
178+
// Ïðîâåðÿåì, äîñòàòî÷íî ëè äàííûõ äëÿ ôèêñèðîâàííîé ÷àñòè çàãîëîâêà Data Page
177179
if Length(PageInfo.Buffer) >= SizeOf(TData_Page_Fixed_Part) then
178180
begin
179-
DataPageHeader := TData_Page_Fixed_Part(PageInfo.Buffer[0]);
181+
// --- ÈÑÏÐÀÂËÅÍÈÅ: Èñïîëüçóåì Move âìåñòî ïðÿìîãî ïðèâåäåíèÿ òèïà ---
182+
Move(PageInfo.Buffer[0], DataPageHeader, SizeOf(TData_Page_Fixed_Part));
180183
var RelationID := DataPageHeader.dpg_relation;
181184

185+
// Íàéäåì èíäåêñ äëÿ ýòîãî RelationID â ìàññèâå ñòàòèñòèêè
182186
FoundRelation := False;
183187
for j := 0 to High(FRelationStats) do
184188
begin
@@ -190,23 +194,24 @@ procedure TDatabaseStats.CalculateRelationStats;
190194
end;
191195
end;
192196

193-
197+
// Åñëè îòíîøåíèÿ íå áûëî â ìàññèâå, äîáàâèì åãî
194198
if not FoundRelation then
195199
begin
196200
SetLength(FRelationStats, Length(FRelationStats) + 1);
197201
FRelationStats[High(FRelationStats)].RelationID := RelationID;
198202
FRelationStats[High(FRelationStats)].PageCount := 1;
199-
FRelationStats[High(FRelationStats)].RecordCount := 0;
203+
FRelationStats[High(FRelationStats)].RecordCount := 0; // Ïîêà 0
200204
end;
201205

202-
203-
Fragments := ExtractDataFragments(PageInfo.Buffer, PageInfo.Size);
204-
206+
// Ïðèìåð: ïîäñ÷åò çàïèñåé (ôðàãìåíòîâ) íà ñòðàíèöå
207+
// Èçâëåêàåì ôðàãìåíòû
208+
Fragments := ExtractDataFragments(PageInfo.Buffer, PageInfo.Size); // ExtractDataFragments èç uDataPage
209+
// Íàéäåì èíäåêñ îòíîøåíèÿ ñíîâà äëÿ îáíîâëåíèÿ RecordCount
205210
for j := 0 to High(FRelationStats) do
206211
begin
207212
if FRelationStats[j].RelationID = RelationID then
208213
begin
209-
Inc(FRelationStats[j].RecordCount, Length(Fragments));
214+
Inc(FRelationStats[j].RecordCount, Length(Fragments)); // Ïðèáàâëÿåì êîëè÷åñòâî ôðàãìåíòîâ
210215
Break;
211216
end;
212217
end;
@@ -215,6 +220,7 @@ procedure TDatabaseStats.CalculateRelationStats;
215220
end;
216221
end;
217222

223+
218224
procedure TDatabaseStats.CalculateStats;
219225
begin
220226
CalculatePageStats;

0 commit comments

Comments
 (0)