temp for tree extraction

This commit is contained in:
2025-10-15 19:13:35 -04:00
commit 89fb7a30f7
50 changed files with 8769 additions and 0 deletions

View File

@ -0,0 +1,201 @@
package storage
import (
"encoding/binary"
"fmt"
"io"
"os"
"git.dws.rip/DWS/onyx/internal/models"
)
// OplogReader handles reading entries from the oplog file
type OplogReader struct {
path string
}
// NewOplogReader creates a new oplog reader for the given file path
func NewOplogReader(path string) *OplogReader {
return &OplogReader{
path: path,
}
}
// ReadLastEntry reads the last (most recent) entry in the oplog
func (r *OplogReader) ReadLastEntry() (*models.OplogEntry, error) {
file, err := os.Open(r.path)
if err != nil {
return nil, fmt.Errorf("failed to open oplog file: %w", err)
}
defer file.Close()
var lastEntry *models.OplogEntry
// Read through all entries to find the last one
for {
// Read entry length (4 bytes)
var entryLen uint32
err := binary.Read(file, binary.LittleEndian, &entryLen)
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("failed to read entry length: %w", err)
}
// Read the entry data
entryData := make([]byte, entryLen)
n, err := file.Read(entryData)
if err != nil {
return nil, fmt.Errorf("failed to read entry data: %w", err)
}
if n != int(entryLen) {
return nil, fmt.Errorf("incomplete entry data read: expected %d bytes, got %d", entryLen, n)
}
// Deserialize the entry
entry, err := models.DeserializeOplogEntry(entryData)
if err != nil {
return nil, fmt.Errorf("failed to deserialize entry: %w", err)
}
lastEntry = entry
}
if lastEntry == nil {
return nil, fmt.Errorf("oplog is empty")
}
return lastEntry, nil
}
// ReadEntry reads a specific entry by ID
func (r *OplogReader) ReadEntry(id uint64) (*models.OplogEntry, error) {
file, err := os.Open(r.path)
if err != nil {
return nil, fmt.Errorf("failed to open oplog file: %w", err)
}
defer file.Close()
// Read through all entries to find the one with matching ID
for {
// Read entry length (4 bytes)
var entryLen uint32
err := binary.Read(file, binary.LittleEndian, &entryLen)
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("failed to read entry length: %w", err)
}
// Read the entry data
entryData := make([]byte, entryLen)
n, err := file.Read(entryData)
if err != nil {
return nil, fmt.Errorf("failed to read entry data: %w", err)
}
if n != int(entryLen) {
return nil, fmt.Errorf("incomplete entry data read: expected %d bytes, got %d", entryLen, n)
}
// Deserialize the entry
entry, err := models.DeserializeOplogEntry(entryData)
if err != nil {
return nil, fmt.Errorf("failed to deserialize entry: %w", err)
}
if entry.ID == id {
return entry, nil
}
}
return nil, fmt.Errorf("entry with ID %d not found", id)
}
// GetUndoStack returns a stack of entries that can be undone (in reverse order)
func (r *OplogReader) GetUndoStack() ([]*models.OplogEntry, error) {
entries, err := r.ReadAllEntries()
if err != nil {
return nil, err
}
// Filter out entries that have already been undone
// For now, we return all entries in reverse order
// In the future, we might track undone entries separately
var undoStack []*models.OplogEntry
for i := len(entries) - 1; i >= 0; i-- {
undoStack = append(undoStack, entries[i])
}
return undoStack, nil
}
// ReadAllEntries reads all entries from the oplog in order
func (r *OplogReader) ReadAllEntries() ([]*models.OplogEntry, error) {
file, err := os.Open(r.path)
if err != nil {
return nil, fmt.Errorf("failed to open oplog file: %w", err)
}
defer file.Close()
var entries []*models.OplogEntry
// Read through all entries
for {
// Read entry length (4 bytes)
var entryLen uint32
err := binary.Read(file, binary.LittleEndian, &entryLen)
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("failed to read entry length: %w", err)
}
// Read the entry data
entryData := make([]byte, entryLen)
n, err := file.Read(entryData)
if err != nil {
return nil, fmt.Errorf("failed to read entry data: %w", err)
}
if n != int(entryLen) {
return nil, fmt.Errorf("incomplete entry data read: expected %d bytes, got %d", entryLen, n)
}
// Deserialize the entry
entry, err := models.DeserializeOplogEntry(entryData)
if err != nil {
return nil, fmt.Errorf("failed to deserialize entry: %w", err)
}
entries = append(entries, entry)
}
return entries, nil
}
// Count returns the total number of entries in the oplog
func (r *OplogReader) Count() (int, error) {
entries, err := r.ReadAllEntries()
if err != nil {
return 0, err
}
return len(entries), nil
}
// IsEmpty checks if the oplog is empty
func (r *OplogReader) IsEmpty() (bool, error) {
file, err := os.Open(r.path)
if err != nil {
return false, fmt.Errorf("failed to open oplog file: %w", err)
}
defer file.Close()
stat, err := file.Stat()
if err != nil {
return false, fmt.Errorf("failed to stat file: %w", err)
}
return stat.Size() == 0, nil
}