Skip to content
8 changes: 7 additions & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ linters:
- makezero
- unparam
- revive
- goimports
- goconst
- unparam
- staticcheck
disable:
- wsl
# Enable presets.
Expand Down Expand Up @@ -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
forbidden-names: ^[_a-z]+(_[a-z0-9]+)*$ # Regex for snake_case
goconst:
min-occurrences: 3
40 changes: 26 additions & 14 deletions kfile/fileMgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
}

Expand Down
50 changes: 21 additions & 29 deletions log/log_dir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package log

import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -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())
}
}
}

Expand Down Expand Up @@ -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()
}
Expand Down
36 changes: 0 additions & 36 deletions log/logmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 13 additions & 46 deletions log/temp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"ultraSQL/buffer"
"ultraSQL/kfile"
"ultraSQL/utils"
"unsafe"
)

func TestLogMgrAppend(t *testing.T) {
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
}

Expand All @@ -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))
}

Expand All @@ -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() {
Expand All @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
Expand Down
4 changes: 1 addition & 3 deletions utils/Iterator.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package utils

import "ultraSQL/kfile"

type Iterator[T any] interface {
HasNext() bool
Next() (*kfile.Cell, error)
Next() ([]byte, error)
}
14 changes: 12 additions & 2 deletions utils/LogIterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading