Я хотел бы обсудить реализации карты, отображающей несколько ключей, сопоставленных с одним и тем же значением в распределенной среде.
Один из способов реализации этого (который мне не нравится) (в Java ):
class ConcurrentMultiKeyMap<K1, K2, V> {
HashMap<K1, K2> map1to2 = new HashMap<>();
HashMap<K2, K1> map2to1 = new HashMap<>();
HashMap<K1, V> mapToV = new HashMap<>();
public synchronized V put(K1 k1, K2 k2, V v) {
K2 previousK2 = map1to2.get(k1);
K1 previousK1 = map2to1.get(k2);
mapToV.remove(previousK1);
map1to2.remove(previousK1);
map2to1.remove(previousK2);
map1to2.put(k1, k2);
map2to1.put(k2, k1);
return mapToV.put(k1, v);
}
synchronized void remove(K1 k1) {
K2 k2 = map1to2.remove(k1);
map2to1.remove(k2);
mapToV.remove(k1);
}
synchronized void remove(K2 k2) {
K1 k1 = map2to1.remove(k2);
map1to2.remove(k1);
mapToV.remove(k1);
}
synchronized V get(K1 k1) {
return mapToV.get(k1);
}
synchronized V getBy2(K2 k2) {
K1 k1 = map2to1.get(k2);
if(k1 != null)
return getBy1(k1);
else
return null;
}
public synchronized boolean containsBy1(K1 k1) {
return map1to2.containsKey(k1);
}
public synchronized boolean containsBy2(K2 k2) {
return map2to1.containsKey(k2);
}
public synchronized V[] values(V[] empty_va) {
return mapToV.values().toArray(empty_va);
}
public synchronized int size() {
return mapToV.size();
}
public synchronized boolean isEmpty() {
return mapToV.isEmpty();
}
public synchronized void clear() {
mapToV.clear();
map1to2.clear();
map2to1.clear();
}
@Override public synchronized String toString() {
StringBuilder builder = new StringBuilder();
builder.append("BadConcurrentMultiKeyMap{");
for(Map.Entry<K1, V> entry : mapToV.entrySet()) {
builder.append("(");
K1 k1 = entry.getKey();
K2 k2 = map1to2.get(k1);
V v = entry.getValue();
builder.append("k1=").append(k1).append(",");
builder.append("k2=").append(k2).append(",");
builder.append("v=").append(v);
builder.append("), ");
}
if(!isEmpty()) builder.delete(builder.length()-2, builder.length());
builder.append("}");
return builder.toString();
}
@Test public void demonstration() {
ConcurrentMultiKeyMap<Integer, String, String> map = new ConcurrentMultiKeyMap<>();
map.put(1, "1", "v1");
map.put(2, "2", "v2");
assertEquals("v1", map.getBy1(1));
assertEquals("v1", map.getBy2("1"));
assertEquals("v2", map.getBy1(2));
assertEquals("v2", map.getBy2("2"));
assertNull(map.getBy1(3));
assertNull(map.getBy2("3"));
map.removeBy1(1);
assertNull(map.getBy1(1));
assertNull(map.getBy2("1"));
map.removeBy2("2");
assertNull(map.getBy1(2));
assertNull(map.getBy2("2"));
map.put(1, "A", "v1");
System.out.println("map = " + map);
map.put(2, "A", "v2");
System.out.println("map = " + map);
map.removeBy1(1);
System.out.println("map = " + map);
System.out.println("map.mapToV = " + map.mapToV);
System.out.println("map.map1to2 = " + map.map1to2);
System.out.println("map.map2to1 = " + map.map2to1);
map.clear();
map.put(1, "A", "v1");
System.out.println("map = " + map);
map.put(2, "A", "v2");
System.out.println("map = " + map);
map.removeBy2("A");
System.out.println("map = " + map);
System.out.println("map.mapToV = " + map.mapToV);
System.out.println("map.map1to2 = " + map.map1to2);
System.out.println("map.map2to1 = " + map.map2to1);
}
}
Кто-нибудь знает решение лучше ? Бонусные баллы, если он будет работать с переменным количеством ключей и использовать схему интеллектуальной блокировки.
ПРИМЕЧАНИЕ: Требуется решение, позволяющее получить доступ к любому ключу отдельно. Поэтому традиционный CompositeKey не работает, так как код ha sh не может быть рассчитан только с помощью одной из клавиш.
Заранее спасибо