Skip to content

Commit

Permalink
Refactor code to bypass mysql db with a simple append only file flushing
Browse files Browse the repository at this point in the history
  • Loading branch information
Russell-Tran committed Jun 4, 2024
1 parent aac51de commit 7347b42
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 5 deletions.
61 changes: 56 additions & 5 deletions go/cmd/gcsobjtable/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"bufio"
"context"
"os"
"time"

// "errors"
Expand Down Expand Up @@ -115,22 +117,71 @@ func NewGCSObjServer(flushIntervalSec int) *GCSObjServer {
func (s *GCSObjServer) flushToDisk() error {
s.mu.Lock()
defer s.mu.Unlock()
garbage_collect := false // TODO: REMOVE HARDCODED
flush_to_AOF_instead := true // TODO: REMOVE HARDCODED
aof_filename := "./aof.txt" // TODO: REMOVE HARDCODED

err := insertOrUpdateObjectLocations(s.database, s.objectLocations)
if err != nil {
return err
if flush_to_AOF_instead {
WriteObjectLocationsToAOF(aof_filename, s.objectLocations)
} else {
// Flush to SQLite3 Disk Database
err := insertOrUpdateObjectLocations(s.database, s.objectLocations)
if err != nil {
return err
}
}

// Completely delete the current map in memory and start blank
s.objectLocations = make(map[uint64][]uint64) // orphaning the old map will get it garbage collected
// Manually trigger garbage collection
garbage_collect := true // TODO: REMOVE HARDCODED
// Manually trigger garbage collection if desired
if garbage_collect {
runtime.GC()
fmt.Println("Garbage collection triggered")
}
return nil
}

// WriteObjectLocationsToAOF appends the contents of the objectLocations map to a file
func WriteObjectLocationsToAOF(filename string, objectLocations map[uint64][]uint64) error {
// Open file in append mode, create if it doesn't exist
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("error opening file: %w", err)
}
defer file.Close()

// Create a buffered writer
writer := bufio.NewWriter(file)

// Iterate over the map and write to file
for key, values := range objectLocations {
// Convert key to string
keyStr := strconv.FormatUint(key, 10)

// Convert values slice to a comma-separated string
var valuesStr string
for i, val := range values {
if i > 0 {
valuesStr += ","
}
valuesStr += strconv.FormatUint(val, 10)
}

// Write key and values to file
_, err := writer.WriteString(fmt.Sprintf("%s: [%s]\n", keyStr, valuesStr))
if err != nil {
return fmt.Errorf("error writing to file: %w", err)
}
}

// Flush the buffered writer
if err := writer.Flush(); err != nil {
return fmt.Errorf("error flushing buffer: %w", err)
}

return nil
}

/*
Returns a nodeId that has object uid. If it doesn't exist anywhere,
then the second return value will be false.
Expand Down
45 changes: 45 additions & 0 deletions go/cmd/gcsobjtable/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import (
"database/sql"
"errors"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net"
"os"
"strconv"
"strings"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -42,6 +45,48 @@ func bufDialer(context.Context, string) (net.Conn, error) {
return lis.Dial()
}

func TestWriteObjectLocationsToAOF(t *testing.T) {
// Create a temporary file
tmpfile, err := ioutil.TempFile("", "test_object_locations_*.txt")
if err != nil {
t.Fatalf("Unable to create temp file: %v", err)
}
defer os.Remove(tmpfile.Name()) // Clean up the temp file after the test

// Close the file so WriteObjectLocations can open it
tmpfile.Close()

// Sample map for testing
objectLocations := map[uint64][]uint64{
1: {10, 20, 30},
2: {40, 50, 60},
3: {70, 80, 90},
}

// Call the function to write the map to the file
err = WriteObjectLocationsToAOF(tmpfile.Name(), objectLocations)
if err != nil {
t.Fatalf("WriteObjectLocations failed: %v", err)
}

// Read the file content
content, err := ioutil.ReadFile(tmpfile.Name())
if err != nil {
t.Fatalf("Unable to read temp file: %v", err)
}

// Expected content
expectedContent := `1: [10,20,30]
2: [40,50,60]
3: [70,80,90]
`

// Check if the content matches the expected content
if strings.TrimSpace(string(content)) != strings.TrimSpace(expectedContent) {
t.Errorf("Content mismatch\nExpected:\n%s\nGot:\n%s", expectedContent, string(content))
}
}

func TestGetNodeId(t *testing.T) {
// Seed the random number generator for reproducibility in tests
rand.Seed(1)
Expand Down

0 comments on commit 7347b42

Please sign in to comment.