/* (c) 2014 LinkedIn Corp. All rights reserved.
*
* 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.
*/
package com.linkedin.cubert.io;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.apache.hadoop.conf.Configuration;
/**
* Creates diffs within the {@code Configuration} object.
*
* @author Maneesh Varshney
*
*/
public class ConfigurationDiff
{
private final Configuration conf;
private Configuration checkpoint;
private int diffIndex = 0;
private int totalDiffs = 0;
public ConfigurationDiff(Configuration conf)
{
this.conf = conf;
}
public int getNumDiffs()
{
return conf.getInt("cubert.conf.num.diffs", 0);
}
public void startDiff()
{
if ((diffIndex + 1) > totalDiffs)
{
totalDiffs = diffIndex + 1;
conf.setInt("cubert.conf.num.diffs", totalDiffs);
}
checkpoint = new Configuration(conf);
}
public void endDiff()
{
if (checkpoint == null)
throw new IllegalStateException("Diffing process was not started");
Iterator<Entry<String, String>> it = conf.iterator();
List<String> diffKeys = new ArrayList<String>();
while (it.hasNext())
{
Entry<String, String> entry = it.next();
String key = entry.getKey();
String newValue = conf.get(key);
String oldValue = checkpoint.get(key);
if (!newValue.equals(oldValue))
{
// print.f("DIFF %d %s: %s => %s", diffIndex, key, oldValue, newValue);
diffKeys.add(key);
if (oldValue == null)
{
conf.unset(key);
}
else
{
conf.set(key, oldValue);
conf.set(String.format("cubert.conf.diff.%d.%s.old", diffIndex, key),
oldValue);
}
conf.set(String.format("cubert.conf.diff.%d.%s.new", diffIndex, key),
newValue);
}
}
if (diffKeys.size() > 0)
{
StringBuilder sb = new StringBuilder();
int idx = 0;
for (String diffKey : diffKeys)
sb.append((idx++ == 0 ? "" : ",") + diffKey);
conf.set(String.format("cubert.conf.diff.%d.keys", diffIndex), sb.toString());
}
checkpoint = null;
diffIndex++;
}
public void applyDiff(int index)
{
int currentDiffIndex = conf.getInt("cubert.diff.current", -1);
// undo diff if one is already present
if (currentDiffIndex != -1 && currentDiffIndex != index)
{
undoDiff(currentDiffIndex);
}
conf.setInt("cubert.diff.current", index);
String diffKeysStr = conf.get(String.format("cubert.conf.diff.%d.keys", index));
if (diffKeysStr == null)
return;
String[] diffKeys = diffKeysStr.split(",");
for (String key : diffKeys)
{
String newValue =
conf.get(String.format("cubert.conf.diff.%d.%s.new", index, key));
if (newValue == null)
conf.unset(key);
else
conf.set(key, newValue);
}
}
public void undoDiff(int index)
{
String diffKeysStr = conf.get(String.format("cubert.conf.diff.%d.keys", index));
if (diffKeysStr == null)
return;
String[] diffKeys = diffKeysStr.split(",");
for (String key : diffKeys)
{
String oldValue =
conf.get(String.format("cubert.conf.diff.%d.%s.old", index, key));
if (oldValue == null)
conf.unset(key);
else
conf.set(key, oldValue);
}
conf.unset("cubert.diff.current");
}
}