Reed-Solomon coding, byte-range parity updates and placement-aware repair planning
moon run examples/placement --target wasm-gc --deny-warn
moon run examples/range_update --target wasm-gc --deny-warnmoon add oyjh0381/moonerasure@0.3.0import {
"oyjh0381/moonerasure",
}moon check --target all --deny-warn
moon build --target all --deny-warn
moon test --target all --deny-warn
moon run cmd/main --target wasm-gc| Operation | Input | Output / contract |
|---|---|---|
| Codec::encode / encode_all | k equal nonempty data shards | m parity shards / detached complete codeword |
| Codec::verify | All k+m shards | Whether parity agrees with data; no corruption localization |
| Codec::reconstruct | k+m optional slots, at least k known-intact | Complete codeword; surplus supplied shards cross-checked |
| Codec::reconstruct_selected | Optional slots plus unique requested indices | Only requested data/parity, in request order; surplus cross-checked |
| Codec::update_parity | Old parity and indexed old/new data pairs | Detached new parity; unchanged data shards are not supplied |
| Object / catalog methods | Manifest and validated frames | Stripe/range recovery, repair frames, health and inventory |
// Missing slots remain None; only shard 1 is materialized in the result.
let selected = try! codec.reconstruct_selected(surviving, [1])
// Both old data and parity must belong to the same consistent generation.
let changes : Array[@moonerasure.DataShardUpdate] = [
{ index: 3, old_data: old_block, new_data: new_block },
]
let next_parity = try! codec.update_parity(old_parity, changes)let codec = try! @moonerasure.Codec::new(3, 2)
let object = try! @moonerasure.encode_object(
codec,
b"backup bytes",
123,
stripe_payload_limit=64,
)
let retained : Array[@moonerasure.ShardEnvelope] = []
for frame in object.frames() {
if frame.shard_index() != 1 && frame.shard_index() != 4 {
retained.push(frame)
}
}
let recovered = try! @moonerasure.recover_object(object.manifest(), retained)
assert_eq(recovered.payload(), b"backup bytes")
let replacements = try! @moonerasure.repair_object(object.manifest(), retained)| Command | Demonstrated need |
|---|---|
| moon run cmd/main | Backup recovery and replacement frame generation after two placements disappear. |
| moon run examples/transfer | Out-of-order packets, one absent data packet and one checksum-failed parity packet per stripe. |
| moon run examples/scrub | Frame inventory, health inspection, and persisted-slot repair. |
| moon run examples/range | Recover a byte range by fetching only overlapping stripes. |
| moon run examples/stream | Encode arbitrary input chunks and decode one stripe at a time. |
| moon run examples/maintenance | Admit a frame batch atomically and plan reads over currently recoverable byte ranges. |
| moon run examples/degraded_read | Read one missing 4 KiB data block from a 6+3 stripe without allocating unrelated missing shards. |
| moon run examples/incremental_update | Update one 4 KiB block in a 10+4 stripe, compare parity with full encoding, then tolerate four erasures. |
| moon run examples/selective_repair | Rebuild and replace only three failed backup placements, then verify the complete codeword. |
| moon run examples/benchmark --target native | Verified fixed workload for local timing of repeated loss patterns. |
pub(all) suberror ErasureError {
InvalidConfiguration(String)
InvalidShardCount(expected~ : Int, actual~ : Int)
InvalidShardLength(index~ : Int, expected~ : Int, actual~ : Int)
EmptyShard
NotEnoughShards(required~ : Int, available~ : Int)
SingularMatrix
InvalidIndex(Int)
DuplicateIndex(Int)
InconsistentShard(Int)
InvalidRange
InvalidEnvelope(String)
UnsupportedVersion(Int)
ChecksumMismatch(Int)
ResourceLimit(String)
InvalidManifest(String)
}pub struct BundleStream {
cursor : Int
stage : Int
expected_frames : Int
parsed_frames : Int
next_frame_length : Int
manifest : Manifest?
received_bytes : Int
max_input_bytes : Int
max_object_bytes : Int
max_encoded_bytes : Int
// private fields
}fn BundleStream::new(max_input_bytes? : Int, max_object_bytes? : Int, max_encoded_bytes? : Int) -> BundleStream raise ErasureErrorfn BundleStream::push(self : BundleStream, chunk : Bytes) -> Array[ShardEnvelope] raise ErasureErrorfn Codec::assess_domains(self : Codec, present : Array[Bool], placement : Array[String]) -> Array[DomainExposure] raise ErasureErrorfn Codec::new(data_count : Int, parity_count : Int, max_encoded_bytes? : Int) -> Codec raise ErasureErrorfn Codec::plan_costed(self : Codec, present : Array[Bool], costs : Array[Int64]) -> CostedRepairPlan raise ErasureErrorfn Codec::update_parity(self : Codec, parity : Array[Bytes], changes : Array[DataShardUpdate]) -> Array[Bytes] raise ErasureErrorfn Codec::update_parity_ranges(self : Codec, parity : Array[Bytes], changes : Array[DataRangeUpdate], max_ranges? : Int, max_changed_bytes? : Int) -> Array[Bytes] raise ErasureErrorpub struct CostedRepairPlan {
total_cost : Int64
// private fields
}pub(all) struct DataRangeUpdate {
index : Int
offset : Int
old_data : Bytes
new_data : Bytes
}pub(all) struct DataShardUpdate {
index : Int
old_data : Bytes
new_data : Bytes
}pub struct DomainExposure {
domain : String
lost_available : Int
remaining : Int
spare : Int
}pub struct Field {
// private fields
}fn FrameCatalog::add_bytes(self : FrameCatalog, wire : Bytes, max_encoded_bytes? : Int) -> Unit raise ErasureErrorfn FrameCatalog::add_many(self : FrameCatalog, frames : Array[ShardEnvelope], max_frames? : Int) -> Int raise ErasureErrorfn FrameCatalog::get(self : FrameCatalog, stripe_index : Int, shard_index : Int) -> ShardEnvelope? raise ErasureErrorfn FrameCatalog::invalidate(self : FrameCatalog, stripe_index : Int, shard_index : Int) -> Bool raise ErasureErrorfn FrameCatalog::missing_indices(self : FrameCatalog, stripe_index : Int) -> Array[Int] raise ErasureErrorfn FrameCatalog::recover_range(self : FrameCatalog, start : Int, length : Int, max_encoded_bytes? : Int) -> Bytes raise ErasureErrorfn FrameCatalog::recover_stripe(self : FrameCatalog, stripe_index : Int, max_encoded_bytes? : Int) -> StripeRecovery raise ErasureErrorfn FrameCatalog::recoverable_ranges(self : FrameCatalog, max_ranges? : Int) -> Array[RecoverableRange] raise ErasureErrorfn FrameCatalog::stripe_frames(self : FrameCatalog, stripe_index : Int) -> Array[ShardEnvelope] raise ErasureErrorfn FrameCatalog::stripe_recoverable(self : FrameCatalog, stripe_index : Int) -> Bool raise ErasureErrorpub struct FrameIssue {
source_position : Int
code : String
}pub struct FrameScan {
// private fields
}pub struct Manifest {
set_id : Int
data_count : Int
parity_count : Int
stripe_payload_limit : Int
stripe_count : Int
total_length : Int
}fn Manifest::from_bytes(input : Bytes, max_object_bytes? : Int, max_encoded_bytes? : Int) -> Manifest raise ErasureErrorfn Manifest::new(codec : Codec, set_id : Int, stripe_payload_limit : Int, total_length : Int, max_object_bytes? : Int) -> Manifest raise ErasureErrorpub struct Matrix {
rows : Int
cols : Int
// private fields
}fn ObjectDecoder::new(manifest : Manifest, max_encoded_bytes? : Int) -> ObjectDecoder raise ErasureErrorfn ObjectDecoder::push_stripe(self : ObjectDecoder, frames : Array[ShardEnvelope]) -> Bytes raise ErasureErrorfn ObjectEncoder::new(codec : Codec, set_id : Int, total_length : Int, stripe_payload_limit? : Int, max_object_bytes? : Int) -> ObjectEncoder raise ErasureErrorfn ObjectEncoder::push(self : ObjectEncoder, chunk : Bytes) -> Array[ShardEnvelope] raise ErasureErrorpub struct ObjectHealth {
healthy_count : Int
repairable_count : Int
unrecoverable_count : Int
invalid_count : Int
// private fields
}pub struct ObjectRecovery {
payload : Bytes
repaired_shard_count : Int
stripe_count : Int
}pub struct ObjectRepair {
repaired_stripes : Int
// private fields
}pub struct RecoverableRange {
start : Int
end : Int
}pub struct RecoverySession {
codec : Codec
capacity : Int
next_evict : Int
hits : Int
misses : Int
// private fields
}fn RecoverySession::reconstruct(self : RecoverySession, shards : Array[Bytes?]) -> Array[Bytes] raise ErasureErrorpub struct RepairPlan {
required : Int
available : Int
// private fields
}pub struct ScannedRangeRecovery {
payload : Bytes
// private fields
}pub struct ShardEnvelope {
set_id : Int
stripe_index : Int
shard_index : Int
data_count : Int
parity_count : Int
original_length : Int
payload : Bytes
}fn ShardEnvelope::from_bytes(input : Bytes, max_encoded_bytes? : Int) -> ShardEnvelope raise ErasureErrorfn ShardEnvelope::new(codec : Codec, set_id : Int, stripe_index : Int, shard_index : Int, original_length : Int, payload : Bytes) -> ShardEnvelope raise ErasureErrorpub struct StripeHealth {
stripe_index : Int
status : StripeStatus
present_count : Int
reason_code : String?
// private fields
}pub struct StripeRecovery {
payload : Bytes
provided_count : Int
// private fields
}pub(all) enum StripeStatus {
Healthy
Repairable
Unrecoverable
InvalidInput
}fn encode_object(codec : Codec, payload : Bytes, set_id : Int, stripe_payload_limit? : Int, max_object_bytes? : Int, max_output_bytes? : Int) -> EncodedObject raise ErasureErrorfn encode_stripe(codec : Codec, payload : Bytes, set_id : Int, stripe_index : Int) -> Array[ShardEnvelope] raise ErasureErrorfn import_bundle(input : Bytes, max_input_bytes? : Int, max_object_bytes? : Int, max_encoded_bytes? : Int) -> EncodedObject raise ErasureErrorfn inspect_object(manifest : Manifest, frames : Array[ShardEnvelope], max_encoded_bytes? : Int) -> ObjectHealth raise ErasureErrorfn inspect_serialized_object(manifest : Manifest, inputs : Array[Bytes], max_encoded_bytes? : Int, max_total_bytes? : Int) -> ScannedObjectHealth raise ErasureErrorfn inspect_stripe(codec : Codec, frames : Array[ShardEnvelope], set_id : Int, stripe_index : Int) -> StripeHealthfn recover_object(manifest : Manifest, frames : Array[ShardEnvelope], max_encoded_bytes? : Int) -> ObjectRecovery raise ErasureErrorfn recover_object_range(manifest : Manifest, frames : Array[ShardEnvelope], start : Int, length : Int, max_encoded_bytes? : Int) -> Bytes raise ErasureErrorfn recover_serialized_object(manifest : Manifest, inputs : Array[Bytes], max_encoded_bytes? : Int, max_total_bytes? : Int) -> ScannedObjectRecovery raise ErasureErrorfn recover_serialized_range(manifest : Manifest, inputs : Array[Bytes], start : Int, length : Int, max_encoded_bytes? : Int, max_total_bytes? : Int) -> ScannedRangeRecovery raise ErasureErrorfn recover_serialized_stripe(codec : Codec, inputs : Array[Bytes], set_id : Int, stripe_index : Int) -> ScannedRecovery raise ErasureErrorfn recover_stripe(codec : Codec, frames : Array[ShardEnvelope], set_id : Int, stripe_index : Int) -> StripeRecovery raise ErasureErrorfn repair_object(manifest : Manifest, frames : Array[ShardEnvelope], max_encoded_bytes? : Int) -> ObjectRepair raise ErasureErrorfn repair_serialized_object(manifest : Manifest, inputs : Array[Bytes], max_encoded_bytes? : Int, max_total_bytes? : Int) -> ScannedObjectRepair raise ErasureErrorfn scan_frames(inputs : Array[Bytes], max_frames? : Int, max_encoded_bytes? : Int, max_total_bytes? : Int) -> FrameScan raise ErasureErrorInstall
Download zipReed-Solomon coding, byte-range parity updates and placement-aware repair planning