Issue #1084
pull/1105/head
Nikita Koksharov 7 years ago committed by GitHub
commit a6d9a65549

@ -864,109 +864,149 @@ public class CommandAsyncService implements CommandAsyncExecutor {
}
private <R, V> void handleReference(RPromise<R> mainPromise, R res) {
if (res instanceof List) {
List<Object> r = (List<Object>) res;
try {
mainPromise.trySuccess(tryHandleReference(res));
} catch (Exception e) {
//fall back and let other part of the code handle the type conversion.
mainPromise.trySuccess(res);
}
}
private <T> T tryHandleReference(T o) {
boolean hasConversion = false;
if (o instanceof List) {
List<Object> r = (List<Object>) o;
for (int i = 0; i < r.size(); i++) {
if (r.get(i) instanceof RedissonReference) {
r.set(i, fromReference(r.get(i)));
} else if (r.get(i) instanceof ScoredEntry && ((ScoredEntry) r.get(i)).getValue() instanceof RedissonReference) {
ScoredEntry<?> se = ((ScoredEntry<?>) r.get(i));
se = new ScoredEntry(se.getScore(), fromReference(se.getValue()));
r.set(i, se);
Object ref = tryHandleReference0(r.get(i));
if (ref != r.get(i)) {
r.set(i, ref);
}
}
mainPromise.trySuccess(res);
} else if (res instanceof Set) {
Set r = (Set) res;
LinkedHashSet converted = new LinkedHashSet();
for (Object o : r) {
if (o instanceof RedissonReference) {
converted.add(fromReference(o));
} else if (o instanceof ScoredEntry && ((ScoredEntry) o).getValue() instanceof RedissonReference) {
ScoredEntry<?> se = ((ScoredEntry<?>) o);
se = new ScoredEntry(se.getScore(), fromReference(se.getValue()));
converted.add(se);
} else if (o instanceof Map.Entry) {
Map.Entry old = (Map.Entry) o;
Object key = old.getKey();
if (key instanceof RedissonReference) {
key = fromReference(key);
}
Object value = old.getValue();
if (value instanceof RedissonReference) {
value = fromReference(value);
}
converted.add(new AbstractMap.SimpleEntry(key, value));
return o;
} else if (o instanceof Set) {
Set set, r = (Set) o;
boolean useNewSet = o instanceof LinkedHashSet;
try {
set = (Set) o.getClass().getConstructor().newInstance();
} catch (Exception exception) {
set = new LinkedHashSet();
}
for (Object i : r) {
Object ref = tryHandleReference0(i);
//Not testing for ref changes because r.add(ref) below needs to
//fail on the first iteration to be able to perform fall back
//if failure happens.
//
//Assuming the failure reason is systematic such as put method
//is not supported or implemented, and not an occasional issue
//like only one element fails.
if (useNewSet) {
set.add(ref);
} else {
converted.add(o);
try {
r.add(ref);
set.add(i);
} catch (Exception e) {
//r is not supporting add operation, like
//LinkedHashMap$LinkedEntrySet and others.
//fall back to use a new set.
useNewSet = true;
set.add(ref);
}
}
hasConversion |= ref != i;
}
mainPromise.trySuccess((R) converted);
} else if (res instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) res;
LinkedHashMap<Object, Object> converted = new LinkedHashMap<Object, Object>();
for (Map.Entry<Object, Object> e : map.entrySet()) {
Object value = e.getValue();
if (e.getValue() instanceof RedissonReference) {
value = fromReference(e.getValue());
}
Object key = e.getKey();
if (e.getKey() instanceof RedissonReference) {
key = fromReference(e.getKey());
}
converted.put(key, value);
if (!hasConversion) {
return o;
} else if (useNewSet) {
return (T) set;
} else if (!set.isEmpty()) {
r.removeAll(set);
}
mainPromise.trySuccess((R) converted);
} else if (res instanceof ListScanResult) {
List<ScanObjectEntry> r = ((ListScanResult) res).getValues();
for (int i = 0; i < r.size(); i++) {
Object obj = r.get(i);
if (!(obj instanceof ScanObjectEntry)) {
break;
}
ScanObjectEntry e = r.get(i);
if (e.getObj() instanceof RedissonReference) {
r.set(i, new ScanObjectEntry(e.getBuf(), fromReference(e.getObj())));
} else if (e.getObj() instanceof ScoredEntry && ((ScoredEntry<?>) e.getObj()).getValue() instanceof RedissonReference) {
ScoredEntry<?> se = ((ScoredEntry<?>) e.getObj());
se = new ScoredEntry(se.getScore(), fromReference(se.getValue()));
r.set(i, new ScanObjectEntry(e.getBuf(), se));
return o;
} else if (o instanceof Map) {
Map<Object, Object> map, r = (Map<Object, Object>) o;
boolean useNewMap = o instanceof LinkedHashMap;
try {
map = (Map) o.getClass().getConstructor().newInstance();
} catch (Exception e) {
map = new LinkedHashMap();
}
for (Map.Entry<Object, Object> e : r.entrySet()) {
Map.Entry<Object, Object> ref = tryHandleReference0(e);
//Not testing for ref changes because r.put(ref.getKey(), ref.getValue())
//below needs to fail on the first iteration to be able to
//perform fall back if failure happens.
//
//Assuming the failure reason is systematic such as put method
//is not supported or implemented, and not an occasional issue
//like only one element fails.
if (useNewMap) {
map.put(ref.getKey(), ref.getValue());
} else {
try {
r.put(ref.getKey(), ref.getValue());
if (e.getKey() != ref.getKey()) {
map.put(e.getKey(), e.getValue());
}
} catch (Exception ex) {
//r is not supporting put operation. fall back to use
//a new map.
useNewMap = true;
map.put(ref.getKey(), ref.getValue());
}
}
hasConversion |= ref != e;
}
mainPromise.trySuccess(res);
} else if (res instanceof MapScanResult) {
MapScanResult scanResult = (MapScanResult) res;
Map<ScanObjectEntry, ScanObjectEntry> map = ((MapScanResult) res).getMap();
LinkedHashMap<ScanObjectEntry, ScanObjectEntry> converted = new LinkedHashMap<ScanObjectEntry, ScanObjectEntry>();
boolean hasConversion = false;
for (Map.Entry<ScanObjectEntry, ScanObjectEntry> e : map.entrySet()) {
ScanObjectEntry value = e.getValue();
if (e.getValue().getObj() instanceof RedissonReference) {
value = new ScanObjectEntry(e.getValue().getBuf(), fromReference(e.getValue().getObj()));
hasConversion = true;
}
ScanObjectEntry key = e.getKey();
if (e.getKey().getObj() instanceof RedissonReference) {
key = new ScanObjectEntry(e.getKey().getBuf(), fromReference(e.getKey().getObj()));
hasConversion = true;
}
converted.put(key, value);
if (!hasConversion) {
return o;
} else if (useNewMap) {
return (T) map;
} else if (!map.isEmpty()) {
r.keySet().removeAll(map.keySet());
}
if (hasConversion) {
MapScanResult<ScanObjectEntry, ScanObjectEntry> newScanResult = new MapScanResult<ScanObjectEntry, ScanObjectEntry>(scanResult.getPos(), converted);
return o;
} else if (o instanceof ListScanResult) {
tryHandleReference(((ListScanResult) o).getValues());
return o;
} else if (o instanceof MapScanResult) {
MapScanResult scanResult = (MapScanResult) o;
Map oldMap = ((MapScanResult) o).getMap();
Map map = tryHandleReference(oldMap);
if (map != oldMap) {
MapScanResult<ScanObjectEntry, ScanObjectEntry> newScanResult
= new MapScanResult<ScanObjectEntry, ScanObjectEntry>(scanResult.getPos(), map);
newScanResult.setRedisClient(scanResult.getRedisClient());
mainPromise.trySuccess((R) newScanResult);
return (T) newScanResult;
} else {
mainPromise.trySuccess((R) res);
}
} else if (res instanceof RedissonReference) {
try {
mainPromise.trySuccess(this.<R>fromReference(res));
} catch (Exception exception) {
mainPromise.trySuccess(res);//fallback
return o;
}
} else {
mainPromise.trySuccess(res);
return tryHandleReference0(o);
}
}
private <T> T tryHandleReference0(T o) {
if (o instanceof RedissonReference) {
return fromReference(o);
} else if (o instanceof ScoredEntry && ((ScoredEntry) o).getValue() instanceof RedissonReference) {
ScoredEntry<?> se = ((ScoredEntry<?>) o);
return (T) new ScoredEntry(se.getScore(), fromReference(se.getValue()));
} else if (o instanceof ScanObjectEntry) {
ScanObjectEntry keyScan = (ScanObjectEntry) o;
Object obj = tryHandleReference0(keyScan.getObj());
return obj != keyScan.getObj() ? (T) new ScanObjectEntry(keyScan.getBuf(), obj) : o;
} else if (o instanceof Map.Entry) {
Map.Entry old = (Map.Entry) o;
Object key = tryHandleReference0(old.getKey());
Object value = tryHandleReference0(old.getValue());
return value != old.getValue() || key != old.getKey()
? (T) new AbstractMap.SimpleEntry(key, value)
: o;
} else {
return o;
}
}

Loading…
Cancel
Save