Created
August 9, 2021 09:58
-
-
Save itzmeanjan/8df52e4b32daf0c5296066a3b240a83d to your computer and use it in GitHub Desktop.
Erasure Coded Storage Cluster with Random Linear Netork Coding --- simulated using `kodr`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module rlnc_in_storage | |
go 1.16 | |
require github.com/itzmeanjan/kodr v0.2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/sha256" | |
"encoding/hex" | |
"log" | |
"math/rand" | |
"os" | |
"time" | |
"github.com/itzmeanjan/kodr" | |
"github.com/itzmeanjan/kodr/full" | |
) | |
func main() { | |
rand.Seed(time.Now().UnixNano()) | |
video, err := os.ReadFile("file.mp4") | |
if err != nil { | |
log.Printf("Error: %s\n", err.Error()) | |
os.Exit(1) | |
} | |
log.Printf("Encoding ::\n\n") | |
log.Printf("Read %d bytes\n", len(video)) | |
hasher := sha256.New() | |
hasher.Write(video) | |
sum := hasher.Sum(nil) | |
log.Printf("SHA256(original): 0x%s\n\n", hex.EncodeToString(sum)) | |
var ( | |
pieceCount = 32 | |
c_pieceCount = 64 | |
) | |
enc, err := full.NewFullRLNCEncoderWithPieceCount(video, uint(pieceCount)) | |
if err != nil { | |
log.Printf("Error: %s\b", err.Error()) | |
os.Exit(1) | |
} | |
c_pieces := make([]*kodr.CodedPiece, 0, c_pieceCount) | |
for i := 0; i < c_pieceCount; i++ { | |
c_piece := enc.CodedPiece() | |
c_pieces = append(c_pieces, c_piece) | |
} | |
log.Printf("Original Piece Size: %d bytes\n", enc.PieceSize()) | |
log.Printf("Padded with %d bytes\n", enc.Padding()) | |
log.Printf("Coded Piece Size: %d bytes\n", enc.CodedPieceLen()) | |
log.Printf("Required %d bytes for decoding\n", enc.DecodableLen()) | |
log.Printf("Coded to %d pieces\n\n", c_pieceCount) | |
{ | |
log.Printf("Decoding ( 1 ) ::\n\n") | |
// random shuffle to demonstrate coded pieces being collected from random locations | |
// all over network | |
rand.Shuffle(c_pieceCount, func(i, j int) { | |
c_pieces[i], c_pieces[j] = c_pieces[j], c_pieces[i] | |
}) | |
have_c_pieces := c_pieces[:pieceCount] | |
dec := full.NewFullRLNCDecoder(uint(pieceCount)) | |
for i := 0; i < pieceCount; i++ { | |
dec.AddPiece(have_c_pieces[i]) | |
} | |
if dec.IsDecoded() { | |
log.Println("Decoded !") | |
} else { | |
log.Println("32 random pieces were not enough !") | |
return // yes just returning back, try again | |
} | |
d_pieces, err := dec.GetPieces() | |
if err != nil { | |
log.Printf("Error: %s\n", err.Error()) | |
os.Exit(1) | |
} | |
flattened := make([]byte, 0) | |
for i := range d_pieces { | |
flattened = append(flattened, d_pieces[i]...) | |
} | |
hasher.Reset() | |
hasher.Write(flattened) | |
sum = hasher.Sum(nil) | |
log.Printf("SHA256(decoded): 0x%s\n\n", hex.EncodeToString(sum)) | |
} | |
log.Printf("Recoding ::\n\n") | |
rand.Shuffle(c_pieceCount, func(i, j int) { | |
c_pieces[i], c_pieces[j] = c_pieces[j], c_pieces[i] | |
}) | |
log.Println("24 pieces unavailable, reconstructing new coded pieces ...") | |
available_c_pieces := c_pieces[:40] | |
r_pieces := make([]*kodr.CodedPiece, 0, 24) | |
{ | |
rec := full.NewFullRLNCRecoder(available_c_pieces[:20]) | |
for i := 0; i < 8; i++ { | |
r_piece, err := rec.CodedPiece() | |
if err != nil { | |
log.Printf("Error: %s\n", err.Error()) | |
os.Exit(1) | |
} | |
r_pieces = append(r_pieces, r_piece) | |
} | |
log.Println("8 recoded pieces from 20 coded pieces") | |
} | |
{ | |
rec := full.NewFullRLNCRecoder(available_c_pieces[10:30]) | |
for i := 0; i < 8; i++ { | |
r_piece, err := rec.CodedPiece() | |
if err != nil { | |
log.Printf("Error: %s\n", err.Error()) | |
os.Exit(1) | |
} | |
r_pieces = append(r_pieces, r_piece) | |
} | |
log.Println("8 recoded pieces from 20 coded pieces") | |
} | |
{ | |
rec := full.NewFullRLNCRecoder(available_c_pieces[20:]) | |
for i := 0; i < 8; i++ { | |
r_piece, err := rec.CodedPiece() | |
if err != nil { | |
log.Printf("Error: %s\n", err.Error()) | |
os.Exit(1) | |
} | |
r_pieces = append(r_pieces, r_piece) | |
} | |
log.Println("8 recoded pieces from 20 coded pieces") | |
} | |
log.Println("24 recoded pieces made from 40 available coded pieces") | |
available_c_pieces = append(available_c_pieces, r_pieces...) | |
log.Printf("Total %d coded pieces available now !\n\n", len(available_c_pieces)) | |
{ | |
log.Printf("Decoding ( 2 ) ::\n\n") | |
rand.Shuffle(c_pieceCount, func(i, j int) { | |
available_c_pieces[i], available_c_pieces[j] = available_c_pieces[j], available_c_pieces[i] | |
}) | |
have_c_pieces := available_c_pieces[:pieceCount] | |
dec := full.NewFullRLNCDecoder(uint(pieceCount)) | |
for i := 0; i < pieceCount; i++ { | |
dec.AddPiece(have_c_pieces[i]) | |
} | |
if dec.IsDecoded() { | |
log.Println("Decoded !") | |
} else { | |
log.Println("32 random pieces were not enough !") | |
return // yes just returning back, try again | |
} | |
d_pieces, err := dec.GetPieces() | |
if err != nil { | |
log.Printf("Error: %s\n", err.Error()) | |
os.Exit(1) | |
} | |
flattened := make([]byte, 0) | |
for i := range d_pieces { | |
flattened = append(flattened, d_pieces[i]...) | |
} | |
hasher.Reset() | |
hasher.Write(flattened) | |
sum = hasher.Sum(nil) | |
log.Printf("SHA256(decoded_): 0x%s\n", hex.EncodeToString(sum)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Background
This simulation accompanies the post I wrote on possibility of using Random Linear Network Coding in storage cluster. It makes use of
kodr
, a RLNC library I'm writing in Golang for demonstrating so.You may want to read aforementioned post in order to get more context.
Usage
You should see something like below in console