From ae364743516de1b5095a2da5ccfd91e1cf55c2ac Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:16:39 +0000 Subject: [PATCH 1/8] updated linter configurations --- .golangci.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 55c4c9f..532888c 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -22,6 +22,10 @@ linters: - makezero - unparam - revive + - goimports + - goconst + - unparam + - staticcheck disable: - wsl # Enable presets. @@ -50,4 +54,6 @@ linters: - name: var-naming arguments: allowed-names: ^[a-z]+([A-Z][a-z0-9]+)*$ # Regex for camelCase - forbidden-names: ^[_a-z]+(_[a-z0-9]+)*$ # Regex for snake_case \ No newline at end of file + forbidden-names: ^[_a-z]+(_[a-z0-9]+)*$ # Regex for snake_case + goconst: + min-occurrences: 3 \ No newline at end of file From a662d6c0885827fbd7448756e1905f1c9bd6bdce Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:17:10 +0000 Subject: [PATCH 2/8] refactored to reduce cyclomatic complexity --- kfile/fileMgr.go | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/kfile/fileMgr.go b/kfile/fileMgr.go index 5411a57..a3727dc 100644 --- a/kfile/fileMgr.go +++ b/kfile/fileMgr.go @@ -91,25 +91,42 @@ func NewMetaData(created_at time.Time) FileMetadata { } } func (fm *FileMgr) PreallocateFile(blk *BlockId, size int64) error { + if err := fm.validatePreallocationParams(blk, size); err != nil { + return err + } + + filename := blk.GetFileName() + if err := fm.validatePermissions(); err != nil { + return err + } + + return fm.performPreallocation(filename, size) +} + +func (fm *FileMgr) validatePreallocationParams(blk *BlockId, size int64) error { if size%int64(fm.blocksize) != 0 { return fmt.Errorf("size must be multiple of blocksize %d", fm.blocksize) } - filename := blk.GetFileName() - if filename == "" { + if blk.GetFileName() == "" { return fmt.Errorf("invalid filename") } + return nil +} +func (fm *FileMgr) validatePermissions() error { dirStat, err := os.Stat(fm.dbDirectory) if err != nil { return fmt.Errorf("failed to stat directory: %v", err) } - dirMode := dirStat.Mode() - isDirWritable := dirMode&0200 != 0 - if !isDirWritable { + + if dirStat.Mode()&0200 == 0 { return fmt.Errorf("directory is not writable") } + return nil +} +func (fm *FileMgr) performPreallocation(filename string, size int64) error { f, err := fm.getFile(filename) if err != nil { return fmt.Errorf("failed to get file for preallocation: %v", err) @@ -120,24 +137,19 @@ func (fm *FileMgr) PreallocateFile(blk *BlockId, size int64) error { return fmt.Errorf("failed to stat file: %v", err) } - mode := stat.Mode() - isWritable := mode&0200 != 0 - if !isWritable { + if stat.Mode()&0200 == 0 { return fmt.Errorf("file is not writable") } - currentSize := stat.Size() - if currentSize >= size { + if stat.Size() >= size { return nil } - err = f.Truncate(size) - if err != nil { + if err := f.Truncate(size); err != nil { return fmt.Errorf("failed to preallocate sparse file: %v", err) } - err = f.Sync() - if err != nil { + if err := f.Sync(); err != nil { return fmt.Errorf("failed to sync preallocated file: %v", err) } From b66f9ef456409786dfafd7e9b2cd7a4950504b9b Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:17:17 +0000 Subject: [PATCH 3/8] refactored to reduce cyclomatic complexity --- kfile/fileMgr_test.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 kfile/fileMgr_test.go diff --git a/kfile/fileMgr_test.go b/kfile/fileMgr_test.go deleted file mode 100644 index e69de29..0000000 From c2f72e17ac3e20a15c8c33e92111d28b75018671 Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:17:50 +0000 Subject: [PATCH 4/8] updated interface to use bytes --- utils/Iterator.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/utils/Iterator.go b/utils/Iterator.go index 8f55836..2485d26 100644 --- a/utils/Iterator.go +++ b/utils/Iterator.go @@ -1,8 +1,6 @@ package utils -import "ultraSQL/kfile" - type Iterator[T any] interface { HasNext() bool - Next() (*kfile.Cell, error) + Next() ([]byte, error) } From a2688affae3891a77b9b72fa2ac6401a43c923ec Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:18:01 +0000 Subject: [PATCH 5/8] updated interface to use bytes --- log/log_dir_test.go | 50 +++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/log/log_dir_test.go b/log/log_dir_test.go index 8ef05f3..731c2d9 100644 --- a/log/log_dir_test.go +++ b/log/log_dir_test.go @@ -2,7 +2,7 @@ package log import ( "bytes" - "encoding/binary" + "errors" "fmt" "os" "path/filepath" @@ -165,15 +165,27 @@ func TestAppendBoundary(t *testing.T) { // Append records to fill the block record := make([]byte, 50) // Record size - for i := 0; i < blockSize/len(record)-2; i++ { - logMgr.Append(record) + for i := 0; i < blockSize/len(record)-3; i++ { + lsn, cellKey, err := logMgr.Append(record) + if err != nil { + t.Errorf("Expected cell key and lsn got %s", err) + } + if lsn < 0 { + t.Errorf("Invalid lsn") + } + if cellKey == nil { + t.Errorf("Invalid CellKey") + } } - initialBlock := logMgr.currentBlock - logMgr.Append(record) + _, _, err = logMgr.Append(record) - if logMgr.currentBlock == initialBlock { - t.Errorf("Expected new block after boundary overflow, but block did not change") + var customErr *Error + if errors.As(err, &customErr) { + expected := "log operation Append failed: failed to insert cell page full" + if customErr.Error() != expected { + t.Errorf("Expected '%s' but got: '%s'", expected, customErr.Error()) + } } } @@ -228,28 +240,8 @@ func printLogRecords(t *testing.T, lm *LogMgr, msg string) { if err != nil { panic(err) } - //page := kfile.NewPageFromBytes(rec) - //s, err := page.GetStringWithOffset(0) - s, err := rec.GetValue() - var results string - if err != nil { - panic(err) - } - switch v := s.(type) { - case string: - fmt.Println("Value is a string:", v) - case []byte: - length := binary.BigEndian.Uint32(v[:4]) // Get the length from first 4 bytes - content := v[4 : 4+length] // Extract just the content bytes - results = string(content) - default: - fmt.Println("Unhandled type") - } - - //npos := utils.MaxLength(len(s)) - //val, _ := page.GetInt(npos) - val := string(rec.GetKey()) - t.Logf("[%s, %s]", results, val) + s := string(rec) + t.Logf("[%s]", s) } t.Log() } From 06939efb23b21a1c76ba977947abc167a6d551ff Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:18:08 +0000 Subject: [PATCH 6/8] updated interface to use bytes --- utils/LogIterator.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/utils/LogIterator.go b/utils/LogIterator.go index fa09e5e..a4f5288 100644 --- a/utils/LogIterator.go +++ b/utils/LogIterator.go @@ -32,17 +32,27 @@ func (it *LogIterator) HasNext() bool { return it.currentPos >= 0 || it.blk.Number() > 0 } -func (it *LogIterator) Next() (*kfile.Cell, error) { +func (it *LogIterator) Next() ([]byte, error) { if it.currentPos < 0 { it.blk = kfile.NewBlockId(it.blk.GetFileName(), it.blk.Number()-1) if err := it.moveToBlock(it.blk); err != nil { return nil, err } } - rec, err := it.buff.GetContents().GetCellBySlot(it.currentPos) + cell, err := it.buff.GetContents().GetCellBySlot(it.currentPos) if err != nil { return nil, fmt.Errorf("error while getting bytes: %v", err) } + cellVal, err := cell.GetValue() + if err != nil { + return nil, fmt.Errorf("error while getting value: %v", err) + } + rec, ok := cellVal.([]byte) + + if !ok { + panic("value is not byte") + } + //recLen := string(rec) //npos := MaxLength(len(recLen)) //it.currentPos += int(unsafe.Sizeof(0)) + npos From 8335336667a05e3dda61681b1f7f81d7850131c5 Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:18:21 +0000 Subject: [PATCH 7/8] updated interface to use bytes --- log/logmgr.go | 36 ------------------------------------ main.go | 4 ++-- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/log/logmgr.go b/log/logmgr.go index 15a3630..218027f 100644 --- a/log/logmgr.go +++ b/log/logmgr.go @@ -143,42 +143,6 @@ func (lm *LogMgr) Append(logrec []byte) (int, []byte, error) { } lm.logBuffer.SetContents(logpage) - //logPage := lm.bm.Get(lm.currentBlock).GetContents() - - //boundary := logPage.GetFreeSpace() - // - //recsize := len(logrec) - //intBytes := int(unsafe.Sizeof(0)) - //bytesNeeded := recsize + intBytes - - //if (boundary - bytesNeeded) < intBytes { - // if err := lm.Flush(); err != nil { - // return 0, &Error{Op: "append", Err: fmt.Errorf("failed to flush: %v", err)} - // } - // - // if lm.currentBlock, _ = lm.appendNewBlock(); lm.currentBlock == nil { - // return 0, &Error{Op: "append", Err: fmt.Errorf("failed to append new block")} - // } - // //if err := lm.logBuffer.GetContents().SetInt(0, lm.fm.BlockSize()); err != nil { - // // return 0, &Error{Op: "Pin", Err: fmt.Errorf("failed to append initial block")} - // //} - // - // if err := lm.logBuffer.Flush(); err != nil { - // return 0, &Error{Op: "Pin", Err: fmt.Errorf("failed to append initial block")} - // } - // - // boundary = logPage.GetFreeSpace() - //} - - //recpos := boundary - bytesNeeded - //if err := logPage.SetBytes(recpos, logrec); err != nil { - // return 0, &Error{Op: "append", Err: fmt.Errorf("failed to set bytes: %v", err)} - //} - // - //if err := logPage.SetInt(0, recpos); err != nil { - // return 0, &Error{Op: "append", Err: fmt.Errorf("failed to update boundary: %v", err)} - //} - lm.latestLSN++ lm.logBuffer.MarkModified(-1, lm.latestLSN) return lm.latestLSN, cellKey, nil diff --git a/main.go b/main.go index 89a26dc..0695999 100644 --- a/main.go +++ b/main.go @@ -28,7 +28,7 @@ func main() { blk, err := fm.Append(Filename) checkError(err, "Failed to append block") fmt.Printf("Appended Block: %v\n", blk) - newPage := kfile.NewPage(blockSize) + newPage := kfile.NewSlottedPage(blockSize) err = newPage.SetInt(0, 42) checkError(err, "Failed to set int") @@ -46,7 +46,7 @@ func main() { err = fm.Write(blk, newPage) checkError(err, "Failed to write to block") - readPage := kfile.NewPage(blockSize) + readPage := kfile.NewSlottedPage(blockSize) err = fm.Read(blk, readPage) checkError(err, "Failed to read from block") From 9d7957bfa0edea22c0485f0100cbb7af2ad69942 Mon Sep 17 00:00:00 2001 From: anthony4m Date: Thu, 16 Jan 2025 12:18:31 +0000 Subject: [PATCH 8/8] updated interface to use bytes --- log/temp_test.go | 59 +++++++++++------------------------------------- 1 file changed, 13 insertions(+), 46 deletions(-) diff --git a/log/temp_test.go b/log/temp_test.go index 7336a45..9dbf68e 100644 --- a/log/temp_test.go +++ b/log/temp_test.go @@ -9,7 +9,6 @@ import ( "ultraSQL/buffer" "ultraSQL/kfile" "ultraSQL/utils" - "unsafe" ) func TestLogMgrAppend(t *testing.T) { @@ -49,11 +48,11 @@ func verifyMultipleRecordsInSingleBlock(t *testing.T, lm *LogMgr, blockSize int) t.Log("Testing appending multiple records within a single block...") // Append multiple small records - record1 := record("record2", 200) - record2 := record("record1", 100) + record1 := "record2" + record2 := "record1" - lsn1, _, err := lm.Append(record1) - lsn2, _, err := lm.Append(record2) + lsn1, _, err := lm.Append([]byte(record1)) + lsn2, _, err := lm.Append([]byte(record2)) if err != nil { t.Errorf("Error occured %s", err) } @@ -69,7 +68,7 @@ func verifyMultipleRecordsInSingleBlock(t *testing.T, lm *LogMgr, blockSize int) t.Errorf("Error occured %s", err) } records := readAllRecords(t, iter) - expected := []string{"record1, 100", "record2, 200"} + expected := []string{"record1", "record2"} compareRecords(t, records, expected) } @@ -80,8 +79,12 @@ func verifyRecordsAcrossBlocks(t *testing.T, lm *LogMgr, blockSize int) { // Each record is 1/5 of the block records := []string{} for i := 1; i <= 10; i++ { - record := record(fmt.Sprintf("record%d", i), i*10) - lm.Append(record) + str := string(rune(i)) + record := []byte(str) + _, _, err := lm.Append(record) + if err != nil { + return + } records = append(records, fmt.Sprintf("record%d, %d", i, i*10)) } @@ -94,23 +97,6 @@ func verifyRecordsAcrossBlocks(t *testing.T, lm *LogMgr, blockSize int) { compareRecords(t, readRecords, records) } -func record(s string, n int) []byte { - strOffset := utils.MaxLength(len(s)) - record := make([]byte, strOffset+int(unsafe.Sizeof(0))) // String + Integer - page := kfile.NewPageFromBytes(record) - - if err := page.SetString(0, s); err != nil { - panic(fmt.Sprintf("Failed to set string: %v", err)) - } - if err := page.SetInt(strOffset, n); err != nil { - panic(fmt.Sprintf("Failed to set int: %v", err)) - } - - // Log serialized record details - //fmt.Printf("Serialized record [%s, %d]: strOffset=%d, recordLen=%d\n", s, n, strOffset, len(record)) - return record -} - func readAllRecords(t *testing.T, iter utils.Iterator[[]byte]) []string { var records []string for iter.HasNext() { @@ -119,29 +105,10 @@ func readAllRecords(t *testing.T, iter utils.Iterator[[]byte]) []string { t.Fatalf("Error reading record: %v", err) } - //page := kfile.NewPageFromBytes(rec) - //s, err := page.GetString(0) - s, err := rec.GetValue() - if err != nil { - panic(err) - } - s, ok := s.(string) - if ok { - fmt.Println("Converted to string:", s) - } else { - fmt.Println("Value is not a string") - } - - //npos := utils.MaxLength(len(s)) // Ensure alignment - //n, err := page.GetInt(npos) - n := rec.GetKey() - if err != nil { - t.Fatalf("Error getting int: %v", err) - } + s := string(rec) - record := fmt.Sprintf("%s, %d", s, n) + record := fmt.Sprintf("%s", s) records = append(records, record) - //t.Logf("Deserialized record: [%s, %d] (npos=%d, recLen=%d)", s, n, npos, len(rec)) } return records }