Documentation
¶
Overview ¶
Package grasure is an Universal Erasure Coding Architecture in Go
For usage and examples, see https://github.com/DurantVivado/Grasure
Index ¶
- type Erasure
- func (e *Erasure) Destroy(mode string, failNum int, fileName string)
- func (e *Erasure) EncodeFile(filename string) (*fileInfo, error)
- func (e *Erasure) InitSystem(assume bool) error
- func (e *Erasure) ReadConfig() error
- func (e *Erasure) ReadDiskPath() error
- func (e *Erasure) ReadFile(filename string, savepath string, degrade bool) error
- func (e *Erasure) Recover() (map[string]string, error)
- func (e *Erasure) RemoveFile(filename string) error
- func (e *Erasure) Scale(new_k, new_m int) error
- func (e *Erasure) Update(oldFile, newFile string) error
- func (e *Erasure) WriteConfig() error
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Erasure ¶
type Erasure struct {
// the number of data blocks in a stripe
K int `json:"dataShards"`
// the number of parity blocks in a stripe
M int `json:"parityShards"`
// the block size. default to 4KiB
BlockSize int64 `json:"blockSize"`
// the disk number, only the first diskNum disks are used in diskPathFile
DiskNum int `json:"diskNum"`
//FileMeta lists, indicating fileName, fileSize, fileHash, fileDist...
FileMeta []*fileInfo `json:"fileLists"`
//how many stripes are allowed to encode/decode concurrently
ConStripes int `json:"-"`
// the replication factor for config file
ReplicateFactor int
// configuration file path
ConfigFile string `json:"-"`
// the path of file recording all disks path
DiskFilePath string `json:"-"`
// whether or not to override former files or directories, default to false
Override bool `json:"-"`
//whether or not to mute outputs
Quiet bool `json:"-"`
// contains filtered or unexported fields
}
func (*Erasure) Destroy ¶
Destroy simulates disk failure or bitrot:
for `diskFail mode`, `failNum` random disks are marked as unavailable, `failName` is ignored.
for `bitRot`, `failNum` random blocks in a stripe of the file corrupts, that only works in Read Mode;
Since it's a simulation, no real data will be lost. Note that failNum = min(failNum, DiskNum).
func (*Erasure) EncodeFile ¶
EncodeFile takes filepath as input and encodes the file into data and parity blocks concurrently.
It returns `*fileInfo` and an error. Specify `blocksize` and `conStripe` for better performance.
Example ¶
An intriguing example of how to encode a file into the system
package main
import (
"fmt"
"log"
"math/rand"
"os"
grasure "github.com/DurantVivado/Grasure"
)
func fillRandom(p []byte) {
for i := 0; i < len(p); i += 7 {
val := rand.Int63()
for j := 0; i+j < len(p) && j < 7; j++ {
p[i+j] = byte(val)
val >>= 8
}
}
}
func prepareDir(diskNum int) error {
f, err := os.Create(".hdr.disks.path")
if err != nil {
return err
}
defer f.Close()
for i := 0; i < diskNum; i++ {
path := fmt.Sprintf("disk%d", i)
if err := os.RemoveAll(path); err != nil {
return err
}
if err := os.Mkdir(path, 0644); err != nil {
return err
}
_, err := f.WriteString(path + "\n")
if err != nil {
return err
}
}
return nil
}
func main() {
// Create some sample data
data := make([]byte, 250000)
filepath := "example.file"
fillRandom(data)
// write it into a file
f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
log.Fatal(err)
}
_, err = f.Write(data)
if err != nil {
log.Fatal(err)
}
f.Close()
// define the struct Erasure
erasure := &grasure.Erasure{
DiskFilePath: ".hdr.disks.path",
ConfigFile: "config.json",
DiskNum: 10,
K: 6,
M: 3,
BlockSize: 4096,
ReplicateFactor: 3,
ConStripes: 100,
Override: true,
}
err = prepareDir(13)
if err != nil {
log.Fatal(err)
}
//read the disk paths
err = erasure.ReadDiskPath()
if err != nil {
log.Fatal(err)
}
//first init the system
err = erasure.InitSystem(true)
if err != nil {
log.Fatal(err)
}
//read the config file (auto-generated)
err = erasure.ReadConfig()
if err != nil {
log.Fatal(err)
}
//encode the file into system
_, err = erasure.EncodeFile(filepath)
if err != nil {
log.Fatal(err)
}
//write the config
err = erasure.WriteConfig()
if err != nil {
log.Fatal(err)
}
fmt.Println("encode ok!")
}
Output: Warning: you are intializing a new erasure-coded system, which means the previous data will also be reset. System init! Erasure parameters: dataShards:6, parityShards:3,blocksize:4096,diskNum:10 encode ok!
func (*Erasure) InitSystem ¶
Init initiates the erasure-coded system, this func can NOT be called concurrently. It will clear all the data on the storage, so a consulting procedure is added in advance of perilous action.
Note if `assume` renders yes then the consulting part will be skipped.
func (*Erasure) ReadConfig ¶
ReadConfig reads the config file during system warm-up.
Calling it before actions like encode and read is a good habit.
func (*Erasure) ReadDiskPath ¶
ReadDiskPath reads the disk paths from diskFilePath. There should be exactly ONE disk path at each line.
This func can NOT be called concurrently.
func (*Erasure) ReadFile ¶
ReadFile reads ONE file on the system and save it to local `savePath`.
In case of any failure within fault tolerance, the file will be decoded first. `degrade` indicates whether degraded read is enabled.
func (*Erasure) Recover ¶
RecoverReadFull mainly deals with a disk-level disaster reconstruction. User should provide enough backup devices in `.hdr.disk.path` for data transferring.
An (oldPath -> replacedPath) replace map is returned in the first placeholder.
Example ¶
A fabulous example on recovery of disks
package main
import (
"fmt"
"log"
grasure "github.com/DurantVivado/Grasure"
)
func main() {
erasure := &grasure.Erasure{
DiskFilePath: ".hdr.disks.path",
ConfigFile: "config.json",
DiskNum: 10,
K: 6,
M: 3,
BlockSize: 4096,
ReplicateFactor: 3,
ConStripes: 100,
Override: true,
}
//read the disk paths
err := erasure.ReadDiskPath()
if err != nil {
log.Fatal(err)
}
err = erasure.ReadConfig()
if err != nil {
log.Fatal(err)
}
erasure.Destroy("diskFail", 2, "")
_, err = erasure.Recover()
if err != nil {
log.Fatal(err)
}
err = erasure.WriteConfig()
if err != nil {
log.Fatal(err)
}
fmt.Println("system recovered")
}
Output: system recovered
func (*Erasure) RemoveFile ¶
RemoveFile deletes specific file `filename`in the system.
Both the file blobs and meta data are deleted. It's currently irreversible.
Example ¶
A curious example on removal of file, please encode the file into system first
package main
import (
"fmt"
"log"
grasure "github.com/DurantVivado/Grasure"
)
func main() {
filepath := "example.file"
erasure := &grasure.Erasure{
DiskFilePath: ".hdr.disks.path",
ConfigFile: "config.json",
DiskNum: 10,
K: 6,
M: 3,
BlockSize: 4096,
ReplicateFactor: 3,
ConStripes: 100,
Override: true,
}
//read the disk paths
err := erasure.ReadDiskPath()
if err != nil {
log.Fatal(err)
}
err = erasure.ReadConfig()
if err != nil {
log.Fatal(err)
}
err = erasure.RemoveFile(filepath)
if err != nil {
log.Fatal(err)
}
err = erasure.WriteConfig()
if err != nil {
log.Fatal(err)
}
fmt.Println("file removed")
}
Output: file removed
func (*Erasure) Scale ¶ added in v0.0.4
Scale expands the storage system to a new k and new m, for example, Start with a (2,1) system but with more data flouring into, the system needs to be scaled to a larger system, say (6,4).
One advantage is that a bigger k supports higher storage efficiency.
Another is that requirement of fault tolerance may level up when needed.
It unavoidably incurrs serious data migration. We are working to minimize the traffic.
func (*Erasure) Update ¶ added in v0.0.4
update a file according to a new file, the local `filename` will be used to update the file in the cloud with the same name
func (*Erasure) WriteConfig ¶
WriteConfig writes the erasure parameters and file information list into config files.
Calling it after actions like encode and read is a good habit.