aboutsummaryrefslogtreecommitdiff
path: root/shared/fs/afs/write/unit.zig
blob: a20da4ecb8c98cbb0d2e1321b1026d6a17e76f8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! AFS Unit Write Operations

const constants = @import("../constants/constants.zig");
const types = @import("../types/types.zig");
const io = @import("../io/io.zig");

const BlockWriter = io.BlockWriter;
const BlockError = io.BlockError;
const SpanDescriptor = types.SpanDescriptor;
const ChannelInfo = types.ChannelInfo;

pub const WriteError = error{
    WriteFailed,
    OutOfSpace,
    InvalidCell,
};

/// Write data to a span
pub fn write_span(
    writer: *const BlockWriter,
    span: *const SpanDescriptor,
    data: []const u8,
    cell_buffer: []u8,
) WriteError!u64 {
    const span_bytes = span.byte_size(writer.cell_size);
    const bytes_to_write = if (data.len < span_bytes) data.len else span_bytes;

    var bytes_written: u64 = 0;
    var current_cell = span.start_cell;

    while (bytes_written < bytes_to_write) {
        // Clear cell buffer
        for (cell_buffer) |*b| {
            b.* = 0;
        }

        const bytes_remaining = bytes_to_write - bytes_written;
        const bytes_to_copy = if (bytes_remaining < writer.cell_size) bytes_remaining else writer.cell_size;

        // Copy data to cell buffer
        var i: u64 = 0;
        while (i < bytes_to_copy) : (i += 1) {
            cell_buffer[@intCast(i)] = data[@intCast(bytes_written + i)];
        }

        writer.write_cell(current_cell, cell_buffer) catch {
            return WriteError.WriteFailed;
        };

        bytes_written += bytes_to_copy;
        current_cell += 1;
    }

    return bytes_written;
}

/// Calculate number of cells needed for a given size
pub fn cells_needed(size: u64, cell_size: u32) u32 {
    if (size == 0) return 0;
    return @intCast((size + cell_size - 1) / cell_size);
}

/// Create a channel info for inline data
pub fn create_channel_info(
    logical_size: u64,
    start_cell: u64,
    cell_count: u64,
    cell_size: u32,
) ChannelInfo {
    var channel = ChannelInfo{
        .logical_size = logical_size,
        .physical_size = cell_count * cell_size,
        .clump_size = cell_size,
        .total_cells = @intCast(cell_count),
        .spans = [_]types.SpanDescriptor{.{}} ** constants.span_inline_count,
    };

    if (cell_count > 0) {
        channel.spans[0] = .{
            .start_cell = start_cell,
            .cell_count = cell_count,
        };
    }

    return channel;
}