Remove obsolete gRPC client/server implementations and migrate to remote package
This commit is contained in:
136
manager.go
136
manager.go
@ -2,6 +2,7 @@ package agate
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -31,6 +32,11 @@ func CreateSnapshotManager(metadataStore store.MetadataStore, blobStore store.Bl
|
||||
return nil, errors.New("parameters can't be nil")
|
||||
}
|
||||
|
||||
// Ensure logger is never nil.
|
||||
if logger == nil {
|
||||
logger = log.New(io.Discard, "", 0)
|
||||
}
|
||||
|
||||
return &SnapshotManagerData{
|
||||
metadataStore: metadataStore,
|
||||
blobStore: blobStore,
|
||||
@ -183,31 +189,24 @@ func (data *SnapshotManagerData) DeleteSnapshot(ctx context.Context, snapshotID
|
||||
return errors.New("snapshot ID cannot be empty")
|
||||
}
|
||||
|
||||
// First check if the snapshot exists and get its details
|
||||
snapshot, err := data.metadataStore.GetSnapshotMetadata(ctx, snapshotID)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNotFound) {
|
||||
// If snapshot doesn't exist, return success (idempotent operation)
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("failed to check if snapshot exists: %w", err)
|
||||
}
|
||||
|
||||
// Get the parent ID of the snapshot being deleted
|
||||
parentID := snapshot.ParentID
|
||||
|
||||
// Find all snapshots that have the deleted snapshot as their parent
|
||||
// We need to update their parent ID to maintain the chain
|
||||
opts := store.ListOptions{}
|
||||
allSnapshots, err := data.metadataStore.ListSnapshotsMetadata(ctx, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list snapshots: %w", err)
|
||||
}
|
||||
|
||||
// Update parent references for any snapshots that have this one as a parent
|
||||
for _, info := range allSnapshots {
|
||||
if info.ParentID == snapshotID {
|
||||
// Используем новый, более надежный метод для обновления только parent_id
|
||||
if err := data.metadataStore.UpdateSnapshotParentID(ctx, info.ID, parentID); err != nil {
|
||||
data.logger.Printf("WARNING: failed to update parent reference for snapshot %s: %v", info.ID, err)
|
||||
} else {
|
||||
@ -216,16 +215,11 @@ func (data *SnapshotManagerData) DeleteSnapshot(ctx context.Context, snapshotID
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the metadata first
|
||||
if err := data.metadataStore.DeleteSnapshotMetadata(ctx, snapshotID); err != nil {
|
||||
return fmt.Errorf("failed to delete snapshot metadata: %w", err)
|
||||
}
|
||||
|
||||
// Then delete the blob
|
||||
if err := data.blobStore.DeleteBlob(ctx, snapshotID); err != nil {
|
||||
// Note: We don't return here because we've already deleted the metadata
|
||||
// and the blob store should handle the case where the blob doesn't exist
|
||||
// Log the error instead
|
||||
data.logger.Printf("WARNING: failed to delete snapshot blob: %v", err)
|
||||
}
|
||||
|
||||
@ -392,22 +386,130 @@ func (data *SnapshotManagerData) UpdateSnapshotMetadata(ctx context.Context, sna
|
||||
return errors.New("new name cannot be empty")
|
||||
}
|
||||
|
||||
// Get the current snapshot metadata
|
||||
snapshot, err := data.metadataStore.GetSnapshotMetadata(ctx, snapshotID)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNotFound) {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return ErrNotFound
|
||||
}
|
||||
return fmt.Errorf("failed to get snapshot metadata: %w", err)
|
||||
}
|
||||
|
||||
// Update the name
|
||||
snapshot.Name = newName
|
||||
|
||||
// Save the updated metadata
|
||||
if err := data.metadataStore.SaveSnapshotMetadata(ctx, *snapshot); err != nil {
|
||||
return fmt.Errorf("failed to update snapshot metadata: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// diffArchiveReader is a wrapper around an *os.File that handles cleanup of temporary files.
|
||||
type diffArchiveReader struct {
|
||||
*os.File
|
||||
tempArchive string
|
||||
tempStaging string
|
||||
}
|
||||
|
||||
// Close closes the file and removes the temporary archive and staging directory.
|
||||
func (r *diffArchiveReader) Close() error {
|
||||
err := r.File.Close()
|
||||
os.Remove(r.tempArchive)
|
||||
os.RemoveAll(r.tempStaging)
|
||||
return err
|
||||
}
|
||||
|
||||
func (data *SnapshotManagerData) StreamSnapshotDiff(ctx context.Context, snapshotID, parentID string, offset int64) (io.ReadCloser, error) {
|
||||
targetSnap, err := data.metadataStore.GetSnapshotMetadata(ctx, snapshotID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get target snapshot metadata: %w", err)
|
||||
}
|
||||
|
||||
parentFiles := make(map[string]string)
|
||||
if parentID != "" {
|
||||
parentSnap, err := data.metadataStore.GetSnapshotMetadata(ctx, parentID)
|
||||
if err == nil {
|
||||
for _, file := range parentSnap.Files {
|
||||
if !file.IsDir {
|
||||
parentFiles[file.Path] = file.SHA256
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data.logger.Printf("Warning: failed to get parent snapshot %s, creating full diff: %v", parentID, err)
|
||||
}
|
||||
}
|
||||
|
||||
var filesToInclude []string
|
||||
for _, file := range targetSnap.Files {
|
||||
if file.IsDir {
|
||||
continue
|
||||
}
|
||||
if parentHash, ok := parentFiles[file.Path]; !ok || parentHash != file.SHA256 {
|
||||
filesToInclude = append(filesToInclude, file.Path)
|
||||
}
|
||||
}
|
||||
|
||||
if len(filesToInclude) == 0 {
|
||||
return io.NopCloser(bytes.NewReader(nil)), nil
|
||||
}
|
||||
|
||||
tempStagingDir, err := os.MkdirTemp(data.blobStore.GetBaseDir(), "diff-staging-*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create temp staging directory: %w", err)
|
||||
}
|
||||
|
||||
targetBlobPath, err := data.blobStore.GetBlobPath(ctx, snapshotID)
|
||||
if err != nil {
|
||||
os.RemoveAll(tempStagingDir)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, filePath := range filesToInclude {
|
||||
destPath := filepath.Join(tempStagingDir, filePath)
|
||||
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
|
||||
os.RemoveAll(tempStagingDir)
|
||||
return nil, fmt.Errorf("failed to create dir for diff file: %w", err)
|
||||
}
|
||||
|
||||
fileWriter, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
os.RemoveAll(tempStagingDir)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = archive.ExtractFileFromArchive(targetBlobPath, filePath, fileWriter)
|
||||
fileWriter.Close()
|
||||
if err != nil {
|
||||
os.RemoveAll(tempStagingDir)
|
||||
return nil, fmt.Errorf("failed to extract file %s for diff: %w", filePath, err)
|
||||
}
|
||||
}
|
||||
|
||||
tempArchivePath := filepath.Join(data.blobStore.GetBaseDir(), "diff-"+snapshotID+".zip")
|
||||
if err := archive.CreateArchive(tempStagingDir, tempArchivePath); err != nil {
|
||||
os.RemoveAll(tempStagingDir)
|
||||
os.Remove(tempArchivePath)
|
||||
return nil, fmt.Errorf("failed to create diff archive: %w", err)
|
||||
}
|
||||
|
||||
archiveFile, err := os.Open(tempArchivePath)
|
||||
if err != nil {
|
||||
os.RemoveAll(tempStagingDir)
|
||||
os.Remove(tempArchivePath)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
if _, err := archiveFile.Seek(offset, io.SeekStart); err != nil {
|
||||
archiveFile.Close()
|
||||
os.RemoveAll(tempStagingDir)
|
||||
os.Remove(tempArchivePath)
|
||||
return nil, fmt.Errorf("failed to seek in diff archive: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &diffArchiveReader{
|
||||
File: archiveFile,
|
||||
tempArchive: tempArchivePath,
|
||||
tempStaging: tempStagingDir,
|
||||
}, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user