feat: Improve OurDBFS ID generation and data persistence

- Use a counter for consistent ID generation in OurDBFS: This
  eliminates reliance on timestamps, preventing ID collisions and
  improving data integrity.
- Refactor save methods to directly use the VFS's save_entry
  function: This simplifies the code and reduces redundancy across
  different file system entity types (Directory, File, Symlink).
- Update `save_entry` in OurDBFS to use IDs for database updates:
  This ensures data is correctly updated in the database based on the
  unique ID of each entry.  This also fixes potential issues with
  overwriting data.
This commit is contained in:
Mahmoud Emad
2025-02-19 01:12:19 +02:00
parent 4691046d5f
commit 383fc9fade
7 changed files with 61 additions and 34 deletions

View File

@@ -15,7 +15,7 @@ pub mut:
} }
pub fn (mut self Directory) save() ! { pub fn (mut self Directory) save() ! {
self.metadata.id = self.myvfs.save_entry(self)! self.myvfs.save_entry(self)!
} }
// write creates a new file or writes to an existing file // write creates a new file or writes to an existing file
@@ -45,7 +45,7 @@ pub fn (mut dir Directory) write(name string, content string) !&File {
current_time := time.now().unix() current_time := time.now().unix()
file = &File{ file = &File{
metadata: Metadata{ metadata: Metadata{
// id: u32(time.now().unix()) id: dir.myvfs.get_next_id()
name: name name: name
file_type: .file file_type: .file
size: u64(content.len) size: u64(content.len)
@@ -62,11 +62,11 @@ pub fn (mut dir Directory) write(name string, content string) !&File {
} }
// Save new file to DB // Save new file to DB
file.metadata.id = dir.myvfs.save_entry(file)! dir.myvfs.save_entry(file)!
// Update children list // Update children list
dir.children << file.metadata.id dir.children << file.metadata.id
dir.metadata.id = dir.myvfs.save_entry(dir)! dir.myvfs.save_entry(dir)!
} else { } else {
// Update existing file // Update existing file
file.write(content)! file.write(content)!
@@ -141,7 +141,7 @@ pub fn (mut dir Directory) mkdir(name string) !&Directory {
current_time := time.now().unix() current_time := time.now().unix()
mut new_dir := Directory{ mut new_dir := Directory{
metadata: Metadata{ metadata: Metadata{
// id: u32(time.now().unix()) // Use timestamp as ID id: dir.myvfs.get_next_id()
name: name name: name
file_type: .directory file_type: .directory
created_at: current_time created_at: current_time
@@ -157,11 +157,11 @@ pub fn (mut dir Directory) mkdir(name string) !&Directory {
} }
// Save new directory to DB // Save new directory to DB
new_dir.metadata.id = dir.myvfs.save_entry(new_dir)! dir.myvfs.save_entry(new_dir)!
// Update children list // Update children list
dir.children << new_dir.metadata.id dir.children << new_dir.metadata.id
dir.metadata.id = dir.myvfs.save_entry(dir)! dir.myvfs.save_entry(dir)!
return &new_dir return &new_dir
} }
@@ -180,6 +180,7 @@ pub fn (mut dir Directory) touch(name string) !&File {
current_time := time.now().unix() current_time := time.now().unix()
mut new_file := File{ mut new_file := File{
metadata: Metadata{ metadata: Metadata{
id: dir.myvfs.get_next_id()
name: name name: name
file_type: .file file_type: .file
size: 0 size: 0
@@ -196,11 +197,11 @@ pub fn (mut dir Directory) touch(name string) !&File {
} }
// Save new file to DB // Save new file to DB
new_file.metadata.id = dir.myvfs.save_entry(new_file)! dir.myvfs.save_entry(new_file)!
// Update children list // Update children list
dir.children << new_file.metadata.id dir.children << new_file.metadata.id
dir.metadata.id = dir.myvfs.save_entry(dir)! dir.myvfs.save_entry(dir)!
return &new_file return &new_file
} }
@@ -236,7 +237,7 @@ pub fn (mut dir Directory) rm(name string) ! {
// Update children list // Update children list
dir.children.delete(found_idx) dir.children.delete(found_idx)
dir.metadata.id = dir.myvfs.save_entry(dir)! dir.myvfs.save_entry(dir)!
} }
// get_children returns all immediate children as FSEntry objects // get_children returns all immediate children as FSEntry objects
@@ -266,9 +267,7 @@ pub fn (mut dir Directory) delete() ! {
dir.children.clear() dir.children.clear()
// Save the updated directory // Save the updated directory
dir.metadata.id = dir.myvfs.save_entry(dir) or { dir.myvfs.save_entry(dir) or { return error('Failed to save directory: ${err}') }
return error('Failed to save directory: ${err}')
}
} }
// add_symlink adds an existing symlink to this directory // add_symlink adds an existing symlink to this directory
@@ -283,9 +282,9 @@ pub fn (mut dir Directory) add_symlink(mut symlink Symlink) ! {
} }
// Save symlink to DB // Save symlink to DB
symlink.metadata.id = dir.myvfs.save_entry(symlink)! dir.myvfs.save_entry(symlink)!
// Add to children // Add to children
dir.children << symlink.metadata.id dir.children << symlink.metadata.id
dir.metadata.id = dir.myvfs.save_entry(dir)! dir.myvfs.save_entry(dir)!
} }

View File

@@ -12,7 +12,7 @@ pub mut:
} }
pub fn (mut f File) save() ! { pub fn (mut f File) save() ! {
f.metadata.id = f.myvfs.save_entry(f)! f.myvfs.save_entry(f)!
} }
// write updates the file's content // write updates the file's content

View File

@@ -12,7 +12,7 @@ pub mut:
} }
pub fn (mut sl Symlink) save() ! { pub fn (mut sl Symlink) save() ! {
sl.metadata.id = sl.myvfs.save_entry(sl)! sl.myvfs.save_entry(sl)!
} }
// update_target changes the symlink's target path // update_target changes the symlink's target path

