Использование rdiff / bsdiff для go из исходной версии файла (v0.1) в новую версию (v0.2) наилучшим образом / хранилище / загрузка - PullRequest
0 голосов
/ 14 января 2020

Возьмите сценарий, который я хочу создать по пути, работая с файлом (photoshop / word / powerpoint et c (например, двоичные данные)), поэтому каждый раз, когда я создаю v0.x, я создаю резервную копию это тоже. Однако я хочу использовать для этого rdiff, так что мне нужно только хранить фрагменты, которые отличаются между исходной версией и текущей версией.

Я , используя код, найденный здесь и мой код (который запускается) выглядит следующим образом

package main

import (
    "bufio"
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"

    "github.com/jbreiding/rsync-go"
)

var originalFile string
var newFile string
var patchFile string
var signatureFile string
var appliedFile string

func openFile(path string) ([]byte, error) {
    data, err := ioutil.ReadFile(path)
    if err != nil {
        fmt.Println("File reading error", err)
    }
    return data, err
}

func writeFile(path string, data []byte) error {
    err := ioutil.WriteFile(path, data, 0644)
    return err
}

func main() {
    originalFile = "./profile-shot.jpg"
    newFile = "./profile-shot-to.jpg"
    patchFile = "./profile-shot.patch"
    signatureFile = "./profile-shot.sig"
    appliedFile = "./profile-shot-applied.jpg"

    //create a signature based on the original file
    originalFileReader, _ := os.Open(originalFile)
    defer originalFileReader.Close()

    rs := &rsync.RSync{}

    //take a signature of the new
    //apply it to the original
    //get a delta
    //apply the delta to the original
    //get the new??

    // 1. prepare a signature
    sig := make([]rsync.BlockHash, 0, 10)
    writeSignature := func(bl rsync.BlockHash) error {
        sig = append(sig, bl)
        return nil
    }

    //2. take the new file
    newFileReader, _ := os.Open(newFile)

    //3. create the signature
    rs.CreateSignature(originalFileReader, writeSignature)
    sigBytes, err := json.Marshal(sig)
    if err != nil {
        fmt.Println("error ", err)
    } else {
        writeFile(signatureFile, sigBytes)
    }

    opsOut := make(chan rsync.Operation)

    dataWriter := bufio.NewWriter(&dataBuffer)
    //4. specify a write operation for the delta
    writeOperation := func(op rsync.Operation) error {
        opsOut <- op
        data, err := json.Marshal(op.Data)
        if err != nil {
            fmt.Println("error ", err)
        }
        if _, err := dataWriter.Write(data); err != nil {
            fmt.Println("error writing data ", err)
        }
        return nil
    }
    var dataBuffer bytes.Buffer
    go func() {
        defer close(opsOut)
        //5. in a routine, create a delta from the new image and the signature of the original
        err := rs.CreateDelta(newFileReader, sig, writeOperation)
        fmt.Println("err creating delta ", err)
        writeFile(patchFile, dataBuffer.Bytes())
        fmt.Println("length of signature ", len(sig))
        //now we have written the patch to file, we can open the applied file and write the data from the patch to it, by passing the struct(s) to a new opsOut channel, and calling apply delta using that channel
    }()

    // saving the applied delta resulting file
    newFileWriter, err := os.OpenFile(appliedFile, os.O_RDWR|os.O_CREATE, 0600)
    if err != nil {
        fmt.Println("error source writer ", err)
    }
    originalFileReader.Seek(0, os.SEEK_SET)
    //6. apply the delta
    rs.ApplyDelta(newFileWriter, originalFileReader, opsOut)
}

Выше, в основном, то, что я думаю от rdiff.

  • Чтение в исходном файле (v0.1)
  • Создайте подпись из этого файла (v0.1 sig)
  • Создайте дельту, основанную на новом файле (v0.x) и подписи
  • Примените дельту к v0.1, и вы получите v0.x

Проблема в том, что в действительности у меня, скорее всего, будет резервная копия v0.1 и всех подписей каждой следующей версии, и не имеют резервные копии каждой полной версии (что бессмысленно).

Однако для создания дельты требуется новая версия, а не исходная версия. Таким образом, в действительности я не могу go задом наперед, потому что я не могу создавать дельты, когда они мне нужны, без более новой версии и новой версии, которую я пытаюсь получить с помощью rsyn c.

Я понимаю, что решение состоит в том, чтобы сохранить дельту, однако пока (с использованием изображений) дельта равна размеру самих файлов (для тестирования я использую изображения размером от 20 до 100 МБ). Следовательно, использование этого метода также не стоит.

Примечание. Я также использовал bsdiff в Go, и это делает свое дело (примерно в 0,5 раза больше размера реальных файлов), однако это очень медленно из-за алгоритма сортировки, который генерирует индекс. Этот индекс необходим для создания различий. Это примерно в 10 раз больше оригинальных файлов, поэтому хранить их тоже нельзя.

Буду очень признателен за любые идеи относительно лучшего подхода.

...