org.elasticsearch.cluster.DiffableUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.cluster;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import com.google.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Maps.newHashMap;
public final class DiffableUtils {
private DiffableUtils() {
}
/**
* Calculates diff between two ImmutableOpenMaps of Diffable objects
*/
public static > Diff> diff(ImmutableOpenMap before, ImmutableOpenMap after) {
assert after != null && before != null;
return new ImmutableOpenMapDiff<>(before, after);
}
/**
* Calculates diff between two ImmutableMaps of Diffable objects
*/
public static > Diff> diff(ImmutableMap before, ImmutableMap after) {
assert after != null && before != null;
return new ImmutableMapDiff<>(before, after);
}
/**
* Loads an object that represents difference between two ImmutableOpenMaps
*/
public static > Diff> readImmutableOpenMapDiff(StreamInput in, KeyedReader keyedReader) throws IOException {
return new ImmutableOpenMapDiff<>(in, keyedReader);
}
/**
* Loads an object that represents difference between two ImmutableMaps
*/
public static > Diff> readImmutableMapDiff(StreamInput in, KeyedReader keyedReader) throws IOException {
return new ImmutableMapDiff<>(in, keyedReader);
}
/**
* Loads an object that represents difference between two ImmutableOpenMaps
*/
public static > Diff> readImmutableOpenMapDiff(StreamInput in, T proto) throws IOException {
return new ImmutableOpenMapDiff<>(in, new PrototypeReader<>(proto));
}
/**
* Loads an object that represents difference between two ImmutableMaps
*/
public static > Diff> readImmutableMapDiff(StreamInput in, T proto) throws IOException {
return new ImmutableMapDiff<>(in, new PrototypeReader<>(proto));
}
/**
* A reader that can deserialize an object. The reader can select the deserialization type based on the key. It's
* used in custom metadata deserialization.
*/
public interface KeyedReader {
/**
* reads an object of the type T from the stream input
*/
T readFrom(StreamInput in, String key) throws IOException;
/**
* reads an object that respresents differences between two objects with the type T from the stream input
*/
Diff readDiffFrom(StreamInput in, String key) throws IOException;
}
/**
* Implementation of the KeyedReader that is using a prototype object for reading operations
*
* Note: this implementation is ignoring the key.
*/
public static class PrototypeReader> implements KeyedReader {
private T proto;
public PrototypeReader(T proto) {
this.proto = proto;
}
@Override
public T readFrom(StreamInput in, String key) throws IOException {
return proto.readFrom(in);
}
@Override
public Diff readDiffFrom(StreamInput in, String key) throws IOException {
return proto.readDiffFrom(in);
}
}
/**
* Represents differences between two ImmutableMaps of diffable objects
*
* @param the diffable object
*/
private static class ImmutableMapDiff> extends MapDiff> {
protected ImmutableMapDiff(StreamInput in, KeyedReader reader) throws IOException {
super(in, reader);
}
public ImmutableMapDiff(ImmutableMap before, ImmutableMap after) {
assert after != null && before != null;
for (String key : before.keySet()) {
if (!after.containsKey(key)) {
deletes.add(key);
}
}
for (ImmutableMap.Entry partIter : after.entrySet()) {
T beforePart = before.get(partIter.getKey());
if (beforePart == null) {
adds.put(partIter.getKey(), partIter.getValue());
} else if (partIter.getValue().equals(beforePart) == false) {
diffs.put(partIter.getKey(), partIter.getValue().diff(beforePart));
}
}
}
@Override
public ImmutableMap apply(ImmutableMap map) {
HashMap builder = newHashMap();
builder.putAll(map);
for (String part : deletes) {
builder.remove(part);
}
for (Map.Entry> diff : diffs.entrySet()) {
builder.put(diff.getKey(), diff.getValue().apply(builder.get(diff.getKey())));
}
for (Map.Entry additon : adds.entrySet()) {
builder.put(additon.getKey(), additon.getValue());
}
return ImmutableMap.copyOf(builder);
}
}
/**
* Represents differences between two ImmutableOpenMap of diffable objects
*
* @param the diffable object
*/
private static class ImmutableOpenMapDiff> extends MapDiff> {
protected ImmutableOpenMapDiff(StreamInput in, KeyedReader reader) throws IOException {
super(in, reader);
}
public ImmutableOpenMapDiff(ImmutableOpenMap before, ImmutableOpenMap after) {
assert after != null && before != null;
for (ObjectCursor key : before.keys()) {
if (!after.containsKey(key.value)) {
deletes.add(key.value);
}
}
for (ObjectObjectCursor partIter : after) {
T beforePart = before.get(partIter.key);
if (beforePart == null) {
adds.put(partIter.key, partIter.value);
} else if (partIter.value.equals(beforePart) == false) {
diffs.put(partIter.key, partIter.value.diff(beforePart));
}
}
}
@Override
public ImmutableOpenMap apply(ImmutableOpenMap map) {
ImmutableOpenMap.Builder builder = ImmutableOpenMap.builder();
builder.putAll(map);
for (String part : deletes) {
builder.remove(part);
}
for (Map.Entry> diff : diffs.entrySet()) {
builder.put(diff.getKey(), diff.getValue().apply(builder.get(diff.getKey())));
}
for (Map.Entry additon : adds.entrySet()) {
builder.put(additon.getKey(), additon.getValue());
}
return builder.build();
}
}
/**
* Represents differences between two maps of diffable objects
*
* This class is used as base class for different map implementations
*
* @param the diffable object
*/
private static abstract class MapDiff, M> implements Diff {
protected final List deletes;
protected final Map> diffs;
protected final Map adds;
protected MapDiff() {
deletes = new ArrayList<>();
diffs = newHashMap();
adds = newHashMap();
}
protected MapDiff(StreamInput in, KeyedReader reader) throws IOException {
deletes = new ArrayList<>();
diffs = newHashMap();
adds = newHashMap();
int deletesCount = in.readVInt();
for (int i = 0; i < deletesCount; i++) {
deletes.add(in.readString());
}
int diffsCount = in.readVInt();
for (int i = 0; i < diffsCount; i++) {
String key = in.readString();
Diff diff = reader.readDiffFrom(in, key);
diffs.put(key, diff);
}
int addsCount = in.readVInt();
for (int i = 0; i < addsCount; i++) {
String key = in.readString();
T part = reader.readFrom(in, key);
adds.put(key, part);
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(deletes.size());
for (String delete : deletes) {
out.writeString(delete);
}
out.writeVInt(diffs.size());
for (Map.Entry> entry : diffs.entrySet()) {
out.writeString(entry.getKey());
entry.getValue().writeTo(out);
}
out.writeVInt(adds.size());
for (Map.Entry entry : adds.entrySet()) {
out.writeString(entry.getKey());
entry.getValue().writeTo(out);
}
}
}
}