func (s *streamSender) Run() error { if err := s.prepare(); err != nil { return err } if err := s.putHeader(&s.header); err != nil { return err } if len(s.srcname) > 0 { // always activate original lv so that target lv can be activated later if err := lvmutil.ActivateLv(s.vgname, s.srcname); err != nil { return err } defer lvmutil.DeactivateLv(s.vgname, s.srcname) } if err := lvmutil.ActivateLv(s.vgname, s.lvname); err != nil { return err } defer lvmutil.DeactivateLv(s.vgname, s.lvname) devpath := lvmutil.LvDevicePath(s.vgname, s.lvname) devFile, err := directio.OpenFile(devpath, os.O_RDONLY, 0644) if err != nil { return err } defer devFile.Close() buf := directio.AlignedBlock(int(s.header.BlockSize)) blockSize := int64(s.header.BlockSize) for _, e := range s.blocks { if e.OpType == thindump.DeltaOpDelete { for i := 0; i < len(buf); i++ { buf[i] = 0 } } else { if _, err := devFile.Seek(e.OriginBlock*blockSize, os.SEEK_SET); err != nil { return err } if _, err := io.ReadFull(devFile, buf); err != nil { return err } } if err := s.putBlock(e.OriginBlock, buf); err != nil { return err } } return nil }
func (sr *streamRecver) recvNextStream() error { if err := sr.prepare(); err != nil { return err } devpath := lvmutil.LvDevicePath(sr.vgname, sr.lvname) devFile, err := directio.OpenFile(devpath, os.O_WRONLY, 0644) if err != nil { return err } defer devFile.Close() n := 8 + sr.header.BlockSize b := make([]byte, n+md5.Size) buf := directio.AlignedBlock(int(sr.header.BlockSize)) for i := uint64(0); i < sr.header.BlockCount; i++ { if _, err := io.ReadFull(sr.r, b); err != nil { return err } sr.h.Reset() sr.h.Write(b[:n]) if !bytes.Equal(sr.h.Sum(nil), b[n:n+md5.Size]) { return fmt.Errorf("check sum mismatch for %dst block", i) } index := int64(binary.BigEndian.Uint64(b)) copy(buf, b[8:n]) if _, err := devFile.Seek(int64(sr.header.BlockSize)*index, os.SEEK_SET); err != nil { return err } if _, err := devFile.Write(buf); err != nil { return err } } sr.prevUUID = string(sr.header.VolumeUUID[:]) return nil }
func (s *streamSender) prepare() error { root, err := vgcfg.Dump(s.vgname) if err != nil { return err } var lv, srclv *vgcfg.ThinLvInfo var ok bool lv, ok = root.FindThinLv(s.lvname) if !ok { return errors.New("can not find thin lv " + s.lvname) } if len(s.srcname) > 0 { srclv, ok = root.FindThinLv(s.srcname) if !ok { return errors.New("can not find thin lv " + s.srcname) } } if srclv != nil && lv.Pool != srclv.Pool { return errors.New("thin volumes must in same pool for delta backup") } pool, ok := root.FindThinPool(lv.Pool) if !ok { return errors.New("can not find thin pool " + lv.Pool) } // dump block mapping tpoolDev := lvmutil.TPoolDevicePath(s.vgname, pool.Name) tmetaDev := lvmutil.LvDevicePath(s.vgname, pool.MetaName) superblk, err := thindump.Dump(tpoolDev, tmetaDev) if err != nil { return err } var dev, srcdev *thindump.Device dev, ok = superblk.FindDevice(lv.DeviceId) if !ok { return errors.New("super block do not have device " + string(lv.DeviceId)) } if srclv != nil { srcdev, ok = superblk.FindDevice(srclv.DeviceId) if !ok { return errors.New("super block do not have device " + string(srclv.DeviceId)) } } // list all blocks for full backup, or find changed blocks by comparing block // mappings for incremental backup. deltas, err := thindump.CompareDeviceBlocks(srcdev, dev) if err != nil { return err } s.blocks = deltas s.header.SchemeVersion = StreamSchemeV1 s.header.StreamType = StreamTypeFull s.header.VolumeSize = uint64(lv.ExtentCount) * uint64(root.ExtentSize()) s.header.BlockSize = uint32(pool.ChunkSize) s.header.BlockCount = uint64(len(s.blocks)) copy(s.header.VolumeUUID[:], []byte(lv.UUID)) if srclv != nil { s.header.StreamType = StreamTypeDelta copy(s.header.DeltaSourceUUID[:], []byte(srclv.UUID)) } return nil }