// saveVolumeIndex save volumes index info to disk. func (s *Store) saveVolumeIndex() (err error) { var ( tn, n int v *volume.Volume ) if _, err = s.vf.Seek(0, os.SEEK_SET); err != nil { log.Errorf("vf.Seek() error(%v)", err) return } for _, v = range s.Volumes { if n, err = s.vf.WriteString(fmt.Sprintf("%s\n", string(v.Meta()))); err != nil { log.Errorf("vf.WriteString() error(%v)", err) return } tn += n } if err = s.vf.Sync(); err != nil { log.Errorf("vf.Sync() error(%v)", err) return } if err = os.Truncate(s.conf.Store.VolumeIndex, int64(tn)); err != nil { log.Errorf("os.Truncate() error(%v)", err) } return }
// CompactVolume compact a super block to another file. func (s *Store) CompactVolume(id int32) (err error) { var ( v, nv *volume.Volume bdir, idir string ) // try check volume if v = s.Volumes[id]; v != nil { if v.Compact { return errors.ErrVolumeInCompact } } else { return errors.ErrVolumeExist } // find a free volume if nv, err = s.freeVolume(id); err != nil { return } log.Infof("start compact volume: (%d) %s to %s", id, v.Block.File, nv.Block.File) // no lock here, Compact is no side-effect if err = v.StartCompact(nv); err != nil { nv.Destroy() v.StopCompact(nil) return } s.vlock.Lock() if v = s.Volumes[id]; v != nil { log.Infof("stop compact volume: (%d) %s to %s", id, v.Block.File, nv.Block.File) if err = v.StopCompact(nv); err == nil { // WARN no need update volumes map, use same object, only update // zookeeper the local index cause the block and index file changed. if err = s.saveVolumeIndex(); err == nil { err = s.zk.SetVolume(id, v.Meta()) } if err != nil { log.Errorf("compact volume: %d error(%v), local index or zookeeper index may save failed", id, err) } } } else { // never happen err = errors.ErrVolumeExist log.Errorf("compact volume: %d not exist(may bug)", id) } s.vlock.Unlock() // WARN if failed, nv is free volume, if succeed nv replace with v. // Sleep untill anyone had old volume variables all processed. time.Sleep(_compactSleep) nv.Destroy() if err == nil { bdir, idir = filepath.Dir(nv.Block.File), filepath.Dir(nv.Indexer.File) _, err = s.AddFreeVolume(1, bdir, idir) } return }
// BulkVolume copy a super block from another store server add to this server. func (s *Store) BulkVolume(id int32, bfile, ifile string) (err error) { var v, nv *volume.Volume // recovery new block if nv, err = newVolume(id, bfile, ifile, s.conf); err != nil { return } s.vlock.Lock() if v = s.Volumes[id]; v == nil { s.addVolume(id, nv) if err = s.saveVolumeIndex(); err == nil { err = s.zk.AddVolume(id, nv.Meta()) } if err != nil { log.Errorf("bulk volume: %d error(%v), local index or zookeeper index may save failed", id, err) } } else { err = errors.ErrVolumeExist } s.vlock.Unlock() return }
// parseVolumeIndex parse index from local config and zookeeper. func (s *Store) parseVolumeIndex() (err error) { var ( i int ok bool id int32 bfile string ifile string v *volume.Volume data []byte lids, zids []int32 lines []string lbfs, lifs []string zbfs, zifs []string lim, zim map[int32]struct{} ) if data, err = ioutil.ReadAll(s.vf); err != nil { log.Errorf("ioutil.ReadAll() error(%v)", err) return } lines = strings.Split(string(data), "\n") if lim, lids, lbfs, lifs, err = s.parseIndex(lines); err != nil { return } if lines, err = s.zk.Volumes(); err != nil { return } if zim, zids, zbfs, zifs, err = s.parseIndex(lines); err != nil { return } // local index for i = 0; i < len(lbfs); i++ { id, bfile, ifile = lids[i], lbfs[i], lifs[i] if _, ok = s.Volumes[id]; ok { continue } if v, err = newVolume(id, bfile, ifile, s.conf); err != nil { return } s.Volumes[id] = v if _, ok = zim[id]; !ok { if err = s.zk.AddVolume(id, v.Meta()); err != nil { return } } else { if err = s.zk.SetVolume(id, v.Meta()); err != nil { return } } } // zk index for i = 0; i < len(zbfs); i++ { id, bfile, ifile = zids[i], zbfs[i], zifs[i] if _, ok = s.Volumes[id]; ok { continue } // if not exists in local if _, ok = lim[id]; !ok { if v, err = newVolume(id, bfile, ifile, s.conf); err != nil { return } s.Volumes[id] = v } } err = s.saveVolumeIndex() return }