Skip to content

Commit 4b2d931

Browse files
author
Alex Gaetano Padula
committed
Analyze method and page count of btree to determine potential io of full scan
1 parent 0bd47d3 commit 4b2d931

File tree

1 file changed

+97
-3
lines changed

1 file changed

+97
-3
lines changed

pager.go

+97-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import (
2121
"fmt"
2222
"io"
2323
"os"
24+
"slices"
2425
"strconv"
2526
"strings"
2627
"sync"
28+
"time"
2729
)
2830

2931
const PAGE_SIZE = 1024 // Page size
@@ -37,6 +39,10 @@ type Pager struct {
3739
deletedPagesFile *os.File // file to store deleted pages
3840
pageLocks map[int64]*sync.RWMutex // locks for pages
3941
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
4046
}
4147

4248
// OpenPager opens a file for page management
@@ -70,7 +76,7 @@ func OpenPager(filename string, flag int, perm os.FileMode) (*Pager, error) {
7076
pgLocks[i] = &sync.RWMutex{}
7177
}
7278

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
7480
}
7581

7682
// writeDelPages writes the deleted pages that are in-memory to the deleted pages file
@@ -150,6 +156,10 @@ func splitDataIntoChunks(data []byte) [][]byte {
150156

151157
// WriteTo writes data to a specific page
152158
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+
153163
p.DeletePage(pageID)
154164
// remove from deleted pages
155165
p.deletedPagesLock.Lock()
@@ -161,6 +171,7 @@ func (p *Pager) WriteTo(pageID int64, data []byte) error {
161171
}
162172

163173
}
174+
164175
// 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
165176

166177
// check if data is larger than the page size
@@ -317,6 +328,19 @@ func (p *Pager) Close() error {
317328
// GetPage gets a page and returns the data
318329
// Will gather all the pages that are linked together
319330
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+
320344
result := make([]byte, 0)
321345

322346
// get the page
@@ -389,6 +413,13 @@ func (p *Pager) GetPage(pageID int64) ([]byte, error) {
389413
return result, nil
390414
}
391415

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+
392423
// DeletePage deletes a page
393424
func (p *Pager) DeletePage(pageID int64) error {
394425
p.deletedPagesLock.Lock()
@@ -406,7 +437,70 @@ func (p *Pager) DeletePage(pageID int64) error {
406437
return nil
407438
}
408439

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
410449
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+
412506
}

0 commit comments

Comments
 (0)