Package com.cybozu.vmbkp.profile

Source Code of com.cybozu.vmbkp.profile.ProfileVm

/**
* @file
* @brief ProfileVm, DescLongComparator
*
* Copyright (C) 2009,2010 Cybozu Inc., all rights reserved.
*
* @author Takashi HOSHINO <hoshino@labs.cybozu.co.jp>
*/
package com.cybozu.vmbkp.profile;

import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Set;
import java.util.TreeSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.Comparator;
import java.util.logging.Logger;

import com.cybozu.vmbkp.config.Entry;
import com.cybozu.vmbkp.config.Group;
import com.cybozu.vmbkp.config.FormatBool;
import com.cybozu.vmbkp.config.FormatInt;
import com.cybozu.vmbkp.config.ParseException;
import com.cybozu.vmbkp.config.NotNormalFileException;

import com.cybozu.vmbkp.util.VmInfo;

import com.cybozu.vmbkp.profile.ConfigWrapper;
import com.cybozu.vmbkp.profile.ProfileGeneration;

/**
* @brief Comparator of long values in descending order.
*/
class DescLongComparator
    implements Comparator<Long>
{
    public int compare(Long o1, Long o2) {
        return (-1) * o1.compareTo(o2);
    }
}

/**
* @brief Wrapper class to access vmbkp_vm.profile
*/
public class ProfileVm
    extends ConfigWrapper
{
    public static final String FILE_NAME = "vmbkp_vm.profile";

    /**
     * Logger.
     */
    private static final Logger logger_ =
        Logger.getLogger(ProfileVm.class.getName());
   
    /**
     * Group [meta].
     */
    private Group grpMeta_;

    /**
     * Group [index "timestamp_ms-generation"].
     */
    private Group grpTsGen_;

    /**
     * Default constructor. This will create an empty config.
     */
    public ProfileVm()
    {
        super();
        initializeGroups();
    }
   
    /**
     * Constructor reading the specified config file.
     *
     * @param fileName Path to a vmbkp_vm.profile file.
     */
    public ProfileVm(String fileName)
        throws IOException, ParseException, NotNormalFileException
    {
        super(fileName);
        initializeGroups();
    }

    /**
     * Initialize group(s).
     */
    private void initializeGroups()
    {
        /* initialize group(s) */
        grpMeta_ = new Group("meta");
        grpTsGen_ = new Group("index", "timestamp_ms-generation");
    }

    /**
     * Make generation group.
     * @param genId generation id.
     * @return generated group.
     */
    private Group makeGenerationGroup(int genId)
    {
        if (genId < 0) {
            logger_.warning("generation id < 0.");
        }
        return new Group("generation", Integer.toString(genId));
    }

    /**
     * Get status flag of the specified generation.
     *
     * @param genId generation id.
     * @return [generation `genertionId`] status
     */
    public boolean isGenerationSucceeded(int genId)
    {
        Group genGroup = makeGenerationGroup(genId);
        String status = cfg_.getVal(genGroup, "status");
        return (status != null && status.equals("succeeded"));
    }

    /**
     * Set status flag of the specified generation.
     *
     * @param genId generation id.
     * @param isSucceeded specify true if the genration was succeeded, or false.
     */
    public void setIsGenerationSucceeded(int genId, boolean isSucceeded)
    {
        Group genGroup = makeGenerationGroup(genId);
        cfg_.put(genGroup, "status", (isSucceeded ? "succeeded" : "failed"));
    }

    /**
     * Set [meta] name.
     */
    public void setName(String name)
    {
        cfg_.put(grpMeta_, "name", name);
    }

    /**
     * Get [meta] name.
     */
    public String getName()
    {
        return cfg_.getVal(grpMeta_, "name");
    }

    /**
     * Get [meta] moref.
     */
    public String getMoref()
    {
        return cfg_.getVal(grpMeta_, "moref");
    }

    /**
     * Check [meta] is_clean.
     */
    public boolean isClean()
    {
        String isClean = cfg_.getVal(grpMeta_, "is_clean");

        if (isClean == null) {
            logger_.warning("is_clean entry not found.");
            return false;
        }

        if (FormatBool.isBool(isClean) == false) {
            logger_.warning("is_clean entry not bool value.");
            return false;
        }

        if (FormatBool.toBool(isClean) == false) {
            logger_.warning
                (String.format
                 ("is_clean of %s is false. check backup archives.",
                  getMoref()));
            return false;
        }

        /* it is clean. */
        return true;
    }

    /**
     * Initialize [meta] *.
     *
     * @param vmm Initialize metadata of the config
     * for the specified virtual machine.
     */
    public void initializeMetadata(VmInfo vmInfo)
    {
        cfg_.put(grpMeta_, "moref", vmInfo.getMoref());
        cfg_.put(grpMeta_, "name", vmInfo.getName());
        cfg_.put(grpMeta_, "is_clean", "true");
        cfg_.put(grpMeta_, "latest", "-1"); /* latest generation id */
    }

    /**
     * Get succeeded latest generation id.
     *
     * @return generation id if succeeded generation exists, or -2.
     */
    public int getLatestSucceededGenerationId()
    {
        int latestId = getLatestGenerationId();
        if (latestId < 0) {
            return -2;
        }
        if (isGenerationSucceeded(latestId)) {
            return latestId;
        }
        int prevId = getPrevSucceededGenerationId(latestId);
        if (prevId >= 0) {
            return prevId;
        }
        return -2; /* error */
    }

    /**
     * Get the value of [meta] latest.
     */
    public int getLatestGenerationId()
    {
        String genStr = cfg_.getVal(grpMeta_, "latest");

        if (FormatInt.canBeInt(genStr)) {
            return FormatInt.toInt(genStr);
        } else {
            return -2; /* -1 is normal, -2 is abnormal. */
        }
    }

    /**
     * Create new generation id.
     *
     * @param timestampMs timestamp in milliseconds as string.
     * @return new generation id.
     */
    public int createNewGenerationId(String timestampMs)
        throws Exception
    {
        int depGenId = this.getLatestSucceededGenerationId();
       
        int currGenId = this.getLatestGenerationId();
        if (currGenId < -1) { throw new Exception("currGenId < -1."); }
        int newGenId = currGenId + 1; assert newGenId >= 0;

        this.setLatestGenerationId(newGenId);
        this.setIsGenerationSucceeded(newGenId, false);
        this.setTimestampMs(newGenId, timestampMs);
        this.setDependingGenerationId(newGenId, depGenId);
       
        return newGenId;
    }

    /**
     * Set [meta] latest
     *
     * @param newGenId newly created generation id.
     */
    private void setLatestGenerationId(int newGenId)
    {
        cfg_.put(grpMeta_, "latest", Integer.toString(newGenId));
    }

    /**
     * Get id of succeeded previous generation.
     *
     * @param genId base generation id.
     * @return previously succeeded generation if found, or -2.
     */
    public int getPrevSucceededGenerationId(int genId)
    {
        Map<Long,Integer> genMap = this.getGenerationMap();
        ArrayList<Integer> genList = new ArrayList<Integer>(genMap.values());
       
        Integer genIdI = new Integer(genId);

        int curIdx = genList.indexOf(genIdI);
        if (curIdx < 0) { return -2; } /* not found */

        for (int idx = curIdx - 1; idx >= 0; idx --) {
            Integer tmpGenIdI = genList.get(idx);
            int tmpGenId = tmpGenIdI.intValue();

            if (isGenerationSucceeded(tmpGenId)) {
                return tmpGenId;
            }
        }
        return -2;
    }

    /**
     * Get id of succeeded next generation.
     *
     * @param genId base generatino id.
     * @return Newer least succeeded generation if found, or -2.
     */
    public int getNextSucceededGenerationId(int genId)
    {
        Map<Long,Integer> genMap = this.getGenerationMap();
        ArrayList<Integer> genList = new ArrayList<Integer>(genMap.values());
       
        Integer genIdI = new Integer(genId);

        int curIdx = genList.indexOf(genIdI);
        if (curIdx < 0) { return -2; } /* not found */

        for (int idx = curIdx + 1; idx < genList.size(); idx ++) {
            Integer tmpGenIdI = genList.get(idx);
            int tmpGenId = tmpGenIdI.intValue();

            if (isGenerationSucceeded(tmpGenId)) {
                return tmpGenId;
            }
        }

        return -2; /* not found */
    }

    /**
     * Get depending generation id.
     *
     * @param genId generation id.
     * @return if >=0 that is depending on the generation,
     *         -1 then no dependency.
     */
    public int getDependingGenerationId(int genId)
    {
        Group genGroup = makeGenerationGroup(genId);
        String depGenIdStr = cfg_.getVal(genGroup, "depending_generation_id");
        if (depGenIdStr != null && FormatInt.canBeInt(depGenIdStr)) {
            return FormatInt.toInt(depGenIdStr);
        } else {
            return -1;
        }
    }

    /**
     * Set depending generation id.
     *
     * @param genId generation id.
     * @param depGenId genId depends on this.
     */
    public void setDependingGenerationId(int genId, int depGenId)
    {
        Group genGroup = makeGenerationGroup(genId);
        cfg_.put(genGroup, "depending_generation_id",
                 Integer.toString(depGenId));
    }
   
    /**
     * Get id set of old generations.
     *
     * @param keepGenerations The number of generations to keep.
     * @return A set of id of old generations.
     */
    public Set<Integer> getOldGenerationSet(int keepGenerations)
    {
        Set<Integer> ret = new TreeSet<Integer>();
       
        DescLongComparator cmp = new DescLongComparator();
        Map<Long,Integer> map = this.getGenerationMap(cmp);
       
        /* skip first keepGenerations entries */
        int i = 0;
        for (Map.Entry<Long, Integer> e : map.entrySet()) {
            Integer genId = e.getValue();
            if (i >= keepGenerations) {
                ret.add(e.getValue());
            }
            if (isGenerationSucceeded(genId)) {
                i ++;
            }
        }
        return ret;
    }

    /**
     * Get id set of failed generations except for latest generation.
     */
    public List<Integer> getFailedGenerationList()
    {
        List<Integer> list = getGenerationIdList();
        List<Integer> ret = new LinkedList<Integer>();

        int latestId = getLatestGenerationId();
        if (latestId < 0) {
            logger_.warning("LatestId < 0.");
            return ret;
        }
       
        for (Integer genIdI : list) {
            assert genIdI != null;
            int genId = genIdI.intValue();
           
            if (! isGenerationSucceeded(genId)
                && genId != latestId) {

                ret.add(genIdI);
            }
        }
        return ret;
    }

    /**
     * Get the set of all geneartion set.
     * @return map of timestamp -> generation id.
     */
    private Map<Long,Integer> getGenerationMap()
    {
        return getGenerationMap(null);
    }
   
    /**
     * Get the set of all geneartion set.
     * @param cmp Comparator of timestamp.
     * @return map of timestamp -> generation id.
     */
    private Map<Long,Integer> getGenerationMap(Comparator<Long> cmp)
    {
        /* convert to ordered map */
        List<Entry> entryList = cfg_.getAllEntries(grpTsGen_);

        Map<Long, Integer> map;
        if (cmp != null) {
            map = new TreeMap<Long, Integer>(cmp);
        } else {
            map = new TreeMap<Long, Integer>();
        }

        for (Entry entry : entryList) {
            String tsStr = entry.getKey();
            assert FormatInt.canBeLong(tsStr);
            long ts = FormatInt.toLong(tsStr);

            String idStr = entry.getVal();
            assert FormatInt.canBeInt(idStr);
            int id = FormatInt.toInt(idStr);
           
            map.put(new Long(ts), new Integer(id));
        }

        return map;
    }

    /**
     * Get value of [generation `genId`] timestamp_ms.
     */
    public String getTimestampMs(int genId)
    {
        Group genGroup = makeGenerationGroup(genId);
        return cfg_.getVal(genGroup, "timestamp_ms");
    }

    /**
     * Get value of [generation `genid`] timestamp.
     */
    public String getTimestampStr(int genId)
    {
        Group genGroup = makeGenerationGroup(genId);
        return cfg_.getVal(genGroup, "timestamp");
    }
   
    /**
     * Set [generation `genId`] timestamp_ms.
     * and reset [index "timestamp_ms-generation"] data.
     */
    public void setTimestampMs(int genId, String timestampMs)
    {
        String oldTimestampStr = getTimestampMs(genId);
        if (oldTimestampStr != null) {
            logger_.info
                ("delete from [index \"timestamp_ms-generation\"] " +
                 oldTimestampStr);
            cfg_.del(grpTsGen_, oldTimestampStr);
        }

        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(Long.valueOf(timestampMs));
       
        Group genGroup = makeGenerationGroup(genId);
        cfg_.put(genGroup, "timestamp", cal.getTime().toString());
        cfg_.put(genGroup, "timestamp_ms", timestampMs);
        cfg_.put(grpTsGen_, timestampMs, Integer.toString(genId));
    }

    /**
     * Set generation information.
     * Please call this after backup of the generation is succeeded.
     */
    public void setGenerationInfo(ProfileGeneration profGen)
    {
        assert profGen != null;

        int genId = profGen.getGenerationId();
       
        Group genGroup = makeGenerationGroup(genId);
        String timestampMs = profGen.getTimestampMs();

        this.setIsGenerationSucceeded(genId, profGen.isSucceeded());
        this.setTimestampMs(genId, timestampMs);
    }

    /**
     * Delete the specified generation information.
     */
    public void delGenerationInfo(int genId)
    {
        /* Delete entry from the secondary index. */
        String timestampMs = this.getTimestampMs(genId);
        if (timestampMs != null) {
            cfg_.del(grpTsGen_, timestampMs);
        }

        /* Delete generation group. */
        Group genGroup = makeGenerationGroup(genId);
        cfg_.delGroup(genGroup);
    }

    /**
     * Get default generation directory path
     * This does not check the path is valid.
     *
     * @return Path string or null in error.
     */
    public String getDefaultGenerationDirectory(int genId)
    {
        if (genId < 0) { return null; }

        /* ProfileVm path */
        String path = getDirectory();
        if (path == null) { return null; }

        return path + "/" +
            Integer.toString(genId);
    }
   
    /**
     * Get default generation profile path for
     * the specified generationId.
     * This does not check the path is valid.
     *
     * @return Path string or null in error.
     */
    public String getDefaultProfileGenerationPath(int genId)
    {
        String path = getDefaultGenerationDirectory(genId);
        if (path == null) { return null; }
        return path + "/" + ProfileGeneration.FILE_NAME;
    }

    /**
     * Get number of generaton.
     */
    private int getNumOfGeneration()
    {
        Map<Long,Integer> genMap = getGenerationMap();
        return genMap.size();
    }
   
    /**
     * Get number of succeeded generation.
     */
    private int getNumOfSuccceededGeneration()
    {
        Map<Long,Integer> genMap = getGenerationMap();
        ArrayList<Integer> genList =
            new ArrayList<Integer>(genMap.values());

        int count = 0;
        for (Integer i: genList) {
            assert i != null;

            if (isGenerationSucceeded(i)) {
                count ++;
            }
        }
        return count;
    }

    /**
     * Get the list of id of generations.
     *
     * @return list of id of generations.
     *         never return null, never contain null.
     */
    public List<Integer> getGenerationIdList()
    {
        List<Integer> ret = new LinkedList<Integer>();
        Map<Long, Integer> map = getGenerationMap();
       
        for (Integer genId: map.values()) {

            if (genId == null) { continue; }
            ret.add(genId);
        }
        return ret;
    }

    /**
     * Get status string.
     */
    public String getStatusString(boolean isAvailable)
    {
        StringBuffer sb = new StringBuffer();

        if (isAvailable) {
            sb.append(String.format
                      ("[%s][%s]", getMoref(), getName()));
        } else {
            sb.append(String.format
                      ("[(%s)][%s]", getMoref(), getName()));
        }

        int genId = getLatestSucceededGenerationId();
        if (genId < 0) {
            sb.append(" ----------NO_ARCHIVE ----------");
        } else {
            sb.append(String.format
                      ("[Latest %d \"%s\"]", genId, getTimestampStr(genId)));

            int numGen = getNumOfGeneration();
            int numSucceededGen = getNumOfSuccceededGeneration();
            sb.append(String.format
                      ("[Clean %d/%d]", numSucceededGen, numGen));
        }

        return sb.toString();
    }
}
TOP

Related Classes of com.cybozu.vmbkp.profile.ProfileVm

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.