View File

@@ -1,6 +1,7 @@
module ourdb_fs module ourdb_fs
import freeflowuniverse.herolib.data.ourdb import freeflowuniverse.herolib.data.ourdb
import time
// OurDBFS represents the virtual filesystem // OurDBFS represents the virtual filesystem
@[heap] @[heap]
@@ -12,6 +13,13 @@ pub mut:
metadata_dir string // Directory where we store the metadata metadata_dir string // Directory where we store the metadata
db_data &ourdb.OurDB // Database instance for persistent storage db_data &ourdb.OurDB // Database instance for persistent storage
db_meta &ourdb.OurDB // Database instance for metadata storage db_meta &ourdb.OurDB // Database instance for metadata storage
last_inserted_id u32
}
// Get the next ID, it should be some kind of auto-incrementing ID
pub fn (mut fs OurDBFS) get_next_id() u32 {
fs.last_inserted_id = fs.last_inserted_id + 1
return fs.last_inserted_id
} }
// get_root returns the root directory // get_root returns the root directory
@@ -28,13 +36,22 @@ pub fn (mut fs OurDBFS) get_root() !&Directory {
// Create and save new root directory // Create and save new root directory
mut myroot := Directory{ mut myroot := Directory{
metadata: Metadata{ metadata: Metadata{
id: fs.get_next_id()
file_type: .directory file_type: .directory
name: ''
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
mode: 0o755 // default directory permissions
owner: 'user' // TODO: get from system
group: 'user' // TODO: get from system
} }
parent_id: 0 parent_id: 0
myvfs: &fs myvfs: &fs
} }
myroot.save()! myroot.save()!
fs.root_id = myroot.metadata.id fs.root_id = myroot.metadata.id
myroot.save()!
return &myroot return &myroot
} }
@@ -76,19 +93,19 @@ pub fn (mut fs OurDBFS) save_entry(entry FSEntry) !u32 {
match entry { match entry {
Directory { Directory {
encoded := entry.encode() encoded := entry.encode()
return fs.db_meta.set(data: encoded) or { return fs.db_meta.set(id: entry.metadata.id, data: encoded) or {
return error('Failed to save directory on id:${entry.metadata.id}: ${err}') return error('Failed to save directory on id:${entry.metadata.id}: ${err}')
} }
} }
File { File {
encoded := entry.encode() encoded := entry.encode()
return fs.db_meta.set(data: encoded) or { return fs.db_meta.set(id: entry.metadata.id, data: encoded) or {
return error('Failed to save file on id:${entry.metadata.id}: ${err}') return error('Failed to save file on id:${entry.metadata.id}: ${err}')
} }
} }
Symlink { Symlink {
encoded := entry.encode() encoded := entry.encode()
return fs.db_meta.set(data: encoded) or { return fs.db_meta.set(id: entry.metadata.id, data: encoded) or {
return error('Failed to save symlink on id:${entry.metadata.id}: ${err}') return error('Failed to save symlink on id:${entry.metadata.id}: ${err}')
} }
} }

View File

@@ -10,6 +10,7 @@ pub enum FileType {
// Metadata represents the common metadata for both files and directories // Metadata represents the common metadata for both files and directories
pub struct Metadata { pub struct Metadata {
pub mut: pub mut:
id u32 // name of file or directory
name string // name of file or directory name string // name of file or directory
file_type FileType file_type FileType
size u64 size u64

View File

@@ -16,7 +16,7 @@ pub fn new(data_dir string, metadata_dir string) !&OurDBVFS {
mut core := ourdb_fs.new( mut core := ourdb_fs.new(
data_dir: data_dir data_dir: data_dir
metadata_dir: metadata_dir metadata_dir: metadata_dir
incremental_mode: true incremental_mode: false
)! )!
return &OurDBVFS{ return &OurDBVFS{
@@ -59,13 +59,15 @@ pub fn (mut self OurDBVFS) file_write(path string, data []u8) ! {
} }
pub fn (mut self OurDBVFS) delete(path string) ! { pub fn (mut self OurDBVFS) delete(path string) ! {
// mut impl, rel_path := self.find_vfs(path)! println('Not implemented')
// return impl.file_read(rel_path)
} }
pub fn (mut self OurDBVFS) link_delete(path string) ! { pub fn (mut self OurDBVFS) link_delete(path string) ! {
// mut impl, rel_path := self.find_vfs(path)! parent_path := os.dir(path)
// return impl.file_read(rel_path) file_name := os.base(path)
mut parent_dir := self.get_directory(parent_path)!
parent_dir.rm(file_name)!
} }
pub fn (mut self OurDBVFS) file_delete(path string) ! { pub fn (mut self OurDBVFS) file_delete(path string) ! {
@@ -136,7 +138,7 @@ pub fn (mut self OurDBVFS) link_create(target_path string, link_path string) !vf
mut symlink := ourdb_fs.Symlink{ mut symlink := ourdb_fs.Symlink{
metadata: ourdb_fs.Metadata{ metadata: ourdb_fs.Metadata{
id: u32(time.now().unix()) id: self.core.get_next_id()
name: link_name name: link_name
file_type: .symlink file_type: .symlink
created_at: time.now().unix() created_at: time.now().unix()
@@ -240,6 +242,7 @@ fn convert_to_vfscore_entry(entry ourdb_fs.FSEntry) vfscore.FSEntry {
fn convert_metadata(meta ourdb_fs.Metadata) vfscore.Metadata { fn convert_metadata(meta ourdb_fs.Metadata) vfscore.Metadata {
return vfscore.Metadata{ return vfscore.Metadata{
id: meta.id
name: meta.name name: meta.name
file_type: match meta.file_type { file_type: match meta.file_type {
.file { vfscore.FileType.file } .file { vfscore.FileType.file }

View File

@@ -43,7 +43,7 @@ fn test_vfsourdb() ! {
assert read_content == test_content assert read_content == test_content
// Test directory listing // Test directory listing
entries := vfs.dir_list('/test_dir')! mut entries := vfs.dir_list('/test_dir')!
assert entries.len == 1 assert entries.len == 1
assert entries[0].get_metadata().name == 'test.txt' assert entries[0].get_metadata().name == 'test.txt'
@@ -57,10 +57,17 @@ fn test_vfsourdb() ! {
link_target := vfs.link_read('/test_dir/test_link')! link_target := vfs.link_read('/test_dir/test_link')!
assert link_target == '/test_dir/test.txt' assert link_target == '/test_dir/test.txt'
// Test symlink deletion
vfs.link_delete('/test_dir/test_link')!
assert vfs.exists('/test_dir/test_link') == false
// Test file deletion // Test file deletion
vfs.file_delete('/test_dir/test.txt')! vfs.file_delete('/test_dir/test.txt')!
assert vfs.exists('/test_dir/test.txt') == false assert vfs.exists('/test_dir/test.txt') == false
entries = vfs.dir_list('/test_dir')!
assert entries.len == 0
// Test directory deletion // Test directory deletion
vfs.dir_delete('/test_dir')! vfs.dir_delete('/test_dir')!
assert vfs.exists('/test_dir') == false assert vfs.exists('/test_dir') == false