func RestoreSnapshot(root, srcSnapshotID, srcVolumeID, dstVolumeID, objectstoreID string, sDriver drivers.Driver) error { b, bsDriver, err := getObjectStoreCfgAndDriver(root, objectstoreID) if err != nil { return err } if _, err := loadVolumeConfig(srcVolumeID, bsDriver); err != nil { return generateError(logrus.Fields{ LOG_FIELD_VOLUME: srcVolumeID, LOG_FIELD_OBJECTSTORE: objectstoreID, }, "Volume doesn't exist in objectstore: %v", err) } volDevName, err := sDriver.GetVolumeDevice(dstVolumeID) if err != nil { return err } volDev, err := os.Create(volDevName) if err != nil { return err } defer volDev.Close() snapshotMap, err := loadSnapshotMap(srcSnapshotID, srcVolumeID, bsDriver) if err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_RESTORE, LOG_FIELD_OBJECT: LOG_FIELD_SNAPSHOT, LOG_FIELD_SNAPSHOT: srcSnapshotID, LOG_FIELD_ORIN_VOLUME: srcVolumeID, LOG_FIELD_VOLUME: dstVolumeID, LOG_FIELD_OBJECTSTORE: objectstoreID, }).Debug() for _, block := range snapshotMap.Blocks { blkFile := getBlockFilePath(srcVolumeID, block.BlockChecksum) rc, err := bsDriver.Read(blkFile) if err != nil { return err } if _, err := volDev.Seek(block.Offset, 0); err != nil { rc.Close() return err } if _, err := io.CopyN(volDev, rc, b.BlockSize); err != nil { rc.Close() return err } rc.Close() } return nil }
func BackupSnapshot(root, snapshotID, volumeID, objectstoreID string, sDriver drivers.Driver) error { b, bsDriver, err := getObjectStoreCfgAndDriver(root, objectstoreID) if err != nil { return err } volume, err := loadVolumeConfig(volumeID, bsDriver) if err != nil { return err } if snapshotExists(snapshotID, volumeID, bsDriver) { return generateError(logrus.Fields{ LOG_FIELD_SNAPSHOT: snapshotID, LOG_FIELD_VOLUME: volumeID, LOG_FIELD_OBJECTSTORE: objectstoreID, }, "Snapshot already exists in objectstore!") } lastSnapshotID := volume.LastSnapshotID var lastSnapshotMap *SnapshotMap if lastSnapshotID != "" { if lastSnapshotID == snapshotID { //Generate full snapshot if the snapshot has been backed up last time lastSnapshotID = "" log.Debug("Would create full snapshot metadata") } else if !sDriver.HasSnapshot(lastSnapshotID, volumeID) { // It's possible that the snapshot in objectstore doesn't exist // in local storage lastSnapshotID = "" log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_FALLBACK, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_SNAPSHOT: lastSnapshotID, LOG_FIELD_VOLUME: volumeID, }).Debug("Cannot find last snapshot in local storage, would process with full backup") } else { log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_EVENT: LOG_EVENT_LOAD, LOG_FIELD_SNAPSHOT: lastSnapshotID, }).Debug("Loading last snapshot") lastSnapshotMap, err = loadSnapshotMap(lastSnapshotID, volumeID, bsDriver) if err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_COMPLETE, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_EVENT: LOG_EVENT_LOAD, LOG_FIELD_SNAPSHOT: lastSnapshotID, }).Debug("Loaded last snapshot") } } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_EVENT: LOG_EVENT_COMPARE, LOG_FIELD_SNAPSHOT: snapshotID, LOG_FIELD_LAST_SNAPSHOT: lastSnapshotID, }).Debug("Generating snapshot changed blocks metadata") delta, err := sDriver.CompareSnapshot(snapshotID, lastSnapshotID, volumeID) if err != nil { return err } if delta.BlockSize != b.BlockSize { return fmt.Errorf("Currently doesn't support different block sizes between objectstore and driver") } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_COMPLETE, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_EVENT: LOG_EVENT_COMPARE, LOG_FIELD_SNAPSHOT: snapshotID, LOG_FIELD_LAST_SNAPSHOT: lastSnapshotID, }).Debug("Generated snapshot changed blocks metadata") log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_BACKUP, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_SNAPSHOT: snapshotID, }).Debug("Creating snapshot changed blocks") snapshotDeltaMap := &SnapshotMap{ Blocks: []BlockMapping{}, } if err := sDriver.OpenSnapshot(snapshotID, volumeID); err != nil { return err } defer sDriver.CloseSnapshot(snapshotID, volumeID) for _, d := range delta.Mappings { block := make([]byte, b.BlockSize) for i := int64(0); i < d.Size/delta.BlockSize; i++ { offset := d.Offset + i*delta.BlockSize err := sDriver.ReadSnapshot(snapshotID, volumeID, offset, block) if err != nil { return err } checksum := util.GetChecksum(block) blkFile := getBlockFilePath(volumeID, checksum) if bsDriver.FileSize(blkFile) >= 0 { blockMapping := BlockMapping{ Offset: offset, BlockChecksum: checksum, } snapshotDeltaMap.Blocks = append(snapshotDeltaMap.Blocks, blockMapping) log.Debugf("Found existed block match at %v", blkFile) continue } log.Debugf("Creating new block file at %v", blkFile) if err := bsDriver.Write(blkFile, bytes.NewReader(block)); err != nil { return err } log.Debugf("Created new block file at %v", blkFile) blockMapping := BlockMapping{ Offset: offset, BlockChecksum: checksum, } snapshotDeltaMap.Blocks = append(snapshotDeltaMap.Blocks, blockMapping) } } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_COMPLETE, LOG_FIELD_EVENT: LOG_EVENT_BACKUP, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_SNAPSHOT: snapshotID, }).Debug("Created snapshot changed blocks") snapshotMap := mergeSnapshotMap(snapshotID, snapshotDeltaMap, lastSnapshotMap) if err := saveSnapshotMap(snapshotID, volumeID, bsDriver, snapshotMap); err != nil { return err } volume.LastSnapshotID = snapshotID if err := saveVolumeConfig(volumeID, bsDriver, volume); err != nil { return err } return nil }