예제 #1
0
파일: recv.go 프로젝트: yangjian/lvbackup
func (sr *streamRecver) prepare() error {
	var buf [SchemeV1HeaderLength]byte
	if _, err := io.ReadFull(sr.r, buf[:]); err != nil {
		return err
	}

	if err := sr.header.UnmarshalBinary(buf[:]); err != nil {
		return err
	}

	// check whether block size of pool match with the stream
	root, err := vgcfg.Dump(sr.vgname)
	if err != nil {
		return err
	}

	pool, ok := root.FindThinPool(sr.poolname)
	if !ok {
		return errors.New("can not find thin pool " + sr.poolname)
	}

	if pool.ChunkSize != int64(sr.header.BlockSize) {
		return errors.New("block size does not match with that of local pool")
	}

	// create new lv if needed
	if sr.header.StreamType == StreamTypeFull {
		if err := lvmutil.CreateThinLv(sr.vgname, sr.poolname, sr.lvname, int64(sr.header.VolumeSize)); err != nil {
			return errors.New("can not create thin lv: " + err.Error())
		}
	}

	if sr.header.StreamType == StreamTypeDelta {
		expected := string(sr.header.DeltaSourceUUID[:])
		if len(sr.prevUUID) > 0 && sr.prevUUID != expected {
			return fmt.Errorf("incremental backup chain is broken; expects %s but prev is %s ", expected, sr.prevUUID)
		}

		// resize the volume if needed
		lv, ok := root.FindThinLv(sr.lvname)
		if !ok {
			return errors.New("can not find thin lv " + sr.lvname)
		}

		size := int64(sr.header.VolumeSize)
		if lv.ExtentCount*root.ExtentSize() != size {
			if err := lvmutil.ResizeLv(sr.vgname, sr.lvname, size); err != nil {
				return errors.New("can not resize thin lv: " + err.Error())
			}
		}
	}

	return nil
}
예제 #2
0
파일: send.go 프로젝트: yangjian/lvbackup
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
}