1
0
mirror of https://github.com/gilbertchen/duplicacy synced 2025-12-19 09:43:17 +00:00

Rework the Backblaze B2 backend

* All APIs include UploadFile are done via the call() function
* New retry mechanism limiting the maximum backoff each time to 1 minute
* Add an env var DUPLICACY_B2_RETRIES to specify the number of retries
* Handle special/unicode characters in repositor ids
* Allow a directory in a bucket to be used as the storage destination
This commit is contained in:
Gilbert Chen
2019-04-30 23:31:57 -04:00
parent a73ed462b6
commit 57a408a577
5 changed files with 253 additions and 247 deletions

View File

@@ -11,32 +11,26 @@ import (
type B2Storage struct {
StorageBase
clients []*B2Client
client *B2Client
}
// CreateB2Storage creates a B2 storage object.
func CreateB2Storage(accountID string, applicationKey string, bucket string, threads int) (storage *B2Storage, err error) {
func CreateB2Storage(accountID string, applicationKey string, bucket string, storageDir string, threads int) (storage *B2Storage, err error) {
var clients []*B2Client
client := NewB2Client(accountID, applicationKey, storageDir, threads)
for i := 0; i < threads; i++ {
client := NewB2Client(accountID, applicationKey)
err = client.AuthorizeAccount(0)
if err != nil {
return nil, err
}
err = client.AuthorizeAccount()
if err != nil {
return nil, err
}
err = client.FindBucket(bucket)
if err != nil {
return nil, err
}
clients = append(clients, client)
err = client.FindBucket(bucket)
if err != nil {
return nil, err
}
storage = &B2Storage{
clients: clients,
client: client,
}
storage.DerivedStorage = storage
@@ -56,7 +50,7 @@ func (storage *B2Storage) ListFiles(threadIndex int, dir string) (files []string
includeVersions = true
}
entries, err := storage.clients[threadIndex].ListFileNames(dir, false, includeVersions)
entries, err := storage.client.ListFileNames(threadIndex, dir, false, includeVersions)
if err != nil {
return nil, nil, err
}
@@ -102,7 +96,7 @@ func (storage *B2Storage) DeleteFile(threadIndex int, filePath string) (err erro
if strings.HasSuffix(filePath, ".fsl") {
filePath = filePath[:len(filePath)-len(".fsl")]
entries, err := storage.clients[threadIndex].ListFileNames(filePath, true, true)
entries, err := storage.client.ListFileNames(threadIndex, filePath, true, true)
if err != nil {
return err
}
@@ -116,7 +110,7 @@ func (storage *B2Storage) DeleteFile(threadIndex int, filePath string) (err erro
toBeDeleted = true
err = storage.clients[threadIndex].DeleteFile(filePath, entry.FileID)
err = storage.client.DeleteFile(threadIndex, filePath, entry.FileID)
if err != nil {
return err
}
@@ -125,7 +119,7 @@ func (storage *B2Storage) DeleteFile(threadIndex int, filePath string) (err erro
return nil
} else {
entries, err := storage.clients[threadIndex].ListFileNames(filePath, true, false)
entries, err := storage.client.ListFileNames(threadIndex, filePath, true, false)
if err != nil {
return err
}
@@ -133,7 +127,7 @@ func (storage *B2Storage) DeleteFile(threadIndex int, filePath string) (err erro
if len(entries) == 0 {
return nil
}
return storage.clients[threadIndex].DeleteFile(filePath, entries[0].FileID)
return storage.client.DeleteFile(threadIndex, filePath, entries[0].FileID)
}
}
@@ -160,10 +154,10 @@ func (storage *B2Storage) MoveFile(threadIndex int, from string, to string) (err
}
if filePath == from {
_, err = storage.clients[threadIndex].HideFile(from)
_, err = storage.client.HideFile(threadIndex, from)
return err
} else {
entries, err := storage.clients[threadIndex].ListFileNames(filePath, true, true)
entries, err := storage.client.ListFileNames(threadIndex, filePath, true, true)
if err != nil {
return err
}
@@ -171,7 +165,7 @@ func (storage *B2Storage) MoveFile(threadIndex int, from string, to string) (err
return nil
}
return storage.clients[threadIndex].DeleteFile(filePath, entries[0].FileID)
return storage.client.DeleteFile(threadIndex, filePath, entries[0].FileID)
}
}
@@ -188,7 +182,7 @@ func (storage *B2Storage) GetFileInfo(threadIndex int, filePath string) (exist b
filePath = filePath[:len(filePath)-len(".fsl")]
}
entries, err := storage.clients[threadIndex].ListFileNames(filePath, true, isFossil)
entries, err := storage.client.ListFileNames(threadIndex, filePath, true, isFossil)
if err != nil {
return false, false, 0, err
}
@@ -211,21 +205,21 @@ func (storage *B2Storage) GetFileInfo(threadIndex int, filePath string) (exist b
func (storage *B2Storage) DownloadFile(threadIndex int, filePath string, chunk *Chunk) (err error) {
filePath = strings.Replace(filePath, " ", "%20", -1)
readCloser, _, err := storage.clients[threadIndex].DownloadFile(filePath)
readCloser, _, err := storage.client.DownloadFile(threadIndex, filePath)
if err != nil {
return err
}
defer readCloser.Close()
_, err = RateLimitedCopy(chunk, readCloser, storage.DownloadRateLimit/len(storage.clients))
_, err = RateLimitedCopy(chunk, readCloser, storage.DownloadRateLimit/storage.client.Threads)
return err
}
// UploadFile writes 'content' to the file at 'filePath'.
func (storage *B2Storage) UploadFile(threadIndex int, filePath string, content []byte) (err error) {
filePath = strings.Replace(filePath, " ", "%20", -1)
return storage.clients[threadIndex].UploadFile(filePath, content, storage.UploadRateLimit/len(storage.clients))
return storage.client.UploadFile(threadIndex, filePath, content, storage.UploadRateLimit/storage.client.Threads)
}
// If a local snapshot cache is needed for the storage to avoid downloading/uploading chunks too often when
@@ -243,7 +237,5 @@ func (storage *B2Storage) IsFastListing() bool { return true }
// Enable the test mode.
func (storage *B2Storage) EnableTestMode() {
for _, client := range storage.clients {
client.TestMode = true
}
storage.client.TestMode = true
}