From 7ce582736db1965432f2add60bf112f1d986ebc3 Mon Sep 17 00:00:00 2001 From: f1v3-dev Date: Fri, 18 Sep 2026 11:52:28 +0900 Subject: [PATCH] INTERNAL: Move result decoding off the IO thread --- .../net/spy/memcached/v2/ArcusFutureImpl.java | 7 +- .../spy/memcached/v2/AsyncArcusCommands.java | 316 +++++++++++++----- 2 files changed, 234 insertions(+), 89 deletions(-) diff --git a/src/main/java/net/spy/memcached/v2/ArcusFutureImpl.java b/src/main/java/net/spy/memcached/v2/ArcusFutureImpl.java index f018bed38..14e24bc70 100644 --- a/src/main/java/net/spy/memcached/v2/ArcusFutureImpl.java +++ b/src/main/java/net/spy/memcached/v2/ArcusFutureImpl.java @@ -35,15 +35,16 @@ public class ArcusFutureImpl extends CompletableFuture implements ArcusFut /** * Use only when the result needs to be decoded. */ - public ArcusFutureImpl(ArcusResult arcusResult, Function decoder) { + @SuppressWarnings("unchecked") + public ArcusFutureImpl(ArcusResult arcusResult, Function decoder) { this.arcusResult = arcusResult; - this.decoder = decoder; + this.decoder = (Function) decoder; } /** * Use only when the result doesn't need to be decoded. */ - public ArcusFutureImpl(ArcusResult arcusResult) { + public ArcusFutureImpl(ArcusResult arcusResult) { this.arcusResult = arcusResult; this.decoder = null; } diff --git a/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java b/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java index d8a36423b..00b12a475 100644 --- a/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java +++ b/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java @@ -81,7 +81,6 @@ import net.spy.memcached.collection.SetExist; import net.spy.memcached.collection.SetGet; import net.spy.memcached.collection.SetInsert; -import net.spy.memcached.internal.result.GetsResultImpl; import net.spy.memcached.ops.APIType; import net.spy.memcached.ops.BTreeFindPositionOperation; import net.spy.memcached.ops.BTreeFindPositionWithGetOperation; @@ -389,8 +388,7 @@ public void complete() { @Override public ArcusFuture get(String key) { AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result, - r -> r == null ? null : tc.decode((CachedData) r)); + ArcusFutureImpl future = new ArcusFutureImpl<>(result, this::decodeValue); ArcusClient client = arcusClientSupplier.get(); GetOperation.Callback cb = new GetOperation.Callback() { @@ -430,18 +428,16 @@ public void complete() { @Override public ArcusFuture> gets(String key) { - AbstractArcusResult> result + AbstractArcusResult> result = new AbstractArcusResult<>(new AtomicReference<>()); - @SuppressWarnings("unchecked") - ArcusFutureImpl> future = new ArcusFutureImpl<>( - result, r -> r == null ? null : ((GetsResultImpl) r).getDecodedValue()); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result, this::decodeCASValue); ArcusClient client = arcusClientSupplier.get(); GetsOperation.Callback cb = new GetsOperation.Callback() { @Override public void gotData(String key, int flags, long cas, byte[] data) { CachedData cachedData = new CachedData(flags, data, tc.getMaxSize()); - result.set(new GetsResultImpl<>(cas, cachedData, tc)); + result.set(new CASValue<>(cas, cachedData)); } @Override @@ -514,16 +510,7 @@ private ArcusFuture> getPerNode(ArcusClient client, MemcachedNode List keyList) { AbstractArcusResult> result = new AbstractArcusResult<>((new AtomicReference<>(new HashMap<>()))); - @SuppressWarnings("unchecked") - ArcusFutureImpl> future = new ArcusFutureImpl<>(result, - r -> { - Map decodedMap = new HashMap<>(); - for (Map.Entry entry - : ((Map) r).entrySet()) { - decodedMap.put(entry.getKey(), tc.decode(entry.getValue())); - } - return decodedMap; - }); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result, this::decodeValueMap); GetOperation.Callback cb = new GetOperation.Callback() { @Override @@ -602,23 +589,18 @@ public ArcusFuture>> multiGets(List keys) { private ArcusFuture>> getsPerNode(ArcusClient client, MemcachedNode node, List keyList) { - AbstractArcusResult>> result + AbstractArcusResult>> result = new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); - @SuppressWarnings("unchecked") - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result, r -> { - Map> decodedMap = new HashMap<>(); - ((Map>) r).forEach((key, getsResult) -> - decodedMap.put(key, getsResult.getDecodedValue())); - return decodedMap; - }); + ArcusFutureImpl>> future = + new ArcusFutureImpl<>(result, this::decodeCASValueMap); GetsOperation.Callback cb = new GetsOperation.Callback() { @Override public void gotData(String key, int flags, long cas, byte[] data) { - Map> map = result.get(); + Map> map = result.get(); CachedData cachedData = new CachedData(flags, data, tc.getMaxSize()); - map.put(key, new GetsResultImpl<>(cas, cachedData, tc)); + map.put(key, new CASValue<>(cas, cachedData)); } @Override @@ -740,8 +722,8 @@ public ArcusFuture lopInsert(String key, int index, T value, @Override public ArcusFuture lopGet(String key, int index, GetMode mode) { - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result, this::decodeElement); ListGet get = new ListGet(index, mode.isWithDelete(), mode.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); @@ -773,8 +755,7 @@ public void complete() { @Override public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.set(tcForCollection.decode(cachedData)); + result.set(new CachedData(flags, data, tcForCollection.getMaxSize())); } }; Operation op = client.getOpFact().collectionGet(key, get, cb); @@ -786,9 +767,9 @@ public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { @Override public ArcusFuture> lopGet(String key, int from, int to, GetMode mode) { - AbstractArcusResult> result = + AbstractArcusResult> result = new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result, this::decodeElementList); ListGet get = new ListGet(from, to, mode.isWithDelete(), mode.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); @@ -820,8 +801,7 @@ public void complete() { @Override public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(tcForCollection.decode(cachedData)); + result.get().add(new CachedData(flags, data, tcForCollection.getMaxSize())); } }; Operation op = client.getOpFact().collectionGet(key, get, cb); @@ -868,17 +848,16 @@ public ArcusFuture sopInsert(String key, T value, CreateAttributes attr @Override public ArcusFuture> sopGet(String key, int count, GetMode mode) { - AbstractArcusResult> result + AbstractArcusResult> result = new AbstractArcusResult<>(new AtomicReference<>(new HashSet<>())); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result, this::decodeElementSet); SetGet get = new SetGet(count, mode.isWithDelete(), mode.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { @Override public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(tcForCollection.decode(cachedData)); + result.get().add(new CachedData(flags, data, tcForCollection.getMaxSize())); } @Override @@ -1019,8 +998,8 @@ public ArcusFuture> mopGet(String key, GetMode mode) { public ArcusFuture mopGet(String key, String mKey, GetMode mode) { keyValidator.validateMKey(mKey); - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result, this::decodeElement); List mKeys = Collections.singletonList(mKey); MapGet get = new MapGet(mKeys, mode.isWithDelete(), mode.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); @@ -1028,8 +1007,7 @@ public ArcusFuture mopGet(String key, String mKey, GetMode mode) { CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { @Override public void gotData(String mKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.set(tcForCollection.decode(cachedData)); + result.set(new CachedData(flags, data, tcForCollection.getMaxSize())); } @Override @@ -1074,17 +1052,16 @@ public ArcusFuture> mopGet(String key, List mKeys, GetMod keyValidator.validateMKey(mKeys); } - AbstractArcusResult> result = + AbstractArcusResult> result = new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result, this::decodeElementMap); MapGet get = new MapGet(mKeys, mode.isWithDelete(), mode.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { @Override public void gotData(String mKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().put(mKey, tcForCollection.decode(cachedData)); + result.get().put(mKey, new CachedData(flags, data, tcForCollection.getMaxSize())); } @Override @@ -1208,16 +1185,17 @@ public ArcusFuture>> bopUpsertAndGetTrimmed( private ArcusFutureImpl>> bopInsertOrUpsertAndGetTrimmed( String key, BTreeElement element, boolean isUpsert, CreateAttributes attributes) { - AbstractArcusResult>> result = + AbstractArcusResult>> result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl>> future = + new ArcusFutureImpl<>(result, this::decodeBTreeEntry); BTreeInsertAndGet insertAndGet = createBTreeInsertAndGet(element, isUpsert, attributes); CachedData co = tcForCollection.encode(insertAndGet.getValue()); insertAndGet.setFlags(co.getFlags()); ArcusClient client = arcusClientSupplier.get(); BTreeInsertAndGetOperation.Callback cb = new BTreeInsertAndGetOperation.Callback() { - private BTreeElement trimmedElement = null; + private BTreeElement trimmedElement = null; @Override public void receivedStatus(OperationStatus status) { @@ -1252,8 +1230,7 @@ public void complete() { @Override public void gotData(int flags, BKeyObject bKeyObject, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - trimmedElement = new BTreeElement<>( - BKey.of(bKeyObject), tcForCollection.decode(cachedData), eFlag); + trimmedElement = new BTreeElement<>(BKey.of(bKeyObject), cachedData, eFlag); } }; Operation op = client.getOpFact() @@ -1308,9 +1285,10 @@ public ArcusFuture bopDecr(String key, BKey bKey, int delta, long initial, @Override public ArcusFuture> bopGet(String key, BKey bKey, BopGetArgs args) { - AbstractArcusResult> result = + AbstractArcusResult> result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl> future = + new ArcusFutureImpl<>(result, this::decodeBTreeElement); BTreeGet get = createBTreeGet(bKey, args); ArcusClient client = arcusClientSupplier.get(); @@ -1341,7 +1319,7 @@ public void complete() { public void gotData(String bKey, int flags, byte[] data, byte[] eFlag) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.set(new BTreeElement<>(BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + result.set(new BTreeElement<>(BKey.of(bKey), cachedData, eFlag)); } }; Operation op = client.getOpFact().collectionGet(key, get, cb); @@ -1356,9 +1334,10 @@ public ArcusFuture> bopGet(String key, BKey from, BKey to, BopRangeGetArgs args) { verifyBKeyTypesMatch(from, to); - AbstractArcusResult> result = + AbstractArcusResult> result = new AbstractArcusResult<>(new AtomicReference<>(new BTreeGetResult<>(new ArrayList<>()))); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl> future = + new ArcusFutureImpl<>(result, this::decodeBTreeGetResult); BTreeGet get = createBTreeGet(from, to, args); ArcusClient client = arcusClientSupplier.get(); @@ -1392,8 +1371,7 @@ public void complete() { public void gotData(String bKey, int flags, byte[] data, byte[] eFlag) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().addElement(new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + result.get().addElement(new BTreeElement<>(BKey.of(bKey), cachedData, eFlag)); } }; Operation op = client.getOpFact().collectionGet(key, get, cb); @@ -1471,9 +1449,10 @@ public ArcusFuture>> bopMultiGet(List keys private ArcusFuture>> bopMultiGetPerNode(ArcusClient client, BTreeGetBulk getBulk) { - AbstractArcusResult>> result = + AbstractArcusResult>> result = new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl>> future = + new ArcusFutureImpl<>(result, this::decodeBTreeGetResultMap); BTreeGetBulkOperation.Callback cb = new BTreeGetBulkOperation.Callback() { @Override @@ -1506,7 +1485,7 @@ public void gotKey(String key, int elementCount, OperationStatus status) { result.get().put(key, new BTreeGetResult<>(new ArrayList<>())); break; case TRIMMED: - BTreeGetResult elements = new BTreeGetResult<>(new ArrayList<>()); + BTreeGetResult elements = new BTreeGetResult<>(new ArrayList<>()); elements.trimmed(); result.get().put(key, elements); break; @@ -1528,9 +1507,8 @@ public void gotKey(String key, int elementCount, OperationStatus status) { @Override public void gotElement(String key, int flags, Object bKey, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - BTreeGetResult elements = result.get().get(key); - elements.addElement(new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + BTreeGetResult elements = result.get().get(key); + elements.addElement(new BTreeElement<>(BKey.of(bKey), cachedData, eFlag)); } }; Operation op = client.getOpFact().bopGetBulk(getBulk, cb); @@ -1590,17 +1568,19 @@ public ArcusFuture> bopSortMergeGet(List keys, BKey private ArcusFuture> bopSortMergeGetPerNode(ArcusClient client, BTreeSMGet smGet) { - List> elementList = new ArrayList<>(); + List> elementList = new ArrayList<>(); List missedKeys = new ArrayList<>(); List trimmedKeys = new ArrayList<>(); - BTreeSMGetResult smGetElements = new BTreeSMGetResult<>( + BTreeSMGetResult smGetElements = new BTreeSMGetResult<>( elementList, missedKeys, trimmedKeys); - AtomicReference> atomicReference = new AtomicReference<>(smGetElements); - AbstractArcusResult> result = + AtomicReference> atomicReference = + new AtomicReference<>(smGetElements); + AbstractArcusResult> result = new AbstractArcusResult<>(atomicReference); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl> future = + new ArcusFutureImpl<>(result, this::decodeBTreeSMGetResult); BTreeSortMergeGetOperation.Callback cb = new BTreeSortMergeGetOperation.Callback() { @Override @@ -1632,8 +1612,8 @@ public void complete() { @Override public void gotData(String key, int flags, Object bKey, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - BTreeElement btreeElement = new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag); + BTreeElement btreeElement = + new BTreeElement<>(BKey.of(bKey), cachedData, eFlag); elementList.add(new BTreeSMGetResult.Element<>(key, btreeElement)); } @@ -1714,9 +1694,10 @@ public void complete() { @Override public ArcusFuture> bopGetByPosition(String key, int pos, BTreeOrder order) { - AbstractArcusResult> result - = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + AbstractArcusResult> result = + new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl> future = + new ArcusFutureImpl<>(result, this::decodeBTreeElement); BTreeGetByPosition getByPosition = new BTreeGetByPosition(order, pos); ArcusClient client = arcusClientSupplier.get(); @@ -1724,7 +1705,7 @@ public ArcusFuture> bopGetByPosition(String key, int pos, BTreeO @Override public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.set(new BTreeElement<>(BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + result.set(new BTreeElement<>(BKey.of(bKey), cachedData, eFlag)); } @Override @@ -1767,9 +1748,10 @@ public ArcusFuture>> bopGetByPosition(String key, throw new IllegalArgumentException("from should be less than or equal to to."); } - AbstractArcusResult>> result - = new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); + AbstractArcusResult>> result = + new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); + ArcusFutureImpl>> future = + new ArcusFutureImpl<>(result, this::decodeBTreeElementList); BTreeGetByPosition getByPosition = new BTreeGetByPosition(order, from, to); ArcusClient client = arcusClientSupplier.get(); @@ -1777,8 +1759,7 @@ public ArcusFuture>> bopGetByPosition(String key, @Override public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + result.get().add(new BTreeElement<>(BKey.of(bKey), cachedData, eFlag)); } @Override @@ -1818,9 +1799,10 @@ public ArcusFuture>> bopPositionWithGet(String key, BKey bKey, int count, BTreeOrder order) { - AbstractArcusResult>> result = + AbstractArcusResult>> result = new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); + ArcusFutureImpl>> future = + new ArcusFutureImpl<>(result, this::decodeBTreePositionElementList); BTreeFindPositionWithGet findPositionWithGet = new BTreeFindPositionWithGet(bKey.toBKeyObject(), order, count); ArcusClient client = arcusClientSupplier.get(); @@ -1830,8 +1812,7 @@ public ArcusFuture>> bopPositionWithGet(String key, @Override public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(new BTreePositionElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag, pos)); + result.get().add(new BTreePositionElement<>(BKey.of(bKey), cachedData, eFlag, pos)); } @Override @@ -2469,4 +2450,167 @@ public void complete() { return future; } + + private T decodeValue(CachedData cachedData) { + return cachedData == null ? null : tc.decode(cachedData); + } + + private Map decodeValueMap(Map rawMap) { + if (rawMap == null) { + return null; + } + + Map decoded = new HashMap<>(); + for (Map.Entry entry : rawMap.entrySet()) { + decoded.put(entry.getKey(), decodeValue(entry.getValue())); + } + return decoded; + } + + private CASValue decodeCASValue(CASValue rawValue) { + if (rawValue == null) { + return null; + } + + return new CASValue<>(rawValue.getCas(), tc.decode(rawValue.getValue())); + } + + private Map> decodeCASValueMap( + Map> rawMap) { + if (rawMap == null) { + return null; + } + + Map> decoded = new HashMap<>(); + for (Map.Entry> entry : rawMap.entrySet()) { + decoded.put(entry.getKey(), decodeCASValue(entry.getValue())); + } + return decoded; + } + + private T decodeElement(CachedData cachedData) { + return cachedData == null ? null : tcForCollection.decode(cachedData); + } + + private List decodeElementList(List rawList) { + if (rawList == null) { + return null; + } + + List decoded = new ArrayList<>(rawList.size()); + for (CachedData cachedData : rawList) { + decoded.add(decodeElement(cachedData)); + } + return decoded; + } + + private Set decodeElementSet(Set rawSet) { + if (rawSet == null) { + return null; + } + + Set decoded = new HashSet<>(); + for (CachedData cachedData : rawSet) { + decoded.add(decodeElement(cachedData)); + } + return decoded; + } + + private Map decodeElementMap(Map rawMap) { + if (rawMap == null) { + return null; + } + + Map decoded = new HashMap<>(); + for (Map.Entry entry : rawMap.entrySet()) { + decoded.put(entry.getKey(), decodeElement(entry.getValue())); + } + return decoded; + } + + private BTreeElement decodeBTreeElement(BTreeElement rawElement) { + if (rawElement == null) { + return null; + } + + return new BTreeElement<>(rawElement.getBKey(), + decodeElement(rawElement.getValue()), rawElement.getEFlag()); + } + + private List> decodeBTreeElementList(List> rawList) { + if (rawList == null) { + return null; + } + + List> decoded = new ArrayList<>(rawList.size()); + for (BTreeElement rawElement : rawList) { + decoded.add(decodeBTreeElement(rawElement)); + } + return decoded; + } + + private Map.Entry> decodeBTreeEntry( + Map.Entry> rawEntry) { + if (rawEntry == null) { + return null; + } + + return new AbstractMap.SimpleEntry<>( + rawEntry.getKey(), decodeBTreeElement(rawEntry.getValue())); + } + + private BTreeGetResult decodeBTreeGetResult(BTreeGetResult rawResult) { + if (rawResult == null) { + return null; + } + + BTreeGetResult decoded = new BTreeGetResult<>( + decodeBTreeElementList(rawResult.getElements())); + if (rawResult.isTrimmed()) { + decoded.trimmed(); + } + return decoded; + } + + private Map> decodeBTreeGetResultMap( + Map> rawMap) { + if (rawMap == null) { + return null; + } + + Map> decoded = new HashMap<>(); + for (Map.Entry> entry : rawMap.entrySet()) { + decoded.put(entry.getKey(), decodeBTreeGetResult(entry.getValue())); + } + return decoded; + } + + private BTreeSMGetResult decodeBTreeSMGetResult(BTreeSMGetResult rawResult) { + if (rawResult == null) { + return null; + } + + List> decodedElements = new ArrayList<>(); + for (BTreeSMGetResult.Element rawElement : rawResult.getElements()) { + decodedElements.add(new BTreeSMGetResult.Element<>( + rawElement.getKey(), decodeBTreeElement(rawElement.getbTreeElement()))); + } + + return new BTreeSMGetResult<>(decodedElements, + rawResult.getMissedKeys(), rawResult.getTrimmedKeys()); + } + + private List> decodeBTreePositionElementList( + List> rawList) { + if (rawList == null) { + return null; + } + + List> decoded = new ArrayList<>(rawList.size()); + for (BTreePositionElement rawElement : rawList) { + decoded.add(new BTreePositionElement<>(rawElement.getBKey(), + decodeElement(rawElement.getValue()), rawElement.getEFlag(), rawElement.getPosition())); + } + return decoded; + } }