ZipponDB/src/file/utils.zig
MrBounty 98f0c69e61 SOLVED THREAD BUG
Needed a thread safe alloc. Will need to update other part as I just did
parseEntities and deleteEntities
2025-01-22 22:34:46 +01:00

202 lines
9.6 KiB
Zig

const std = @import("std");
const utils = @import("../utils.zig");
const config = @import("config");
const Self = @import("core.zig").Self;
const ZipponError = @import("error").ZipponError;
const Allocator = std.mem.Allocator;
const ConditionValue = @import("../dataStructure/filter.zig").ConditionValue;
const ValueOrArray = @import("../ziql/parts/newData.zig").ValueOrArray;
const dtype = @import("dtype");
const UUID = dtype.UUID;
const zid = @import("ZipponData");
const log = std.log.scoped(.fileEngine);
var path_buffer: [1024]u8 = undefined;
pub fn readSchemaFile(sub_path: []const u8, buffer: []u8) ZipponError!usize {
const file = std.fs.cwd().openFile(sub_path, .{}) catch return ZipponError.CantOpenFile;
defer file.close();
const len = file.readAll(buffer) catch return ZipponError.ReadError;
return len;
}
pub fn writeDbMetrics(self: *Self, buffer: *std.ArrayList(u8)) ZipponError!void {
const main_dir = std.fs.cwd().openDir(self.path_to_ZipponDB_dir, .{ .iterate = true }) catch return ZipponError.CantOpenDir;
const writer = buffer.writer();
writer.print("Database path: {s}\n", .{self.path_to_ZipponDB_dir}) catch return ZipponError.WriteError;
const main_size = getDirTotalSize(main_dir) catch 0;
writer.print("Total size: {d:.2}Mb\n", .{@as(f64, @floatFromInt(main_size)) / 1024.0 / 1024.0}) catch return ZipponError.WriteError;
writer.print("CPU core: {d}\n", .{config.CPU_CORE}) catch return ZipponError.WriteError;
writer.print("Max file size: {d:.2}Mb\n", .{@as(f64, @floatFromInt(config.MAX_FILE_SIZE)) / 1024.0 / 1024.0}) catch return ZipponError.WriteError;
const log_dir = main_dir.openDir("LOG", .{ .iterate = true }) catch return ZipponError.CantOpenDir;
const log_size = getDirTotalSize(log_dir) catch 0;
writer.print("LOG: {d:.2}Mb\n", .{@as(f64, @floatFromInt(log_size)) / 1024.0 / 1024.0}) catch return ZipponError.WriteError;
const backup_dir = main_dir.openDir("BACKUP", .{ .iterate = true }) catch return ZipponError.CantOpenDir;
const backup_size = getDirTotalSize(backup_dir) catch 0;
writer.print("BACKUP: {d:.2}Mb\n", .{@as(f64, @floatFromInt(backup_size)) / 1024.0 / 1024.0}) catch return ZipponError.WriteError;
const data_dir = main_dir.openDir("DATA", .{ .iterate = true }) catch return ZipponError.CantOpenDir;
const data_size = getDirTotalSize(data_dir) catch 0;
writer.print("DATA: {d:.2}Mb\n", .{@as(f64, @floatFromInt(data_size)) / 1024.0 / 1024.0}) catch return ZipponError.WriteError;
var iter = data_dir.iterate();
while (iter.next() catch return ZipponError.DirIterError) |entry| {
if (entry.kind != .directory) continue;
const sub_dir = data_dir.openDir(entry.name, .{ .iterate = true }) catch return ZipponError.CantOpenDir;
const size = getDirTotalSize(sub_dir) catch 0;
const result = try self.getNumberOfEntityAndFile(entry.name);
writer.print(" {s}: {d:.2}Mb | {d} entities | {d} files\n", .{
entry.name,
@as(f64, @floatFromInt(size)) / 1024.0 / 1024.0,
result.entity,
result.file,
}) catch return ZipponError.WriteError;
}
}
pub fn getDirTotalSize(dir: std.fs.Dir) !u64 {
var total: u64 = 0;
var stat: std.fs.File.Stat = undefined;
var iter = dir.iterate();
while (try iter.next()) |entry| {
if (entry.kind == .directory) {
const sub_dir = try dir.openDir(entry.name, .{ .iterate = true });
total += try getDirTotalSize(sub_dir);
}
if (entry.kind != .file) continue;
stat = try dir.statFile(entry.name);
total += stat.size;
}
return total;
}
pub fn string2Data(allocator: Allocator, value: ConditionValue) ZipponError!zid.Data {
switch (value) {
.int => |v| return zid.Data.initInt(v),
.float => |v| return zid.Data.initFloat(v),
.bool_ => |v| return zid.Data.initBool(v),
.unix => |v| return zid.Data.initUnix(v),
.str => |v| return zid.Data.initStr(v),
.link => |v| {
if (v.count() > 0) {
var iter = v.keyIterator();
return zid.Data.initUUID(iter.next().?.bytes);
} else {
const uuid = UUID.parse("00000000-0000-0000-0000-000000000000") catch return ZipponError.InvalidUUID;
return zid.Data.initUUID(uuid.bytes);
}
},
.link_array => |v| {
var iter = v.keyIterator();
var items = std.ArrayList([16]u8).init(allocator);
defer items.deinit();
while (iter.next()) |uuid| {
items.append(uuid.bytes) catch return ZipponError.MemoryError;
}
return zid.Data.initUUIDArray(zid.allocEncodArray.UUID(allocator, items.items) catch return ZipponError.AllocEncodError);
},
.self => |v| return zid.Data.initUUID(v.bytes),
.int_array => |v| return zid.Data.initIntArray(zid.allocEncodArray.Int(allocator, v) catch return ZipponError.AllocEncodError),
.float_array => |v| return zid.Data.initFloatArray(zid.allocEncodArray.Float(allocator, v) catch return ZipponError.AllocEncodError),
.str_array => |v| return zid.Data.initStrArray(zid.allocEncodArray.Str(allocator, v) catch return ZipponError.AllocEncodError),
.bool_array => |v| return zid.Data.initBoolArray(zid.allocEncodArray.Bool(allocator, v) catch return ZipponError.AllocEncodError),
.unix_array => |v| return zid.Data.initUnixArray(zid.allocEncodArray.Unix(allocator, v) catch return ZipponError.AllocEncodError),
}
}
/// Take a map from the parseNewData and return an ordered array of Data to be use in a DataWriter
pub fn orderedNewData(
self: *Self,
allocator: Allocator,
struct_name: []const u8,
map: std.StringHashMap(ValueOrArray),
) ZipponError![]zid.Data {
const members = try self.schema_engine.structName2structMembers(struct_name);
var datas = allocator.alloc(zid.Data, (members.len)) catch return ZipponError.MemoryError;
const new_uuid = UUID.init();
datas[0] = zid.Data.initUUID(new_uuid.bytes);
for (members, 0..) |member, i| {
if (i == 0) continue; // Skip the id
datas[i] = try string2Data(allocator, map.get(member).?.value);
}
return datas;
}
/// Get the index of the first file that is bellow the size limit. If not found, create a new file
pub fn getFirstUsableIndexFile(self: Self, struct_name: []const u8) ZipponError!usize {
var member_dir = try self.printOpenDir("{s}/DATA/{s}", .{ self.path_to_ZipponDB_dir, struct_name }, .{ .iterate = true });
defer member_dir.close();
var i: usize = 0;
var iter = member_dir.iterate();
while (iter.next() catch return ZipponError.DirIterError) |entry| {
i += 1;
const file_stat = member_dir.statFile(entry.name) catch return ZipponError.FileStatError;
if (file_stat.size < config.MAX_FILE_SIZE) {
// Cant I just return i ? It is supossed that files are ordered. I think I already check and it is not
log.debug("First usable file found for `{s}`: {s}", .{ struct_name, entry.name });
return std.fmt.parseInt(usize, entry.name[0..(entry.name.len - 4)], 10) catch return ZipponError.InvalidFileIndex; // INFO: Hardcoded len of file extension
}
}
const path = std.fmt.bufPrint(&path_buffer, "{s}/DATA/{s}/{d}.zid", .{ self.path_to_ZipponDB_dir, struct_name, i }) catch return ZipponError.MemoryError;
zid.createFile(path, null) catch return ZipponError.ZipponDataError;
return i;
}
pub fn allFileIndex(self: Self, allocator: Allocator, struct_name: []const u8) ZipponError![]usize {
var dir = try self.printOpenDir("{s}/DATA/{s}", .{ self.path_to_ZipponDB_dir, struct_name }, .{ .iterate = true });
defer dir.close();
var array = std.ArrayList(usize).init(allocator);
var iter = dir.iterate();
while (iter.next() catch return ZipponError.DirIterError) |entry| {
if (entry.kind != .file) continue;
if (std.mem.eql(u8, entry.name[0..(entry.name.len - 4)], ".new")) continue; // TODO: Delete the file, shouldn't be here
const index = std.fmt.parseInt(usize, entry.name[0..(entry.name.len - 4)], 10) catch return ZipponError.InvalidFileIndex;
array.append(index) catch return ZipponError.MemoryError;
}
return array.toOwnedSlice() catch return ZipponError.MemoryError;
}
pub fn isSchemaFileInDir(self: *Self) bool {
_ = self.printOpenFile("{s}/schema", .{self.path_to_ZipponDB_dir}, .{}) catch return false;
return true;
}
pub fn writeSchemaFile(self: *Self, null_terminated_schema_buff: [:0]const u8) ZipponError!void {
var zippon_dir = std.fs.cwd().openDir(self.path_to_ZipponDB_dir, .{}) catch return ZipponError.MemoryError;
defer zippon_dir.close();
zippon_dir.deleteFile("schema") catch |err| switch (err) {
error.FileNotFound => {},
else => return ZipponError.DeleteFileError,
};
var file = zippon_dir.createFile("schema", .{}) catch return ZipponError.CantMakeFile;
defer file.close();
file.writeAll(null_terminated_schema_buff) catch return ZipponError.WriteError;
}
pub fn printOpenDir(_: Self, comptime format: []const u8, args: anytype, options: std.fs.Dir.OpenDirOptions) ZipponError!std.fs.Dir {
const path = std.fmt.bufPrint(&path_buffer, format, args) catch return ZipponError.CantOpenDir;
return std.fs.cwd().openDir(path, options) catch ZipponError.CantOpenDir;
}
pub fn printOpenFile(_: Self, comptime format: []const u8, args: anytype, options: std.fs.File.OpenFlags) ZipponError!std.fs.File {
const path = std.fmt.bufPrint(&path_buffer, format, args) catch return ZipponError.CantOpenDir;
return std.fs.cwd().openFile(path, options) catch ZipponError.CantOpenFile;
}