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