@@ -21,9 +21,11 @@ import (
21
21
"fmt"
22
22
"io"
23
23
"os"
24
+ "slices"
24
25
"strconv"
25
26
"strings"
26
27
"sync"
28
+ "time"
27
29
)
28
30
29
31
const PAGE_SIZE = 1024 // Page size
@@ -37,6 +39,10 @@ type Pager struct {
37
39
deletedPagesFile * os.File // file to store deleted pages
38
40
pageLocks map [int64 ]* sync.RWMutex // locks for pages
39
41
pageLocksLock * sync.RWMutex // lock for pagesLocks
42
+ StatLock * sync.RWMutex // lock for stats
43
+ cachedCount int64 // cached count of pages
44
+ lastCacheTime time.Time // last time the cache was updated
45
+ interval time.Duration // interval to update the cache
40
46
}
41
47
42
48
// OpenPager opens a file for page management
@@ -70,7 +76,7 @@ func OpenPager(filename string, flag int, perm os.FileMode) (*Pager, error) {
70
76
pgLocks [i ] = & sync.RWMutex {}
71
77
}
72
78
73
- return & Pager {file : file , deletedPages : deletedPages , deletedPagesFile : deletedPagesFile , deletedPagesLock : & sync.Mutex {}, pageLocks : pgLocks , pageLocksLock : & sync.RWMutex {}}, nil
79
+ return & Pager {file : file , deletedPages : deletedPages , deletedPagesFile : deletedPagesFile , deletedPagesLock : & sync.Mutex {}, pageLocks : pgLocks , pageLocksLock : & sync.RWMutex {}, StatLock : & sync. RWMutex {}, interval : time . Minute * 10 , lastCacheTime : time . Now (). Add ( time . Minute * 10 ) }, nil
74
80
}
75
81
76
82
// writeDelPages writes the deleted pages that are in-memory to the deleted pages file
@@ -150,6 +156,10 @@ func splitDataIntoChunks(data []byte) [][]byte {
150
156
151
157
// WriteTo writes data to a specific page
152
158
func (p * Pager ) WriteTo (pageID int64 , data []byte ) error {
159
+ // lock the page
160
+ p .getPageLock (pageID ).Lock ()
161
+ defer p .getPageLock (pageID ).Unlock ()
162
+
153
163
p .DeletePage (pageID )
154
164
// remove from deleted pages
155
165
p .deletedPagesLock .Lock ()
@@ -161,6 +171,7 @@ func (p *Pager) WriteTo(pageID int64, data []byte) error {
161
171
}
162
172
163
173
}
174
+
164
175
// the reason we are doing this is because we are going to write to the page thus having any overflowed pages which are linked to the page may not be needed
165
176
166
177
// check if data is larger than the page size
@@ -317,6 +328,19 @@ func (p *Pager) Close() error {
317
328
// GetPage gets a page and returns the data
318
329
// Will gather all the pages that are linked together
319
330
func (p * Pager ) GetPage (pageID int64 ) ([]byte , error ) {
331
+
332
+ // lock the page
333
+ p .getPageLock (pageID ).Lock ()
334
+ defer p .getPageLock (pageID ).Unlock ()
335
+
336
+ p .deletedPagesLock .Lock ()
337
+ // Check if in deleted pages, if so return nil
338
+ if slices .Contains (p .deletedPages , pageID ) {
339
+ p .deletedPagesLock .Unlock ()
340
+ return nil , nil
341
+ }
342
+ p .deletedPagesLock .Unlock ()
343
+
320
344
result := make ([]byte , 0 )
321
345
322
346
// get the page
@@ -389,6 +413,13 @@ func (p *Pager) GetPage(pageID int64) ([]byte, error) {
389
413
return result , nil
390
414
}
391
415
416
+ // GetDeletedPages returns the list of deleted pages
417
+ func (p * Pager ) GetDeletedPages () []int64 {
418
+ p .deletedPagesLock .Lock ()
419
+ defer p .deletedPagesLock .Unlock ()
420
+ return p .deletedPages
421
+ }
422
+
392
423
// DeletePage deletes a page
393
424
func (p * Pager ) DeletePage (pageID int64 ) error {
394
425
p .deletedPagesLock .Lock ()
@@ -406,7 +437,70 @@ func (p *Pager) DeletePage(pageID int64) error {
406
437
return nil
407
438
}
408
439
409
- func (p * Pager ) Count () int64 {
440
+ // Analyze forces the pager to analyze the file
441
+ func (p * Pager ) Analyze () error {
442
+ p .StatLock .Lock ()
443
+ defer p .StatLock .Unlock ()
444
+
445
+ // Initialize a counter for the pages
446
+ var pageCount int64 = 0
447
+
448
+ // Get the size of the file
410
449
stat , _ := p .file .Stat ()
411
- return stat .Size () / (PAGE_SIZE + HEADER_SIZE )
450
+ fileSize := stat .Size ()
451
+
452
+ // Initialize a counter for the bytes read
453
+ var bytesRead int64 = 0
454
+
455
+ // Read through the file in chunks of PAGE_SIZE + HEADER_SIZE bytes
456
+ for bytesRead < fileSize {
457
+ bytesRead += PAGE_SIZE + HEADER_SIZE
458
+ pageCount ++
459
+ }
460
+
461
+ p .cachedCount = pageCount
462
+
463
+ return nil
464
+ }
465
+
466
+ // Count returns the number of pages
467
+ func (p * Pager ) Count () int64 {
468
+
469
+ if p .cachedCount == 0 {
470
+ p .Analyze ()
471
+
472
+ }
473
+
474
+ if time .Since (p .lastCacheTime ) > p .interval {
475
+ time .Now ()
476
+
477
+ p .StatLock .Lock ()
478
+ defer p .StatLock .Unlock ()
479
+
480
+ // Initialize a counter for the pages
481
+ var pageCount int64 = 0
482
+
483
+ // Get the size of the file
484
+ stat , _ := p .file .Stat ()
485
+ fileSize := stat .Size ()
486
+
487
+ // Initialize a counter for the bytes read
488
+ var bytesRead int64 = 0
489
+
490
+ // Read through the file in chunks of PAGE_SIZE + HEADER_SIZE bytes
491
+ for bytesRead < fileSize {
492
+ bytesRead += PAGE_SIZE + HEADER_SIZE
493
+ pageCount ++
494
+ }
495
+
496
+ p .cachedCount = pageCount
497
+
498
+ // Subtract the number of deleted pages
499
+ //pageCount -= int64(len(p.GetDeletedPages()))
500
+
501
+ return pageCount
502
+ } else {
503
+ return p .cachedCount
504
+ }
505
+
412
506
}
0 commit comments