reed solomon符号化の実践
17717 ワード
raidの原理をよく知っていれば、このreed solomon(リード・ソロモンコード)符号化には慣れていない.原理の第一歩はまずVandermonde行列によって符号化され、以下のように簡単に説明する.
これで元のABCD-MNOPのデータが符号化されます.このとき選択されるparityフォーマットは2であり、2行のデータの損失を許容し、Vandermonde行列の逆行列に乗算することで元のデータを以下のように得られる.
これがデータリカバリの原理を実証したものです.原理はやはりcode実践してみましょう、このコードはすでに大神が実現して、主義を持ってきました.reed-solomonはまずどのようにコードするかを見ます.
まず元のファイルを開き、データを割り当て、enc.Splitでデータスライスを行い、parityをenc.Encodeで符号化します.私はこの中で4つのスライスと3つのparityを制定して、結果は以下の通りです.
もちろん3つを削除しても復元できます
次はdecodeコードです
この中で得られたスライスは,まずVerifyスライスが完全であるかどうかをチェックし,不完全であればReconstructを再構築する.次に例を示します
decodeのときにデータを再構築します.この符号化を紹介するのは,後続の記述対象格納のための理論的基礎である.
これで元のABCD-MNOPのデータが符号化されます.このとき選択されるparityフォーマットは2であり、2行のデータの損失を許容し、Vandermonde行列の逆行列に乗算することで元のデータを以下のように得られる.
これがデータリカバリの原理を実証したものです.原理はやはりcode実践してみましょう、このコードはすでに大神が実現して、主義を持ってきました.reed-solomonはまずどのようにコードするかを見ます.
func main() {
// Parse command line parameters.
flag.Parse()
args := flag.Args()
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "Error: No input filename given
")
flag.Usage()
os.Exit(1)
}
if *dataShards > 257 {
fmt.Fprintf(os.Stderr, "Error: Too many data shards
")
os.Exit(1)
}
fname := args[0]
// Create encoding matrix.
enc, err := reedsolomon.NewStream(*dataShards, *parShards)
checkErr(err)
fmt.Println("Opening", fname)
f, err := os.Open(fname)
checkErr(err)
instat, err := f.Stat()
checkErr(err)
shards := *dataShards + *parShards
out := make([]*os.File, shards)
// Create the resulting files.
dir, file := filepath.Split(fname)
if *outDir != "" {
dir = *outDir
}
for i := range out {
outfn := fmt.Sprintf("%s.%d", file, i)
fmt.Println("Creating", outfn)
out[i], err = os.Create(filepath.Join(dir, outfn))
checkErr(err)
}
// Split into files.
data := make([]io.Writer, *dataShards)
for i := range data {
data[i] = out[i]
}
// Do the split
err = enc.Split(f, data, instat.Size())
checkErr(err)
// Close and re-open the files.
input := make([]io.Reader, *dataShards)
for i := range data {
out[i].Close()
f, err := os.Open(out[i].Name())
checkErr(err)
input[i] = f
defer f.Close()
}
// Create parity output writers
parity := make([]io.Writer, *parShards)
for i := range parity {
parity[i] = out[*dataShards+i]
defer out[*dataShards+i].Close()
}
// Encode parity
err = enc.Encode(input, parity)
checkErr(err)
fmt.Printf("File split into %d data + %d parity shards.
", *dataShards, *parShards)
}
まず元のファイルを開き、データを割り当て、enc.Splitでデータスライスを行い、parityをenc.Encodeで符号化します.私はこの中で4つのスライスと3つのparityを制定して、結果は以下の通りです.
Opening /mnt/download/kubernetes.tar.gz
Creating kubernetes.tar.gz.0
Creating kubernetes.tar.gz.1
Creating kubernetes.tar.gz.2
Creating kubernetes.tar.gz.3
Creating kubernetes.tar.gz.4
Creating kubernetes.tar.gz.5
Creating kubernetes.tar.gz.6
File split into 4 data + 3 parity shards.
もちろん3つを削除しても復元できます
次はdecodeコードです
func main() {
// Parse flags
flag.Parse()
args := flag.Args()
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "Error: No filenames given
")
flag.Usage()
os.Exit(1)
}
fname := args[0]
// Create matrix
enc, err := reedsolomon.NewStream(*dataShards, *parShards)
checkErr(err)
// Open the inputs
shards, size, err := openInput(*dataShards, *parShards, fname)
checkErr(err)
// Verify the shards
ok, err := enc.Verify(shards)
if ok {
fmt.Println("No reconstruction needed")
} else {
fmt.Println("Verification failed. Reconstructing data")
shards, size, err = openInput(*dataShards, *parShards, fname)
checkErr(err)
// Create out destination writers
out := make([]io.Writer, len(shards))
for i := range out {
if shards[i] == nil {
//dir, _ := filepath.Split(fname)
outfn := fmt.Sprintf("%s.%d", fname, i)
fmt.Println("Creating", outfn)
out[i], err = os.Create(outfn)
checkErr(err)
}
}
fmt.Println("reconstruct")
err = enc.Reconstruct(shards, out)
if err != nil {
fmt.Println("Reconstruct failed -", err)
os.Exit(1)
}
// Close output.
for i := range out {
if out[i] != nil {
err := out[i].(*os.File).Close()
checkErr(err)
}
}
shards, size, err = openInput(*dataShards, *parShards, fname)
ok, err = enc.Verify(shards)
if !ok {
fmt.Println("Verification failed after reconstruction, data likely corrupted:", err)
os.Exit(1)
}
checkErr(err)
}
// Join the shards and write them
outfn := *outFile
if outfn == "" {
outfn = fname
}
fmt.Println("Writing data to", outfn)
f, err := os.Create(outfn)
checkErr(err)
shards, size, err = openInput(*dataShards, *parShards, fname)
checkErr(err)
// We don't know the exact filesize.
err = enc.Join(f, shards, int64(*dataShards)*size)
checkErr(err)
}
func openInput(dataShards, parShards int, fname string) (r []io.Reader, size int64, err error) {
// Create shards and load the data.
shards := make([]io.Reader, dataShards+parShards)
for i := range shards {
infn := fmt.Sprintf("%s.%d", fname, i)
fmt.Println("Opening", infn)
f, err := os.Open(infn)
if err != nil {
fmt.Println("Error reading file", err)
shards[i] = nil
continue
} else {
shards[i] = f
}
stat, err := f.Stat()
checkErr(err)
if stat.Size() > 0 {
size = stat.Size()
} else {
shards[i] = nil
}
}
return shards, size, nil
}
この中で得られたスライスは,まずVerifyスライスが完全であるかどうかをチェックし,不完全であればReconstructを再構築する.次に例を示します
rm -rf kubernetes.tar.gz.1
rm -rf kubernetes.tar.gz.3
rm -rf kubernetes.tar.gz.5
Opening /mnt/download/kubernetes.tar.gz.0
Opening /mnt/download/kubernetes.tar.gz.1
Error reading file open /mnt/download/kubernetes.tar.gz.1: no such file or directory
Opening /mnt/download/kubernetes.tar.gz.2
Opening /mnt/download/kubernetes.tar.gz.3
Error reading file open /mnt/download/kubernetes.tar.gz.3: no such file or directory
Opening /mnt/download/kubernetes.tar.gz.4
Opening /mnt/download/kubernetes.tar.gz.5
Error reading file open /mnt/download/kubernetes.tar.gz.5: no such file or directory
Opening /mnt/download/kubernetes.tar.gz.6
Verification failed. Reconstructing data
Opening /mnt/download/kubernetes.tar.gz.0
Opening /mnt/download/kubernetes.tar.gz.1
Error reading file open /mnt/download/kubernetes.tar.gz.1: no such file or directory
Opening /mnt/download/kubernetes.tar.gz.2
Opening /mnt/download/kubernetes.tar.gz.3
Error reading file open /mnt/download/kubernetes.tar.gz.3: no such file or directory
Opening /mnt/download/kubernetes.tar.gz.4
Opening /mnt/download/kubernetes.tar.gz.5
Error reading file open /mnt/download/kubernetes.tar.gz.5: no such file or directory
Opening /mnt/download/kubernetes.tar.gz.6
Creating /mnt/download/kubernetes.tar.gz.1
Creating /mnt/download/kubernetes.tar.gz.3
Creating /mnt/download/kubernetes.tar.gz.5
reconstruct
Opening /mnt/download/kubernetes.tar.gz.0
Opening /mnt/download/kubernetes.tar.gz.1
Opening /mnt/download/kubernetes.tar.gz.2
Opening /mnt/download/kubernetes.tar.gz.3
Opening /mnt/download/kubernetes.tar.gz.4
Opening /mnt/download/kubernetes.tar.gz.5
Opening /mnt/download/kubernetes.tar.gz.6
Writing data to /mnt/download/kubernetes.tar.gz
Opening /mnt/download/kubernetes.tar.gz.0
Opening /mnt/download/kubernetes.tar.gz.1
Opening /mnt/download/kubernetes.tar.gz.2
Opening /mnt/download/kubernetes.tar.gz.3
Opening /mnt/download/kubernetes.tar.gz.4
Opening /mnt/download/kubernetes.tar.gz.5
Opening /mnt/download/kubernetes.tar.gz.6
decodeのときにデータを再構築します.この符号化を紹介するのは,後続の記述対象格納のための理論的基礎である.