package org.corfudb.runtime.collections; import com.google.common.collect.ImmutableMap; import org.corfudb.annotations.Accessor; import org.corfudb.annotations.ConflictParameter; import org.corfudb.annotations.Mutator; import org.corfudb.annotations.MutatorAccessor; import java.util.Collection; import java.util.Map; import java.util.Set; /** * Created by mwei on 1/9/16. */ public interface ISMRMap<K, V> extends Map<K, V>, ISMRObject { /** * {@inheritDoc} * * Conflicts: this operation conflicts with any modification to * the map, since the size of the map could be potentially changed. */ @Accessor @Override int size(); /** * {@inheritDoc} * * Conflicts: this operation conflicts with any modification to * the map, since the size of the map could be potentially changed. */ @Accessor @Override boolean isEmpty(); /** * {@inheritDoc} * * Conflicts: this operation conflicts with any operation on the * given key. */ @Accessor @Override boolean containsKey(@ConflictParameter Object key); /** * {@inheritDoc} * * Conflicts: this operation conflicts with any modification to * the map, since the presence of values could be potentially changed. */ @Accessor @Override boolean containsValue(Object value); /** * {@inheritDoc} * * Conflicts: this operation conflicts with any operation on the * given key. */ @Accessor @Override V get(@ConflictParameter Object key); /** * {@inheritDoc} * * Conflicts: this operation produces a conflict with any other * operation on the given key. */ @MutatorAccessor(name = "put", undoFunction = "undoPut", undoRecordFunction = "undoPutRecord") @Override V put(@ConflictParameter K key, V value); /** * This operation behaves like a put operation, but does not * return the previous value, and does not result in a read * of the map. * * Calling this operation produces the same put record as calling * "put" directly. However, the runtime will not try to sync * the object to obtain an upcall. * * Conflicts: this operation produces a conflict with any other * operation on the given key. */ @Mutator(name = "put", noUpcall = true) default void blindPut(@ConflictParameter K key, V value) { put(key, value); } /** Generate an undo record for a put, given the previous state of the map * and the parameters to the put call. * * @param previousState The previous state of the map * @param key The key from the put call * @param value The value from the put call. This is not * needed to generate an undo record. * @return An undo record, which for a put is the * previous value in the map. */ default V undoPutRecord(ISMRMap<K,V> previousState, K key, V value) { return previousState.get(key); } /** Undo a put, given the current state of the map, an undo record * and the arguments to the put command to undo. * * @param map The state of the map after the put to undo * @param undoRecord The undo record generated by undoPutRecord * @param key The key of the put to undo * @param value The value of the put to undo, which is not * needed. */ default void undoPut(ISMRMap<K,V> map, V undoRecord, K key, V value) { if (undoRecord == null) { map.remove(key); } else { map.put(key, undoRecord); } } /** * {@jnheritDoc} * * Conflicts: this operation produces a conflict with any other * operation on the given key. */ @MutatorAccessor(name="remove", undoFunction = "undoRemove", undoRecordFunction = "undoRemoveRecord") @Override V remove(@ConflictParameter Object key); /** Generate an undo record for a remove, given the previous state of the map * and the parameters to the remove call. * * @param previousState The previous state of the map * @param key The key from the remove call * @return An undo record, which for a remove is the * previous value in the map. */ default V undoRemoveRecord(ISMRMap<K,V> previousState, K key) { return previousState.get(key); } /** Undo a remove, given the current state of the map, an undo record * and the arguments to the remove command to undo. * * @param map The state of the map after the put to undo * @param undoRecord The undo record generated by undoRemoveRecord */ default void undoRemove(ISMRMap<K,V> map, V undoRecord, K key) { if (undoRecord == null) { map.remove(key); } else { map.put(key, undoRecord); } } /** * {@inheritDoc} * * Conflicts: this operation conflicts on any keys that are in the map given. */ @Mutator(name="putAll", undoFunction="undoPutAll", undoRecordFunction="undoPutAllRecord", conflictParameterFunction="putAllConflictFunction") @Override void putAll(Map<? extends K, ? extends V> m); /** Generate the conflict parameters for putAll, given the arguments to the * putAll operation. * @param m The map for the putAll operation. * @return An array of conflict parameters, which are the * hash codes of the keys given. */ default Object[] putAllConflictFunction(Map<? extends K, ? extends V> m) { return m.keySet().stream() .map(Object::hashCode) .toArray(Object[]::new); } enum UndoNullable { NULL; } /** Generate an undo record for putAll, given the previous state of the map * and the parameters to the putAll call. * * @param previousState The previous state of the map * @param m The map from the putAll call * @return An undo record, which for a putAll is all the * previous entries in the map. */ default Map<K,V> undoPutAllRecord(ISMRMap<K,V> previousState, Map<? extends K, ? extends V> m) { ImmutableMap.Builder<K,V> builder = ImmutableMap.builder(); m.keySet().forEach(k -> builder.put(k, (previousState.get(k) == null ? (V) UndoNullable.NULL : previousState.get(k)))); return builder.build(); } /** Undo a remove, given the current state of the map, an undo record * and the arguments to the remove command to undo. * * @param map The state of the map after the put to undo * @param undoRecord The undo record generated by undoRemoveRecord */ default void undoPutAll(ISMRMap<K,V> map, Map<K,V> undoRecord, Map<? extends K, ? extends V> m) { undoRecord.entrySet().forEach(e -> { if (e.getValue() == UndoNullable.NULL) { map.remove(e.getKey()); } else { map.put(e.getKey(), e.getValue()); } }); } /** * {@inheritDoc} * * Conflicts: this operation conflicts with the entire map, since it drops * all mappings which are present. */ @Mutator(name="clear", reset=true) @Override void clear(); /** * {@inheritDoc} * * This function currently does not return a view like the java.util implementation, * and changes to the keySet will *not* be reflected in the map. * * Conflicts: This operation currently conflicts with any modification * to the map. */ @Accessor @Override Set<K> keySet(); /** * {@inheritDoc} * * This function currently does not return a view like the java.util implementation, * and changes to the values will *not* be reflected in the map. * * Conflicts: This operation currently conflicts with any modification * to the map. */ @Accessor @Override Collection<V> values(); /** * {@inheritDoc} * * This function currently does not return a view like the java.util implementation, * and changes to the entrySet will *not* be reflected in the map. * * Conflicts: This operation currently conflicts with any modification * to the map. */ @Accessor @Override Set<Entry<K, V>> entrySet(); }