private void putAllFromData(DataInput in,
      DeserializationContext context) throws IOException, ClassNotFoundException {
    int putAllSize = DataSerializer.readInteger(in);
    PutAllEntryData[] putAllEntries = new PutAllEntryData[putAllSize];
    if (putAllSize > 0) {
      final KnownVersion version = StaticSerialization.getVersionForDataStreamOrNull(in);
      final ByteArrayDataInput bytesIn = new ByteArrayDataInput();
      for (int i = 0; i < putAllSize; i++) {
        putAllEntries[i] = new PutAllEntryData(in, context, eventID, i);
      }

      boolean hasTags = in.readBoolean();
      if (hasTags) {
        EntryVersionsList versionTags = EntryVersionsList.create(in);
        for (int i = 0; i < putAllSize; i++) {
          putAllEntries[i].versionTag = versionTags.get(i);
        }
      }
    }
    op = Operation.PUTALL_CREATE;
    setOriginRemote(true);
    setGenerateCallbacks(true);

    putAllOp = new DistributedPutAllOperation(this, putAllSize, false /* [DISTTX] TODO */);
    putAllOp.setPutAllEntryData(putAllEntries);
  }
TODO DISTTX: callers of this constructor need to make sure that release is called. In general
the distributed tx code needs to be reviewed to see if it correctly handles off-heap.
geode-core/src/main/java/org/apache/geode/internal/cache/tx/DistTxEntryEvent.java