package org.corfudb.protocols.logprotocol;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.corfudb.protocols.wireprotocol.ILogData;
import org.corfudb.runtime.CorfuRuntime;
import org.corfudb.util.serializer.Serializers;
import java.util.*;
/**
* A log entry sturcture which contains a collection of multiSMRentries,
* each one contains a list of updates for one object.
*/
@ToString
@Slf4j
public class MultiObjectSMREntry extends LogEntry implements ISMRConsumable {
// map from stream-ID to a list of updates encapsulated as MultiSMREntry
@Getter
public Map<UUID, MultiSMREntry> entryMap = new HashMap<>();
public MultiObjectSMREntry() { this.type = LogEntryType.MULTIOBJSMR; }
public MultiObjectSMREntry(Map<UUID, MultiSMREntry> entryMap) {
this.type = LogEntryType.MULTIOBJSMR;
this.entryMap = entryMap;
}
/**
*
* @param streamID
* @return the MultiSMREntry corresponding to streamID
*/
protected MultiSMREntry getStreamEntry(UUID streamID) {
return getEntryMap().computeIfAbsent(streamID, u -> {
return new MultiSMREntry();
} );
}
/**
* Add one SMR-update to one object's update-list
* @param streamID
* @param updateEntry
*/
public void addTo(UUID streamID, SMREntry updateEntry) {
getStreamEntry(streamID).addTo(updateEntry);
}
/**
* merge two MultiObjectSMREntry records.
* merging is done object-by-object
* @param other
*/
public void mergeInto(MultiObjectSMREntry other) {
if (other == null) return;
other.getEntryMap().forEach((streamID, MSMRentry) -> {
getStreamEntry(streamID).mergeInto(MSMRentry);
});
}
/**
* This function provides the remaining buffer.
*
* @param b The remaining buffer.
*/
@Override
void deserializeBuffer(ByteBuf b, CorfuRuntime rt) {
super.deserializeBuffer(b, rt);
short numUpdates = b.readShort();
entryMap = new HashMap<>();
for (short i = 0; i < numUpdates; i++) {
entryMap.put(
new UUID(b.readLong(), b.readLong()),
((MultiSMREntry) Serializers.CORFU.deserialize(b, rt))
);
}
}
@Override
public void serialize(ByteBuf b) {
super.serialize(b);
b.writeShort(entryMap.size());
entryMap.entrySet().stream()
.forEach(x -> {
b.writeLong(x.getKey().getMostSignificantBits());
b.writeLong(x.getKey().getLeastSignificantBits());
Serializers.CORFU.serialize(x.getValue(), b);});
}
/**
* Get the list of SMR updates for a particular object
* @param id
* @return an empty list if object has no updates; a list of updates if exists
*/
@Override
public List<SMREntry> getSMRUpdates(UUID id) {
MultiSMREntry entry = entryMap.get(id);
return entryMap.get(id) == null ? Collections.emptyList() :
entry.getUpdates();
}
/**
* An underlying log entry, if present.
*
* @param entry
*/
@Override
public void setEntry(ILogData entry) {
super.setEntry(entry);
this.getEntryMap().values().forEach(x -> {
x.setEntry(entry);
});
}
}