void processChunkResponse(FetchBulkEntriesReplyMessage msg) {
      boolean doneProcessing = false;

      if (msg.getException() != null) {
        process(msg);
      } else {
        boolean deserializingKey = true;
        try {
          ByteArrayInputStream byteStream = new ByteArrayInputStream(msg.chunk);
          DataInputStream in = new DataInputStream(byteStream);
          Object key;
          int currentId;

          final boolean isDebugEnabled = logger.isTraceEnabled(LogMarker.DM_VERBOSE);
          while (in.available() > 0) {
            currentId = DataSerializer.readPrimitiveInt(in);
            if (currentId == -1) {
              break;
            }
            while (in.available() > 0) {
              deserializingKey = true;
              key = DataSerializer.readObject(in);
              if (key != null) {
                deserializingKey = false;
                Object value = DataSerializer.readObject(in);
                VersionTag versionTag = DataSerializer.readObject(in);

                if (versionTag != null) {
                  // Fix for 47260 - canonicalize the member ids to avoid an OOME
                  if (canonicalMembers.containsKey(versionTag.getMemberID())) {
                    versionTag.setMemberID(canonicalMembers.get(versionTag.getMemberID()));
                  } else {
                    canonicalMembers.put(versionTag.getMemberID(), versionTag.getMemberID());
                  }
                }

                synchronized (returnValue) {
                  HashMap<Object, Object> valueMap = returnValue.get(currentId);
                  HashMap<Object, VersionTag> versionMap = returnVersions.get(currentId);
                  if (valueMap != null) {
                    valueMap.put(key, value);
                  } else {
                    valueMap = new HashMap<>();
                    valueMap.put(key, value);
                    returnValue.put(currentId, valueMap);
                  }
                  if (versionMap != null) {
                    versionMap.put(key, versionTag);
                  } else {
                    versionMap = new HashMap<>();
                    versionMap.put(key, versionTag);
                    returnVersions.put(currentId, versionMap);
                  }
                }
              } else {
                // null should signal the end of the set of keys
                boolean bucketHasMore = DataSerializer.readPrimitiveBoolean(in);
                synchronized (returnValue) {
                  if (!bucketHasMore) {
                    receivedBuckets.add(currentId);
                  }
                }
                break;
              }
            } // inner while
          } // outer while

          synchronized (endLock) {
            chunksProcessed = chunksProcessed + 1;

            if (msg.lastInSeries) {
              expectedChunks = msg.msgNum;
              failedBucketIds = msg.failedBucketIds;
            }
            if (expectedChunks == chunksProcessed) {
              doneProcessing = true;
              lastChunkReceived = true;
            }

            if (isDebugEnabled) {
              logger.trace(LogMarker.DM_VERBOSE,
                  "{} chunksProcessed={}, lastChunkReceived={},done={}", this, chunksProcessed,
                  lastChunkReceived, doneProcessing);
            }
          }
        } catch (Exception e) {
          if (deserializingKey) {
            processException(new ReplyException(
                "Error deserializing keys",
                e));
          } else {
            processException(new ReplyException(
                "Error deserializing values",
                e)); // for bug 41202
          }
          checkIfDone(); // fix for hang in 41202
        }

        // if all chunks have been received, wake up the waiting thread
        if (doneProcessing) {
          process(msg);
        }
      } // else msg.getException() == null
    }
whether the last chunk has been processed
geode-core/src/main/java/org/apache/geode/internal/cache/partitioned/FetchBulkEntriesMessage.java