/* * Copyright 2008-2012 LinkedIn, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package voldemort.utils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; import java.util.Properties; import org.apache.log4j.Logger; import voldemort.client.SystemStoreClient; import voldemort.store.system.SystemStoreConstants; import voldemort.versioning.VectorClock; import voldemort.versioning.Versioned; /** * A Utils class that facilitates conversion between the string containing * metadata versions and the corresponding Properties object. * * @author csoman * */ public class MetadataVersionStoreUtils { private final static Logger logger = Logger.getLogger(MetadataVersionStoreUtils.class); /** * Retrieves a properties (hashmap) consisting of all the metadata versions * * @param versionStore The system store client used to retrieve the metadata * versions * @return Properties object containing all the * 'property_name=property_value' values */ public static Properties getProperties(SystemStoreClient<String, String> versionStore) { Properties props = null; Versioned<String> versioned = versionStore.getSysStore(SystemStoreConstants.VERSIONS_METADATA_KEY); if(versioned != null && versioned.getValue() != null) { try { String versionList = versioned.getValue(); props = new Properties(); props.load(new ByteArrayInputStream(versionList.getBytes())); } catch(Exception e) { logger.warn("Error retrieving properties ", e); } } return props; } private static long tryParse(String s) { try { return Long.parseLong(s); } catch(NumberFormatException e) { return 0L; } } public static Long getVersion(Properties prop, String versionKey) { long value = 0; if(prop != null && prop.getProperty(versionKey) != null) { String strValue = prop.getProperty(versionKey); value = tryParse(strValue); } if(logger.isDebugEnabled()) { logger.debug("*********** For key : " + versionKey + " received value = " + value); } return value; } public static Properties mergeVersions(Properties prop1, Properties prop2) { if(prop1 == null) { return prop2; } if(prop2 == null) { return prop1; } Properties result = new Properties(); for(String propName: prop1.stringPropertyNames()) { result.setProperty(propName, prop1.getProperty(propName)); } for(String propName: prop2.stringPropertyNames()) { String currValue = result.getProperty(propName); long currlValue = tryParse(currValue); String newValue = prop2.getProperty(propName); long lValue = tryParse(newValue); long maxlValue = Math.max(currlValue, lValue); result.setProperty(propName, Long.toString(maxlValue)); } return result; } public static Versioned<Properties> parseProperties(List<Versioned<byte[]>> versionProps) { Properties props = new Properties(); if(versionProps == null || versionProps.size() == 0) { return new Versioned<Properties>(props); } VectorClock version = new VectorClock(); for(int cur = 0; cur < versionProps.size(); cur++) { VectorClock curVersion = (VectorClock) versionProps.get(cur).getVersion(); version = version.merge(curVersion); byte[] value = versionProps.get(cur).getValue(); if(value == null) { continue; } Properties curProps = new Properties(); try { curProps.load(new ByteArrayInputStream(value)); } catch(Exception e) { continue; } props = mergeVersions(props, curProps); } return new Versioned<Properties>(props, version); } private static String getPropertiesString(Properties props) { StringBuilder finalVersionList = new StringBuilder(); for(String propName: props.stringPropertyNames()) { if(finalVersionList.length() == 0) { finalVersionList.append(propName + "=" + props.getProperty(propName)); } else { finalVersionList.append("\n" + propName + "=" + props.getProperty(propName)); } } return finalVersionList.toString(); } public static byte[] convertToByteArray(Properties props) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); props.store(out, null); out.flush(); return out.toByteArray(); } /** * Writes the Properties object to the Version metadata system store * * @param versionStore The system store client used to retrieve the metadata * versions * @param props The Properties object to write to the System store */ public static void setProperties(SystemStoreClient<String, String> versionStore, Versioned<Properties> props) { if(props == null || props.getValue() == null) { logger.info("Ignoring set for empty properties"); return; } try { String versionString = getPropertiesString(props.getValue()); Versioned<String> versionedString = new Versioned<String>(versionString, props.getVersion()); versionStore.putSysStore(SystemStoreConstants.VERSIONS_METADATA_KEY, versionedString); } catch(Exception e) { logger.info("Got exception in setting properties : ", e); } } /** * Writes the Properties object to the Version metadata system store * * @param versionStore The system store client used to retrieve the metadata * versions * @param props The Properties object to write to the System store */ public static void setProperties(SystemStoreClient<String, String> versionStore, Properties props) { if (props == null) { logger.info("Ignoring set for empty properties"); return; } try { String versionString = getPropertiesString(props); versionStore.putSysStore(SystemStoreConstants.VERSIONS_METADATA_KEY, versionString); } catch(Exception e) { logger.info("Got exception in setting properties : ", e); } } }