This is an automated email from the ASF dual-hosted git repository.

leerho pushed a commit to branch main21
in repository https://gitbox.apache.org/repos/asf/datasketches-java.git


The following commit(s) were added to refs/heads/main21 by this push:
     new 82b155fa This is the first crack at updating ds-java to Java 21.
82b155fa is described below

commit 82b155fa907e786889a7697fea22512053c33214
Author: Lee Rhodes <[email protected]>
AuthorDate: Mon Feb 17 22:30:29 2025 -0800

    This is the first crack at updating ds-java to Java 21.
    
    Lots of changes.
---
 .../datasketches/hash/MurmurHash3Adaptor.java      | 479 ---------------------
 .../apache/datasketches/hash/MurmurHash3FFM21.java | 386 +++++++++++++++++
 .../apache/datasketches/hll/DirectAuxHashMap.java  |   2 +-
 .../apache/datasketches/kll/KllDoublesHelper.java  |   7 +-
 .../apache/datasketches/kll/KllDoublesSketch.java  |   2 +-
 .../apache/datasketches/kll/KllFloatsHelper.java   |   7 +-
 .../apache/datasketches/kll/KllFloatsSketch.java   |   2 +-
 .../org/apache/datasketches/kll/KllHelper.java     |  14 +-
 .../apache/datasketches/kll/KllLongsHelper.java    |   7 +-
 .../apache/datasketches/kll/KllLongsSketch.java    |   2 +-
 .../quantiles/DirectUpdateDoublesSketch.java       |   3 +-
 .../quantiles/DirectUpdateDoublesSketchR.java      |   2 +-
 .../datasketches/quantiles/DoublesSketch.java      |   4 +-
 .../theta/ConcurrentDirectQuickSelectSketch.java   |   4 +-
 .../theta/ConcurrentHeapQuickSelectSketch.java     |   4 +-
 .../theta/DirectQuickSelectSketch.java             |   4 +-
 .../filters/bloomfilter/BloomFilterTest.java       |  26 +-
 .../datasketches/hash/MurmurHash3AdaptorTest.java  | 377 ----------------
 ...rHash3v4Test.java => MurmurHash3FFM21Test.java} |  69 ++-
 .../datasketches/hash/MurmurHash3FFM21bTest.java   | 419 ++++++++++++++++++
 .../datasketches/hll/DirectAuxHashMapTest.java     |  11 +-
 .../datasketches/hll/DirectCouponListTest.java     |   8 +-
 .../datasketches/kll/KllItemsSketchTest.java       |  13 +-
 .../datasketches/quantiles/DebugUnionTest.java     |   7 +-
 .../DirectQuantilesMemoryRequestTest.java          |  32 +-
 .../datasketches/quantiles/DoublesSketchTest.java  |  12 +-
 .../datasketches/quantiles/PreambleUtilTest.java   |  11 +-
 .../datasketches/theta/CompactSketchTest.java      |   6 +-
 .../theta/DirectQuickSelectSketchTest.java         | 104 +++--
 .../theta/HeapifyWrapSerVer1and2Test.java          | 106 ++---
 .../datasketches/theta/SetOperationTest.java       |  10 +-
 .../apache/datasketches/theta/UnionImplTest.java   |  19 +-
 32 files changed, 1068 insertions(+), 1091 deletions(-)

diff --git a/src/main/java/org/apache/datasketches/hash/MurmurHash3Adaptor.java 
b/src/main/java/org/apache/datasketches/hash/MurmurHash3Adaptor.java
deleted file mode 100644
index feecdba9..00000000
--- a/src/main/java/org/apache/datasketches/hash/MurmurHash3Adaptor.java
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.hash;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.datasketches.common.Util.ceilingPowerOf2;
-import static org.apache.datasketches.hash.MurmurHash3.hash;
-
-import java.nio.ByteBuffer;
-
-import org.apache.datasketches.common.SketchesArgumentException;
-import org.apache.datasketches.common.SketchesStateException;
-
-/**
- * A general purpose wrapper for the MurmurHash3.
- * <ul>
- * <li>Inputs can be long, long[], int[], char[], byte[], double or 
String.</li>
- * <li>Returns null if arrays or String is null or empty.</li>
- * <li>Provides methods for returning the 128-bit result as either an array of 
2 longs or as a byte
- * array of 16 bytes.</li>
- * <li>Provides modulo, asDouble and asInt functions.</li>
- * </ul>
- *
- * @author Lee Rhodes
- */
-public final class MurmurHash3Adaptor {
-  private static final long BIT62 = 1L << 62;
-  private static final long MAX_LONG = Long.MAX_VALUE;
-  private static final long INT_MASK = 0x7FFFFFFFL;
-  private static final long PRIME = 9219741426499971445L; //from P. L'Ecuyer 
and R. Simard
-
-  private MurmurHash3Adaptor() {}
-
-  /**
-   * Hash a long and long seed.
-   *
-   * @param datum the input long value
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a byte[16] in Big Endian order from 2 64-bit 
longs.
-   */
-  public static byte[] hashToBytes(final long datum, final long seed) {
-    final long[] data = { datum };
-    return toByteArray(hash(data, seed));
-  }
-
-  /**
-   * Hash a long[] and long seed.
-   *
-   * @param data the input long array
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a byte[16] in Big Endian order from 2 64-bit 
longs.
-   */
-  public static byte[] hashToBytes(final long[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return toByteArray(hash(data, seed));
-  }
-
-  /**
-   * Hash an int[] and long seed.
-   *
-   * @param data the input int array
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a byte[16] in Big Endian order from 2 64-bit 
longs.
-   */
-  public static byte[] hashToBytes(final int[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return toByteArray(hash(data, seed));
-  }
-
-  /**
-   * Hash a char[] and long seed.
-   *
-   * @param data the input char array
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a byte[16] in Big Endian order from 2 64-bit 
longs.
-   */
-  public static byte[] hashToBytes(final char[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return toByteArray(hash(data, seed));
-  }
-
-  /**
-   * Hash a byte[] and long seed.
-   *
-   * @param data the input byte array
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a byte[16] in Big Endian order from 2 64-bit 
longs.
-   */
-  public static byte[] hashToBytes(final byte[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return toByteArray(hash(data, seed));
-  }
-
-  /**
-   * Hash a double and long seed.
-   *
-   * @param datum the input double
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a byte[16] in Big Endian order from 2 64-bit 
longs.
-   */
-  public static byte[] hashToBytes(final double datum, final long seed) {
-    final double d = (datum == 0.0) ? 0.0 : datum; //canonicalize -0.0, 0.0
-    final long[] data = { Double.doubleToLongBits(d) }; //canonicalize all NaN 
forms
-    return toByteArray(hash(data, seed));
-  }
-
-  /**
-   * Hash a String and long seed.
-   *
-   * @param datum the input String
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a byte[16] in Big Endian order from 2 64-bit 
longs.
-   */
-  public static byte[] hashToBytes(final String datum, final long seed) {
-    if ((datum == null) || datum.isEmpty()) {
-      return null;
-    }
-    final byte[] data = datum.getBytes(UTF_8);
-    return toByteArray(hash(data, seed));
-  }
-
-  /**
-   * Hash a long and long seed.
-   *
-   * @param datum the input long
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a long[2].
-   */
-  public static long[] hashToLongs(final long datum, final long seed) {
-    final long[] data = { datum };
-    return hash(data, seed);
-  }
-
-  /**
-   * Hash a long[] and long seed.
-   *
-   * @param data the input long array.
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a long[2].
-   */
-  public static long[] hashToLongs(final long[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return hash(data, seed);
-  }
-
-  /**
-   * Hash a int[] and long seed.
-   *
-   * @param data the input int array.
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a long[2].
-   */
-  public static long[] hashToLongs(final int[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return hash(data, seed);
-  }
-
-  /**
-   * Hash a char[] and long seed.
-   *
-   * @param data the input char array.
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a long[2].
-   */
-  public static long[] hashToLongs(final char[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return hash(data, seed);
-  }
-
-  /**
-   * Hash a byte[] and long seed.
-   *
-   * @param data the input byte array.
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a long[2].
-   */
-  public static long[] hashToLongs(final byte[] data, final long seed) {
-    if ((data == null) || (data.length == 0)) {
-      return null;
-    }
-    return hash(data, seed);
-  }
-
-  /**
-   * Hash a double and long seed.
-   *
-   * @param datum the input double.
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a long[2].
-   */
-  public static long[] hashToLongs(final double datum, final long seed) {
-    final double d = (datum == 0.0) ? 0.0 : datum; //canonicalize -0.0, 0.0
-    final long[] data = { Double.doubleToLongBits(d) };//canonicalize all NaN 
forms
-    return hash(data, seed);
-  }
-
-  /**
-   * Hash a String and long seed.
-   *
-   * @param datum the input String.
-   * @param seed A long valued seed.
-   * @return The 128-bit hash as a long[2].
-   */
-  public static long[] hashToLongs(final String datum, final long seed) {
-    if ((datum == null) || datum.isEmpty()) {
-      return null;
-    }
-    final byte[] data = datum.getBytes(UTF_8);
-    return hash(data, seed);
-  }
-
-  //As Integer functions
-
-  /**
-   * Returns a deterministic uniform random integer between zero (inclusive) 
and
-   * n (exclusive) given the input data.
-   * @param data the input long array.
-   * @param n The upper exclusive bound of the integers produced. Must be &gt; 
1.
-   * @return deterministic uniform random integer
-   */
-  public static int asInt(final long[] data, final int n) {
-    if ((data == null) || (data.length == 0)) {
-      throw new SketchesArgumentException("Input is null or empty.");
-    }
-    return asInteger(data, n); //data is long[]
-  }
-
-  /**
-   * Returns a deterministic uniform random integer between zero (inclusive) 
and
-   * n (exclusive) given the input data.
-   * @param data the input int array.
-   * @param n The upper exclusive bound of the integers produced. Must be &gt; 
1.
-   * @return deterministic uniform random integer
-   */
-  public static int asInt(final int[] data, final int n) {
-    if ((data == null) || (data.length == 0)) {
-      throw new SketchesArgumentException("Input is null or empty.");
-    }
-    return asInteger(toLongArray(data), n); //data is int[]
-  }
-
-  /**
-   * Returns a deterministic uniform random integer between zero (inclusive) 
and
-   * n (exclusive) given the input data.
-   * @param data the input byte array.
-   * @param n The upper exclusive bound of the integers produced. Must be &gt; 
1.
-   * @return deterministic uniform random integer.
-   */
-  public static int asInt(final byte[] data, final int n) {
-    if ((data == null) || (data.length == 0)) {
-      throw new SketchesArgumentException("Input is null or empty.");
-    }
-    return asInteger(toLongArray(data), n); //data is byte[]
-  }
-
-  /**
-   * Returns a deterministic uniform random integer between zero (inclusive) 
and
-   * n (exclusive) given the input datum.
-   * @param datum the input long
-   * @param n The upper exclusive bound of the integers produced. Must be &gt; 
1.
-   * @return deterministic uniform random integer
-   */
-  public static int asInt(final long datum, final int n) {
-    final long[] data = { datum };
-    return asInteger(data, n); //data is long[]
-  }
-
-  /**
-   * Returns a deterministic uniform random integer between zero (inclusive) 
and
-   * n (exclusive) given the input double.
-   * @param datum the given double.
-   * @param n The upper exclusive bound of the integers produced. Must be &gt; 
1.
-   * @return deterministic uniform random integer
-   */
-  public static int asInt(final double datum, final int n) {
-    final double d = (datum == 0.0) ? 0.0 : datum; //canonicalize -0.0, 0.0
-    final long[] data = { Double.doubleToLongBits(d) };//canonicalize all NaN 
forms
-    return asInteger(data, n); //data is long[]
-  }
-
-  /**
-   * Returns a deterministic uniform random integer between zero (inclusive) 
and
-   * n (exclusive) given the input datum.
-   * @param datum the given String.
-   * @param n The upper exclusive bound of the integers produced. Must be &gt; 
1.
-   * @return deterministic uniform random integer
-   */
-  public static int asInt(final String datum, final int n) {
-    if ((datum == null) || datum.isEmpty()) {
-      throw new SketchesArgumentException("Input is null or empty.");
-    }
-    final byte[] data = datum.getBytes(UTF_8);
-    return asInteger(toLongArray(data), n); //data is byte[]
-  }
-
-  /**
-   * Returns a deterministic uniform random integer with a minimum inclusive 
value of zero and a
-   * maximum exclusive value of n given the input data.
-   *
-   * <p>The integer values produced are only as random as the MurmurHash3 
algorithm, which may be
-   * adequate for many applications. However, if you are looking for high 
guarantees of randomness
-   * you should turn to more sophisticated random generators such as Mersenne 
Twister or Well19937c
-   * algorithms.
-   *
-   * @param data The input data (key)
-   * @param n The upper exclusive bound of the integers produced. Must be &gt; 
1.
-   * @return deterministic uniform random integer
-   */
-  private static int asInteger(final long[] data, final int n) {
-    int t;
-    int cnt = 0;
-    long seed = 0;
-    if (n < 2) {
-      throw new SketchesArgumentException("Given value of n must be &gt; 1.");
-    }
-    if (n > (1 << 30)) {
-      while (++cnt < 10000) {
-        final long[] h = MurmurHash3.hash(data, seed);
-        t = (int) (h[0] & INT_MASK);
-        if (t < n) {
-          return t;
-        }
-        t = (int) ((h[0] >>> 33));
-        if (t < n) {
-          return t;
-        }
-        t = (int) (h[1] & INT_MASK);
-        if (t < n) {
-          return t;
-        }
-        t = (int) ((h[1] >>> 33));
-        if (t < n) {
-          return t;
-        }
-        seed += PRIME;
-      } // end while
-      throw new SketchesStateException(
-          "Internal Error: Failed to find integer &lt; n within 10000 
iterations.");
-    }
-    final long mask = ceilingPowerOf2(n) - 1;
-    while (++cnt < 10000) {
-      final long[] h = MurmurHash3.hash(data, seed);
-      t = (int) (h[0] & mask);
-      if (t < n) {
-        return t;
-      }
-      t = (int) ((h[0] >>> 33) & mask);
-      if (t < n) {
-        return t;
-      }
-      t = (int) (h[1] & mask);
-      if (t < n) {
-        return t;
-      }
-      t = (int) ((h[1] >>> 33) & mask);
-      if (t < n) {
-        return t;
-      }
-      seed += PRIME;
-    } // end while
-    throw new SketchesStateException(
-        "Internal Error: Failed to find integer &lt; n within 10000 
iterations.");
-  }
-
-  /**
-   * Returns a uniform random double with a minimum inclusive value of zero 
and a maximum exclusive
-   * value of 1.0.
-   *
-   * <p>The double values produced are only as random as the MurmurHash3 
algorithm, which may be
-   * adequate for many applications. However, if you are looking for high 
guarantees of randomness
-   * you should turn to more sophisticated random generators such as Mersenne 
Twister or Well
-   * algorithms.
-   *
-   * @param hash The output of the MurmurHash3.
-   * @return the uniform random double.
-   */
-  public static double asDouble(final long[] hash) {
-    return (hash[0] >>> 12) * 0x1.0p-52d;
-  }
-
-  /**
-   * Returns the remainder from the modulo division of the 128-bit output of 
the murmurHash3 by the
-   * divisor.
-   *
-   * @param h0 The lower 64-bits of the 128-bit MurmurHash3 hash.
-   * @param h1 The upper 64-bits of the 128-bit MurmurHash3 hash.
-   * @param divisor Must be positive and greater than zero.
-   * @return the modulo result.
-   */
-  public static int modulo(final long h0, final long h1, final int divisor) {
-    final long d = divisor;
-    final long modH0 = (h0 < 0L) ? addRule(mulRule(BIT62, 2L, d), (h0 & 
MAX_LONG), d) : h0 % d;
-    final long modH1 = (h1 < 0L) ? addRule(mulRule(BIT62, 2L, d), (h1 & 
MAX_LONG), d) : h1 % d;
-    final long modTop = mulRule(mulRule(BIT62, 4L, d), modH1, d);
-    return (int) addRule(modTop, modH0, d);
-  }
-
-  /**
-   * Returns the remainder from the modulo division of the 128-bit output of 
the murmurHash3 by the
-   * divisor.
-   *
-   * @param hash The size 2 long array from the MurmurHash3.
-   * @param divisor Must be positive and greater than zero.
-   * @return the modulo result
-   */
-  public static int modulo(final long[] hash, final int divisor) {
-    return modulo(hash[0], hash[1], divisor);
-  }
-
-  private static long addRule(final long a, final long b, final long d) {
-    return ((a % d) + (b % d)) % d;
-  }
-
-  private static long mulRule(final long a, final long b, final long d) {
-    return ((a % d) * (b % d)) % d;
-  }
-
-  private static byte[] toByteArray(final long[] hash) { //Assumes Big Endian
-    final byte[] bArr = new byte[16];
-    final ByteBuffer bb = ByteBuffer.wrap(bArr);
-    bb.putLong(hash[0]);
-    bb.putLong(hash[1]);
-    return bArr;
-  }
-
-  private static long[] toLongArray(final byte[] data) {
-    final int dataLen = data.length;
-    final int longLen = (dataLen + 7) / 8;
-    final long[] longArr = new long[longLen];
-    for (int bi = 0; bi < dataLen; bi++) {
-      final int li = bi / 8;
-      longArr[li] |= (((long)data[bi]) << ((bi * 8) % 64));
-    }
-    return longArr;
-  }
-
-  private static long[] toLongArray(final int[] data) {
-    final int dataLen = data.length;
-    final int longLen = (dataLen + 1) / 2;
-    final long[] longArr = new long[longLen];
-    for (int ii = 0; ii < dataLen; ii++) {
-      final int li = ii / 2;
-      longArr[li] |= (((long)data[ii]) << ((ii * 32) % 64));
-    }
-    return longArr;
-  }
-
-}
diff --git a/src/main/java/org/apache/datasketches/hash/MurmurHash3FFM21.java 
b/src/main/java/org/apache/datasketches/hash/MurmurHash3FFM21.java
new file mode 100644
index 00000000..a94fd3fd
--- /dev/null
+++ b/src/main/java/org/apache/datasketches/hash/MurmurHash3FFM21.java
@@ -0,0 +1,386 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.hash;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.ValueLayout;
+import java.util.Objects;
+
+import org.apache.datasketches.memory.Memory;
+
+/**
+ * The MurmurHash3 is a fast, non-cryptographic, 128-bit hash function that has
+ * excellent avalanche and 2-way bit independence properties.
+ *
+ * <p>Austin Appleby's C++
+ * <a 
href="https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp";>
+ * MurmurHash3_x64_128(...), final revision 150</a>,
+ * which is in the Public Domain, was the inspiration for this implementation 
in Java.</p>
+ *
+ * <p>This implementation of the MurmurHash3 allows hashing of a block of 
on-heap Memory defined by an offset
+ * and length. The calling API also allows the user to supply the small output 
array of two longs,
+ * so that the entire hash function is static and free of object 
allocations.</p>
+ *
+ * <p>This implementation produces exactly the same hash result as the
+ * MurmurHash3 function in datasketches-java given compatible inputs.</p>
+ *
+ * <p>This FFM21 version of the implementation leverages the java.lang.foreign 
package (FFM) of JDK-21 in place of
+ * the Unsafe class.
+ *
+ * @author Lee Rhodes
+ */
+public final class MurmurHash3FFM21 {
+  private static final long C1 = 0x87c37b91114253d5L;
+  private static final long C2 = 0x4cf5ad432745937fL;
+
+  /**
+   * Returns a 128-bit hash of the input.
+   * Provided for compatibility with older version of MurmurHash3,
+   * but empty or null input now throws IllegalArgumentException.
+   * @param in long array
+   * @param seed A long valued seed.
+   * @return the hash
+   * @throws IllegalArgumentException if input is empty or null
+   */
+  public static long[] hash(final long[] in, final long seed) {
+    if ((in == null) || (in.length == 0)) {
+      throw new IllegalArgumentException("Input in is empty or null.");
+    }
+    return hash(MemorySegment.ofArray(in), 0L, in.length << 3, seed, new 
long[2]);
+  }
+
+  /**
+   * Returns a 128-bit hash of the input.
+   * Provided for compatibility with older version of MurmurHash3,
+   * but empty or null input now throws IllegalArgumentException.
+   * @param in int array
+   * @param seed A long valued seed.
+   * @return the hash
+   * @throws IllegalArgumentException if input is empty or null
+   */
+  public static long[] hash(final int[] in, final long seed) {
+    if ((in == null) || (in.length == 0)) {
+      throw new IllegalArgumentException("Input in is empty or null.");
+    }
+    return hash(MemorySegment.ofArray(in), 0L, in.length << 2, seed, new 
long[2]);
+  }
+
+  /**
+   * Returns a 128-bit hash of the input.
+   * Provided for compatibility with older version of MurmurHash3,
+   * but empty or null input now throws IllegalArgumentException.
+   * @param in char array
+   * @param seed A long valued seed.
+   * @return the hash
+   * @throws IllegalArgumentException if input is empty or null
+   */
+  public static long[] hash(final char[] in, final long seed) {
+    if ((in == null) || (in.length == 0)) {
+      throw new IllegalArgumentException("Input in is empty or null.");
+    }
+    return hash(MemorySegment.ofArray(in), 0L, in.length << 1, seed, new 
long[2]);
+  }
+
+  /**
+   * Returns a 128-bit hash of the input.
+   * Provided for compatibility with older version of MurmurHash3,
+   * but empty or null input now throws IllegalArgumentException.
+   * @param in byte array
+   * @param seed A long valued seed.
+   * @return the hash
+   * @throws IllegalArgumentException if input is empty or null
+   */
+  public static long[] hash(final byte[] in, final long seed) {
+    if ((in == null) || (in.length == 0)) {
+      throw new IllegalArgumentException("Input in is empty or null.");
+    }
+    return hash(MemorySegment.ofArray(in), 0L, in.length, seed, new long[2]);
+  }
+
+  //Single primitive inputs
+
+  /**
+   * Returns a 128-bit hash of the input.
+   * Note the entropy of the resulting hash cannot be more than 64 bits.
+   * @param in a long
+   * @param seed A long valued seed.
+   * @param hashOut A long array of size 2
+   * @return the hash
+   */
+  public static long[] hash(final long in, final long seed, final long[] 
hashOut) {
+    final long h1 = seed ^ mixK1(in);
+    final long h2 = seed;
+    return finalMix128(h1, h2, 8, hashOut);
+  }
+
+  /**
+   * Returns a 128-bit hash of the input.
+   * Note the entropy of the resulting hash cannot be more than 64 bits.
+   * @param in a double
+   * @param seed A long valued seed.
+   * @param hashOut A long array of size 2
+   * @return the hash
+   */
+  public static long[] hash(final double in, final long seed, final long[] 
hashOut) {
+    final double d = (in == 0.0) ? 0.0 : in;    // canonicalize -0.0, 0.0
+    final long k1 = Double.doubleToLongBits(d); // canonicalize all NaN forms
+    final long h1 = seed ^ mixK1(k1);
+    final long h2 = seed;
+    return finalMix128(h1, h2, 8, hashOut);
+  }
+
+  /**
+   * Returns a 128-bit hash of the input.
+   * An empty or null input throws IllegalArgumentException.
+   * @param in a String
+   * @param seed A long valued seed.
+   * @param hashOut A long array of size 2
+   * @return the hash
+   * @throws IllegalArgumentException if input is empty or null
+   */
+  public static long[] hash(final String in, final long seed, final long[] 
hashOut) {
+    if ((in == null) || (in.length() == 0)) {
+      throw new IllegalArgumentException("Input in is empty or null.");
+    }
+    final byte[] byteArr = in.getBytes(UTF_8);
+    return hash(MemorySegment.ofArray(byteArr), 0L, byteArr.length, seed, 
hashOut);
+  }
+
+  //The main API calls
+
+  /**
+   * Returns a 128-bit hash of the input as a long array of size 2.
+   *
+   * @param mem The input Memory. Must be non-null and non-empty,
+   * otherwise throws IllegalArgumentException.
+   * @param offsetBytes the starting point within Memory.
+   * @param lengthBytes the total number of bytes to be hashed.
+   * @param seed A long valued seed.
+   * @param hashOut the size 2 long array for the resulting 128-bit hash
+   * @return the hash.
+   */
+  public static long[] hash(final Memory mem, final long offsetBytes, final 
long lengthBytes,
+      final long seed, final long[] hashOut) {
+    Objects.requireNonNull(mem, "Input Memory is null");
+    final MemorySegment seg = mem.getMemorySegment();
+    return hash(seg, offsetBytes, lengthBytes, seed, hashOut);
+  }
+
+  /**
+   * Returns a 128-bit hash of the input as a long array of size 2.
+   *
+   * @param seg The input MemorySegment. Must be non-null and non-empty,
+   * otherwise throws IllegalArgumentException.
+   * @param offsetBytes the starting point within Memory.
+   * @param lengthBytes the total number of bytes to be hashed.
+   * @param seed A long valued seed.
+   * @param hashOut the size 2 long array for the resulting 128-bit hash
+   * @return the hash.
+   * @throws IllegalArgumentException if input MemorySegment is empty
+   */
+  public static long[] hash(final MemorySegment seg, final long offsetBytes, 
final long lengthBytes,
+      final long seed, final long[] hashOut) {
+    Objects.requireNonNull(seg, "Input MemorySegment is null");
+    if (seg.byteSize() == 0L) { throw new IllegalArgumentException("Input 
MemorySegment is empty."); }
+
+    long cumOff = offsetBytes;
+
+    long h1 = seed;
+    long h2 = seed;
+    long rem = lengthBytes;
+
+    // Process the 128-bit blocks (the body) into the hash
+    while (rem >= 16L) {
+      final long k1 = seg.get(ValueLayout.JAVA_LONG_UNALIGNED, cumOff);     
//0, 16, 32, ...
+      final long k2 = seg.get(ValueLayout.JAVA_LONG_UNALIGNED, cumOff + 8); 
//8, 24, 40, ...
+      cumOff += 16L;
+      rem -= 16L;
+
+      h1 ^= mixK1(k1);
+      h1 = Long.rotateLeft(h1, 27);
+      h1 += h2;
+      h1 = (h1 * 5) + 0x52dce729L;
+
+      h2 ^= mixK2(k2);
+      h2 = Long.rotateLeft(h2, 31);
+      h2 += h1;
+      h2 = (h2 * 5) + 0x38495ab5L;
+    }
+
+    // Get the tail (if any): 1 to 15 bytes
+    if (rem > 0L) {
+      long k1 = 0;
+      long k2 = 0;
+      switch ((int) rem) {
+        case 15: {
+          k2 ^= (seg.get(ValueLayout.JAVA_BYTE, cumOff + 14) & 0xFFL) << 48;
+        }
+        //$FALL-THROUGH$
+        case 14: {
+          k2 ^= (seg.get(ValueLayout.JAVA_SHORT_UNALIGNED, cumOff + 12) & 
0xFFFFL) << 32;
+          k2 ^= seg.get(ValueLayout.JAVA_INT_UNALIGNED, cumOff + 8) & 
0xFFFFFFFFL;
+          k1 = seg.get(ValueLayout.JAVA_LONG_UNALIGNED, cumOff);
+          break;
+        }
+
+        case 13: {
+          k2 ^= (seg.get(ValueLayout.JAVA_BYTE, cumOff + 12) & 0xFFL) << 32;
+        }
+        //$FALL-THROUGH$
+        case 12: {
+          k2 ^= seg.get(ValueLayout.JAVA_INT_UNALIGNED, cumOff + 8) & 
0xFFFFFFFFL;
+          k1 = seg.get(ValueLayout.JAVA_LONG_UNALIGNED, cumOff);
+          break;
+        }
+
+        case 11: {
+          k2 ^= (seg.get(ValueLayout.JAVA_BYTE, cumOff + 10) & 0xFFL) << 16;
+        }
+        //$FALL-THROUGH$
+        case 10: {
+          k2 ^= seg.get(ValueLayout.JAVA_SHORT_UNALIGNED, cumOff + 8) & 
0xFFFFL;
+          k1 = seg.get(ValueLayout.JAVA_LONG_UNALIGNED, cumOff);
+          break;
+        }
+
+        case  9: {
+          k2 ^= seg.get(ValueLayout.JAVA_BYTE, cumOff + 8) & 0xFFL;
+        }
+        //$FALL-THROUGH$
+        case  8: {
+          k1 = seg.get(ValueLayout.JAVA_LONG_UNALIGNED, cumOff);
+          break;
+        }
+
+        case  7: {
+          k1 ^= (seg.get(ValueLayout.JAVA_BYTE, cumOff + 6) & 0xFFL) << 48;
+        }
+        //$FALL-THROUGH$
+        case  6: {
+          k1 ^= (seg.get(ValueLayout.JAVA_SHORT_UNALIGNED, cumOff + 4) & 
0xFFFFL) << 32;
+          k1 ^= seg.get(ValueLayout.JAVA_INT_UNALIGNED, cumOff) & 0xFFFFFFFFL;
+          break;
+        }
+
+        case  5: {
+          k1 ^= (seg.get(ValueLayout.JAVA_BYTE, cumOff + 4) & 0xFFL) << 32;
+        }
+        //$FALL-THROUGH$
+        case  4: {
+          k1 ^= seg.get(ValueLayout.JAVA_INT_UNALIGNED, cumOff) & 0xFFFFFFFFL;
+          break;
+        }
+
+        case  3: {
+          k1 ^= (seg.get(ValueLayout.JAVA_BYTE, cumOff + 2) & 0xFFL) << 16;
+        }
+        //$FALL-THROUGH$
+        case  2: {
+          k1 ^= seg.get(ValueLayout.JAVA_SHORT_UNALIGNED, cumOff) & 0xFFFFL;
+          break;
+        }
+
+        case  1: {
+          k1 ^= seg.get(ValueLayout.JAVA_BYTE, cumOff) & 0xFFL;
+          break;
+        }
+        default: break; //can't happen
+      }
+
+      h1 ^= mixK1(k1);
+      h2 ^= mixK2(k2);
+    }
+    return finalMix128(h1, h2, lengthBytes, hashOut);
+  }
+
+  //--Helper methods----------------------------------------------------
+
+  /**
+   * Self mix of k1
+   *
+   * @param k1 input argument
+   * @return mix
+   */
+  private static long mixK1(long k1) {
+    k1 *= C1;
+    k1 = Long.rotateLeft(k1, 31);
+    k1 *= C2;
+    return k1;
+  }
+
+  /**
+   * Self mix of k2
+   *
+   * @param k2 input argument
+   * @return mix
+   */
+  private static long mixK2(long k2) {
+    k2 *= C2;
+    k2 = Long.rotateLeft(k2, 33);
+    k2 *= C1;
+    return k2;
+  }
+
+  /**
+   * Final self mix of h*.
+   *
+   * @param h input to final mix
+   * @return mix
+   */
+  private static long finalMix64(long h) {
+    h ^= h >>> 33;
+    h *= 0xff51afd7ed558ccdL;
+    h ^= h >>> 33;
+    h *= 0xc4ceb9fe1a85ec53L;
+    h ^= h >>> 33;
+    return h;
+  }
+
+  /**
+   * Finalization: Add the length into the hash and mix
+   * @param h1 intermediate hash
+   * @param h2 intermediate hash
+   * @param lengthBytes the length in bytes
+   * @param hashOut the output array of 2 longs
+   * @return hashOut
+   */
+  private static long[] finalMix128(long h1, long h2, final long lengthBytes, 
final long[] hashOut) {
+    h1 ^= lengthBytes;
+    h2 ^= lengthBytes;
+
+    h1 += h2;
+    h2 += h1;
+
+    h1 = finalMix64(h1);
+    h2 = finalMix64(h2);
+
+    h1 += h2;
+    h2 += h1;
+
+    hashOut[0] = h1;
+    hashOut[1] = h2;
+    return hashOut;
+  }
+
+  private MurmurHash3FFM21() { }
+
+}
diff --git a/src/main/java/org/apache/datasketches/hll/DirectAuxHashMap.java 
b/src/main/java/org/apache/datasketches/hll/DirectAuxHashMap.java
index 98884f5e..e6c408f3 100644
--- a/src/main/java/org/apache/datasketches/hll/DirectAuxHashMap.java
+++ b/src/main/java/org/apache/datasketches/hll/DirectAuxHashMap.java
@@ -195,7 +195,7 @@ final class DirectAuxHashMap implements AuxHashMap {
       final WritableMemory newWmem = svr.request(host.wmem, requestBytes);
       host.wmem.copyTo(0, newWmem, 0, host.auxStart);
       newWmem.clear(host.auxStart, newAuxBytes); //clear space for new aux data
-      svr.requestClose(host.wmem, newWmem); //old host.wmem is now invalid
+      svr.requestClose(host.wmem); //old host.wmem is now invalid
       host.updateMemory(newWmem);
     }
     //rehash into larger aux array
diff --git a/src/main/java/org/apache/datasketches/kll/KllDoublesHelper.java 
b/src/main/java/org/apache/datasketches/kll/KllDoublesHelper.java
index acbecdf0..cb5788a7 100644
--- a/src/main/java/org/apache/datasketches/kll/KllDoublesHelper.java
+++ b/src/main/java/org/apache/datasketches/kll/KllDoublesHelper.java
@@ -207,8 +207,11 @@ final class KllDoublesHelper {
 
       //MEMORY SPACE MANAGEMENT
       if (mySketch.getWritableMemory() != null) {
-        final WritableMemory wmem =
-            KllHelper.memorySpaceMgmt(mySketch, myNewLevelsArr.length, 
myNewDoubleItemsArr.length);
+        final WritableMemory oldWmem = mySketch.getWritableMemory();
+        final WritableMemory wmem = KllHelper.memorySpaceMgmt(mySketch, 
myNewLevelsArr.length, myNewDoubleItemsArr.length);
+        if (!wmem.isSameResource(oldWmem)) {
+          mySketch.getMemoryRequestServer().requestClose(oldWmem);
+        }
         mySketch.setWritableMemory(wmem);
       }
     } //end of updating levels above level 0
diff --git a/src/main/java/org/apache/datasketches/kll/KllDoublesSketch.java 
b/src/main/java/org/apache/datasketches/kll/KllDoublesSketch.java
index fbe9dbb3..01608ca0 100644
--- a/src/main/java/org/apache/datasketches/kll/KllDoublesSketch.java
+++ b/src/main/java/org/apache/datasketches/kll/KllDoublesSketch.java
@@ -137,7 +137,7 @@ public abstract class KllDoublesSketch extends KllSketch 
implements QuantilesDou
     Objects.requireNonNull(srcMem, "Parameter 'srcMem' must not be null");
     final KllMemoryValidate memVal = new KllMemoryValidate(srcMem, 
DOUBLES_SKETCH, null);
     if (memVal.sketchStructure == UPDATABLE) {
-      final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer(); 
//dummy
+      final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
       return new KllDirectDoublesSketch(memVal.sketchStructure, 
(WritableMemory)srcMem, memReqSvr, memVal);
     } else {
       return new KllDirectCompactDoublesSketch(memVal.sketchStructure, srcMem, 
memVal);
diff --git a/src/main/java/org/apache/datasketches/kll/KllFloatsHelper.java 
b/src/main/java/org/apache/datasketches/kll/KllFloatsHelper.java
index 69045f78..1796cac4 100644
--- a/src/main/java/org/apache/datasketches/kll/KllFloatsHelper.java
+++ b/src/main/java/org/apache/datasketches/kll/KllFloatsHelper.java
@@ -207,8 +207,11 @@ final class KllFloatsHelper {
 
       //MEMORY SPACE MANAGEMENT
       if (mySketch.getWritableMemory() != null) {
-        final WritableMemory wmem =
-            KllHelper.memorySpaceMgmt(mySketch, myNewLevelsArr.length, 
myNewFloatItemsArr.length);
+        final WritableMemory oldWmem = mySketch.getWritableMemory();
+        final WritableMemory wmem = KllHelper.memorySpaceMgmt(mySketch, 
myNewLevelsArr.length, myNewFloatItemsArr.length);
+        if (!wmem.isSameResource(oldWmem)) {
+          mySketch.getMemoryRequestServer().requestClose(oldWmem);
+        }
         mySketch.setWritableMemory(wmem);
       }
     } //end of updating levels above level 0
diff --git a/src/main/java/org/apache/datasketches/kll/KllFloatsSketch.java 
b/src/main/java/org/apache/datasketches/kll/KllFloatsSketch.java
index b993f999..cf282c87 100644
--- a/src/main/java/org/apache/datasketches/kll/KllFloatsSketch.java
+++ b/src/main/java/org/apache/datasketches/kll/KllFloatsSketch.java
@@ -137,7 +137,7 @@ public abstract class KllFloatsSketch extends KllSketch 
implements QuantilesFloa
     Objects.requireNonNull(srcMem, "Parameter 'srcMem' must not be null");
     final KllMemoryValidate memVal = new KllMemoryValidate(srcMem, 
FLOATS_SKETCH, null);
     if (memVal.sketchStructure == UPDATABLE) {
-      final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer(); 
//dummy
+      final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
       return new KllDirectFloatsSketch(memVal.sketchStructure, 
(WritableMemory)srcMem, memReqSvr, memVal);
     } else {
       return new KllDirectCompactFloatsSketch(memVal.sketchStructure, srcMem, 
memVal);
diff --git a/src/main/java/org/apache/datasketches/kll/KllHelper.java 
b/src/main/java/org/apache/datasketches/kll/KllHelper.java
index 21188255..8dd729da 100644
--- a/src/main/java/org/apache/datasketches/kll/KllHelper.java
+++ b/src/main/java/org/apache/datasketches/kll/KllHelper.java
@@ -52,6 +52,7 @@ import org.apache.datasketches.common.ArrayOfItemsSerDe;
 import org.apache.datasketches.common.SketchesArgumentException;
 import org.apache.datasketches.kll.KllSketch.SketchStructure;
 import org.apache.datasketches.kll.KllSketch.SketchType;
+import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
 import org.apache.datasketches.memory.WritableMemory;
 
@@ -353,7 +354,8 @@ final class KllHelper {
     final WritableMemory newWmem;
 
     if (requiredSketchBytes > oldWmem.getCapacity()) { //Acquire new 
WritableMemory
-      newWmem = sketch.getMemoryRequestServer().request(oldWmem, 
requiredSketchBytes);
+      final MemoryRequestServer memReqSvr = sketch.getMemoryRequestServer();
+      newWmem = memReqSvr.request(oldWmem, requiredSketchBytes);
       oldWmem.copyTo(0, newWmem, 0, DATA_START_ADR); //copy preamble (first 20 
bytes)
     }
     else { //Expand or contract in current memory
@@ -617,7 +619,7 @@ final class KllHelper {
       maxFloat = fltSk.getMaxItem();
       //assert we are following a certain growth scheme
       assert myCurFloatItemsArr.length == myCurTotalItemsCapacity;
-    } 
+    }
     else if (sketchType == LONGS_SKETCH) {
       final KllLongsSketch lngSk = (KllLongsSketch) sketch;
       myCurLongItemsArr = lngSk.getLongItemsArray();
@@ -668,7 +670,7 @@ final class KllHelper {
       myNewFloatItemsArr = new float[myNewTotalItemsCapacity];
       // copy and shift the current items data into the new array
       System.arraycopy(myCurFloatItemsArr, 0, myNewFloatItemsArr, 
deltaItemsCap, myCurTotalItemsCapacity);
-    } 
+    }
     else if (sketchType == LONGS_SKETCH) {
       myNewLongItemsArr = new long[myNewTotalItemsCapacity];
       // copy and shift the current items data into the new array
@@ -682,7 +684,11 @@ final class KllHelper {
 
     //MEMORY SPACE MANAGEMENT
     if (sketch.getWritableMemory() != null) {
+      final WritableMemory oldWmem = sketch.getWritableMemory();
       final WritableMemory wmem = memorySpaceMgmt(sketch, 
myNewLevelsArr.length, myNewTotalItemsCapacity);
+      if (!wmem.isSameResource(oldWmem)) {
+        sketch.getMemoryRequestServer().requestClose(oldWmem);
+      }
       sketch.setWritableMemory(wmem);
     }
 
@@ -700,7 +706,7 @@ final class KllHelper {
       fltSk.setMinItem(minFloat);
       fltSk.setMaxItem(maxFloat);
       fltSk.setFloatItemsArray(myNewFloatItemsArr);
-    } 
+    }
     else if (sketchType == LONGS_SKETCH) {
       final KllLongsSketch lngSk = (KllLongsSketch) sketch;
       lngSk.setMinItem(minLong);
diff --git a/src/main/java/org/apache/datasketches/kll/KllLongsHelper.java 
b/src/main/java/org/apache/datasketches/kll/KllLongsHelper.java
index 04fe2cc0..2dc14610 100644
--- a/src/main/java/org/apache/datasketches/kll/KllLongsHelper.java
+++ b/src/main/java/org/apache/datasketches/kll/KllLongsHelper.java
@@ -207,8 +207,11 @@ final class KllLongsHelper {
 
       //MEMORY SPACE MANAGEMENT
       if (mySketch.getWritableMemory() != null) {
-        final WritableMemory wmem =
-            KllHelper.memorySpaceMgmt(mySketch, myNewLevelsArr.length, 
myNewLongItemsArray.length);
+        final WritableMemory oldWmem = mySketch.getWritableMemory();
+        final WritableMemory wmem = KllHelper.memorySpaceMgmt(mySketch, 
myNewLevelsArr.length, myNewLongItemsArray.length);
+        if (!wmem.isSameResource(oldWmem)) {
+          mySketch.getMemoryRequestServer().requestClose(oldWmem);
+        }
         mySketch.setWritableMemory(wmem);
       }
     } //end of updating levels above level 0
diff --git a/src/main/java/org/apache/datasketches/kll/KllLongsSketch.java 
b/src/main/java/org/apache/datasketches/kll/KllLongsSketch.java
index f5688ad7..827f825f 100644
--- a/src/main/java/org/apache/datasketches/kll/KllLongsSketch.java
+++ b/src/main/java/org/apache/datasketches/kll/KllLongsSketch.java
@@ -137,7 +137,7 @@ public abstract class KllLongsSketch extends KllSketch 
implements QuantilesLongs
     Objects.requireNonNull(srcMem, "Parameter 'srcMem' must not be null");
     final KllMemoryValidate memVal = new KllMemoryValidate(srcMem, 
LONGS_SKETCH, null);
     if (memVal.sketchStructure == UPDATABLE) {
-      final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer(); 
//dummy
+      final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
       return new KllDirectLongsSketch(memVal.sketchStructure, 
(WritableMemory)srcMem, memReqSvr, memVal);
     } else {
       return new KllDirectCompactLongsSketch(memVal.sketchStructure, srcMem, 
memVal);
diff --git 
a/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketch.java
 
b/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketch.java
index 7a7a7a85..12604ecb 100644
--- 
a/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketch.java
+++ 
b/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketch.java
@@ -266,9 +266,8 @@ final class DirectUpdateDoublesSketch extends 
DirectUpdateDoublesSketchR {
     }
 
     final WritableMemory newMem = memReqSvr.request(mem_, needBytes);
-
     mem_.copyTo(0, newMem, 0, memBytes);
-    memReqSvr.requestClose(mem_, newMem);
+    memReqSvr.requestClose(mem_);
 
     return newMem;
   }
diff --git 
a/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketchR.java
 
b/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketchR.java
index 3e80b3f0..23417033 100644
--- 
a/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketchR.java
+++ 
b/src/main/java/org/apache/datasketches/quantiles/DirectUpdateDoublesSketchR.java
@@ -146,7 +146,7 @@ class DirectUpdateDoublesSketchR extends 
UpdateDoublesSketch {
 
   @Override
   int getCombinedBufferItemCapacity() {
-    return ((int)mem_.getCapacity() - COMBINED_BUFFER) / 8;
+    return Math.max(0, (int)mem_.getCapacity() - COMBINED_BUFFER) / 8;
   }
 
   @Override
diff --git a/src/main/java/org/apache/datasketches/quantiles/DoublesSketch.java 
b/src/main/java/org/apache/datasketches/quantiles/DoublesSketch.java
index 2fc399f9..4c9f7428 100644
--- a/src/main/java/org/apache/datasketches/quantiles/DoublesSketch.java
+++ b/src/main/java/org/apache/datasketches/quantiles/DoublesSketch.java
@@ -460,9 +460,9 @@ public abstract class DoublesSketch implements 
QuantilesDoublesAPI {
     final int totLevels = computeNumLevelsNeeded(k, n);
     if (n <= k) {
       final int ceil = Math.max(ceilingPowerOf2((int)n), MIN_K * 2);
-      return metaPre + ceil << 3;
+      return (metaPre + ceil) << 3;
     }
-    return metaPre + (2 + totLevels) * k << 3;
+    return (metaPre + (2 + totLevels) * k) << 3;
   }
 
   /**
diff --git 
a/src/main/java/org/apache/datasketches/theta/ConcurrentDirectQuickSelectSketch.java
 
b/src/main/java/org/apache/datasketches/theta/ConcurrentDirectQuickSelectSketch.java
index 94660319..dbdedebd 100644
--- 
a/src/main/java/org/apache/datasketches/theta/ConcurrentDirectQuickSelectSketch.java
+++ 
b/src/main/java/org/apache/datasketches/theta/ConcurrentDirectQuickSelectSketch.java
@@ -199,7 +199,7 @@ final class ConcurrentDirectQuickSelectSketch extends 
DirectQuickSelectSketch
 
   @Override
   public final void initBgPropagationService() {
-    executorService_ = 
ConcurrentPropagationService.getExecutorService(Thread.currentThread().getId());
+    executorService_ = 
ConcurrentPropagationService.getExecutorService(Thread.currentThread().threadId());
   }
 
   @Override
@@ -258,7 +258,7 @@ final class ConcurrentDirectQuickSelectSketch extends 
DirectQuickSelectSketch
   private void advanceEpoch() {
     awaitBgPropagationTermination();
     startEagerPropagation();
-    
ConcurrentPropagationService.resetExecutorService(Thread.currentThread().getId());
+    
ConcurrentPropagationService.resetExecutorService(Thread.currentThread().threadId());
     //no inspection NonAtomicOperationOnVolatileField
     // this increment of a volatile field is done within the scope of the 
propagation
     // synchronization and hence is done by a single thread.
diff --git 
a/src/main/java/org/apache/datasketches/theta/ConcurrentHeapQuickSelectSketch.java
 
b/src/main/java/org/apache/datasketches/theta/ConcurrentHeapQuickSelectSketch.java
index 1ce3b4ec..e4cc3a15 100644
--- 
a/src/main/java/org/apache/datasketches/theta/ConcurrentHeapQuickSelectSketch.java
+++ 
b/src/main/java/org/apache/datasketches/theta/ConcurrentHeapQuickSelectSketch.java
@@ -194,7 +194,7 @@ final class ConcurrentHeapQuickSelectSketch extends 
HeapQuickSelectSketch
 
   @Override
   public void initBgPropagationService() {
-    executorService_ = 
ConcurrentPropagationService.getExecutorService(Thread.currentThread().getId());
+    executorService_ = 
ConcurrentPropagationService.getExecutorService(Thread.currentThread().threadId());
   }
 
   @Override
@@ -253,7 +253,7 @@ final class ConcurrentHeapQuickSelectSketch extends 
HeapQuickSelectSketch
   private void advanceEpoch() {
     awaitBgPropagationTermination();
     startEagerPropagation();
-    
ConcurrentPropagationService.resetExecutorService(Thread.currentThread().getId());
+    
ConcurrentPropagationService.resetExecutorService(Thread.currentThread().threadId());
     //no inspection NonAtomicOperationOnVolatileField
     // this increment of a volatile field is done within the scope of the 
propagation
     // synchronization and hence is done by a single thread
diff --git 
a/src/main/java/org/apache/datasketches/theta/DirectQuickSelectSketch.java 
b/src/main/java/org/apache/datasketches/theta/DirectQuickSelectSketch.java
index ad9051a0..af073a5e 100644
--- a/src/main/java/org/apache/datasketches/theta/DirectQuickSelectSketch.java
+++ b/src/main/java/org/apache/datasketches/theta/DirectQuickSelectSketch.java
@@ -327,11 +327,11 @@ class DirectQuickSelectSketch extends 
DirectQuickSelectSketchR {
             throw new SketchesArgumentException("Out of Memory, 
MemoryRequestServer is null, cannot expand.");
           }
 
-          final WritableMemory newDstMem = memReqSvr_.request(wmem_,reqBytes);
+          final WritableMemory newDstMem = memReqSvr_.request(wmem_, reqBytes);
 
           moveAndResize(wmem_, preambleLongs, lgArrLongs, newDstMem, 
tgtLgArrLongs, thetaLong);
 
-          memReqSvr_.requestClose(wmem_, newDstMem);
+          memReqSvr_.requestClose(wmem_);
 
           wmem_ = newDstMem;
           hashTableThreshold_ = getOffHeapHashTableThreshold(lgNomLongs, 
tgtLgArrLongs);
diff --git 
a/src/test/java/org/apache/datasketches/filters/bloomfilter/BloomFilterTest.java
 
b/src/test/java/org/apache/datasketches/filters/bloomfilter/BloomFilterTest.java
index 7d72fae2..2d71805a 100644
--- 
a/src/test/java/org/apache/datasketches/filters/bloomfilter/BloomFilterTest.java
+++ 
b/src/test/java/org/apache/datasketches/filters/bloomfilter/BloomFilterTest.java
@@ -31,7 +31,7 @@ import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
-import jdk.incubator.foreign.ResourceScope;
+import java.lang.foreign.Arena;
 
 public class BloomFilterTest {
 
@@ -52,8 +52,9 @@ public class BloomFilterTest {
     assertFalse(bf1.isDirect());
     assertFalse(bf1.isReadOnly());
 
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = 
WritableMemory.allocateDirect(sizeBytes)).scope()) {
+
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(sizeBytes, arena);
       final BloomFilter bf2 = new BloomFilter(numBits, numHashes, seed, wmem);
       assertTrue(bf2.isEmpty());
       assertTrue(bf2.hasMemory());
@@ -158,8 +159,9 @@ public class BloomFilterTest {
 
     int numFound = 0;
     for (long i = 0; i < 2 * n; ++i) {
-      if (bf.query(i))
+      if (bf.query(i)) {
         ++numFound;
+      }
     }
     assertTrue(numFound >= n);
     assertTrue(numFound < 1.1 * n);
@@ -339,8 +341,12 @@ public class BloomFilterTest {
     int fromBytesCount = 0;
     for (int i = 0; i < numBits; ++i) {
       boolean val = fromBytes.query(0.5 + i);
-      if (val) ++fromBytesCount;
-      if (i < n) assertTrue(val);
+      if (val) {
+        ++fromBytesCount;
+      }
+      if (i < n) {
+        assertTrue(val);
+      }
     }
     assertEquals(fromBytesCount, n + count); // same numbers of items should 
match
 
@@ -354,8 +360,12 @@ public class BloomFilterTest {
     int fromLongsCount = 0;
     for (int i = 0; i < numBits; ++i) {
       boolean val = fromLongs.query(0.5 + i);
-      if (val) ++fromLongsCount;
-      if (i < n) assertTrue(val);
+      if (val) {
+        ++fromLongsCount;
+      }
+      if (i < n) {
+        assertTrue(val);
+      }
     }
     assertEquals(fromLongsCount, n + count); // same numbers of items should 
match
 
diff --git 
a/src/test/java/org/apache/datasketches/hash/MurmurHash3AdaptorTest.java 
b/src/test/java/org/apache/datasketches/hash/MurmurHash3AdaptorTest.java
deleted file mode 100644
index 16a8e665..00000000
--- a/src/test/java/org/apache/datasketches/hash/MurmurHash3AdaptorTest.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.hash;
-
-import static org.apache.datasketches.hash.MurmurHash3Adaptor.asDouble;
-import static org.apache.datasketches.hash.MurmurHash3Adaptor.asInt;
-import static org.apache.datasketches.hash.MurmurHash3Adaptor.hashToBytes;
-import static org.apache.datasketches.hash.MurmurHash3Adaptor.hashToLongs;
-import static org.apache.datasketches.hash.MurmurHash3Adaptor.modulo;
-
-import org.apache.datasketches.common.SketchesArgumentException;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-/**
- * @author Lee Rhodes
- */
-public class MurmurHash3AdaptorTest {
-
-  @Test
-  public void checkToBytesLong() {
-    byte[] result = hashToBytes(2L, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-  }
-
-  @Test
-  public void checkToBytesLongArr() {
-    long[] arr = { 1L, 2L };
-    byte[] result = hashToBytes(arr, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new long[0];
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  @Test
-  public void checkToBytesIntArr() {
-    int[] arr = { 1, 2 };
-    byte[] result = hashToBytes(arr, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new int[0];
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  @Test
-  public void checkToBytesCharArr() {
-    char[] arr = { 1, 2 };
-    byte[] result = hashToBytes(arr, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new char[0];
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  @Test
-  public void checkToBytesByteArr() {
-    byte[] arr = { 1, 2 };
-    byte[] result = hashToBytes(arr, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new byte[0];
-    result = hashToBytes(arr, 0L);
-    Assert.assertEquals(result, null);
-
-  }
-
-  @Test
-  public void checkToBytesDouble() {
-    byte[] result = hashToBytes(1.0, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    result = hashToBytes(0.0, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    result = hashToBytes( -0.0, 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-  }
-
-  @Test
-  public void checkToBytesString() {
-    byte[] result = hashToBytes("1", 0L);
-    for (int i = 8; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    result = hashToBytes("", 0L);
-    Assert.assertEquals(result, null);
-
-    String s = null;
-    result = hashToBytes(s, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  /************/
-
-  @Test
-  public void checkToLongsLong() {
-    long[] result = hashToLongs(2L, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-  }
-
-  @Test
-  public void checkToLongsLongArr() {
-    long[] arr = { 1L, 2L };
-    long[] result = hashToLongs(arr, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new long[0];
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  @Test
-  public void checkToLongsIntArr() {
-    int[] arr = { 1, 2 };
-    long[] result = hashToLongs(arr, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new int[0];
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  @Test
-  public void checkToLongsCharArr() {
-    char[] arr = { 1, 2 };
-    long[] result = hashToLongs(arr, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new char[0];
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  @Test
-  public void checkToLongsByteArr() {
-    byte[] arr = { 1, 2 };
-    long[] result = hashToLongs(arr, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    arr = null;
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-
-    arr = new byte[0];
-    result = hashToLongs(arr, 0L);
-    Assert.assertEquals(result, null);
-
-  }
-
-  @Test
-  public void checkToLongsDouble() {
-    long[] result = hashToLongs(1.0, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    result = hashToLongs(0.0, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    result = hashToLongs( -0.0, 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-  }
-
-  @Test
-  public void checkToLongsString() {
-    long[] result = hashToLongs("1", 0L);
-    for (int i = 2; i-- > 0;) {
-      Assert.assertNotEquals(result[i], 0);
-    }
-    result = hashToLongs("", 0L);
-    Assert.assertEquals(result, null);
-    String s = null;
-    result = hashToLongs(s, 0L);
-    Assert.assertEquals(result, null);
-  }
-
-  /*************/
-
-  @Test
-  public void checkModulo() {
-    int div = 7;
-    for (int i = 20; i-- > 0;) {
-      long[] out = hashToLongs(i, 9001);
-      int mod = modulo(out[0], out[1], div);
-      Assert.assertTrue((mod < div) && (mod >= 0));
-      mod = modulo(out, div);
-      Assert.assertTrue((mod < div) && (mod >= 0));
-    }
-  }
-
-  @Test
-  public void checkAsDouble() {
-    for (int i = 0; i < 10000; i++ ) {
-      double result = asDouble(hashToLongs(i, 0));
-      Assert.assertTrue((result >= 0) && (result < 1.0));
-    }
-  }
-
-  //Check asInt() functions
-
-  @Test
-  public void checkAsInt() {
-    int lo = (3 << 28);
-    int hi = (1 << 30) + 1;
-    for (byte i = 0; i < 126; i++ ) {
-      long[] longArr = {i, i+1};         //long[]
-      int result = asInt(longArr, lo);
-      Assert.assertTrue((result >= 0) && (result < lo));
-      result = asInt(longArr, hi);
-      Assert.assertTrue((result >= 0) && (result < hi));
-
-      int[] intArr = {i, i+1};           //int[]
-      result = asInt(intArr, lo);
-      Assert.assertTrue((result >= 0) && (result < lo));
-      result = asInt(intArr, hi);
-      Assert.assertTrue((result >= 0) && (result < hi));
-
-      byte[] byteArr = {i, (byte)(i+1)}; //byte[]
-      result = asInt(byteArr, lo);
-      Assert.assertTrue((result >= 0) && (result < lo));
-      result = asInt(byteArr, hi);
-      Assert.assertTrue((result >= 0) && (result < hi));
-
-      long longV = i;                    //long
-      result = asInt(longV, lo);
-      Assert.assertTrue((result >= 0) && (result < lo));
-      result = asInt(longV, hi);
-      Assert.assertTrue((result >= 0) && (result < hi));
-
-      double v = i;                //double
-      result = asInt(v, lo);
-      Assert.assertTrue((result >= 0) && (result < lo));
-      result = asInt(v, hi);
-      Assert.assertTrue((result >= 0) && (result < hi));
-
-      String s = Integer.toString(i);    //String
-      result = asInt(s, lo);
-      Assert.assertTrue((result >= 0) && (result < lo));
-      result = asInt(s, hi);
-      Assert.assertTrue((result >= 0) && (result < hi));
-    }
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseLongNull() {
-    long[] arr = null;
-    asInt(arr, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseLongEmpty() {
-    long[] arr = new long[0];
-    asInt(arr, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseIntNull() {
-    int[] arr = null;
-    asInt(arr, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseIntEmpty() {
-    int[] arr = new int[0];
-    asInt(arr, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseByteNull() {
-    byte[] arr = null;
-    asInt(arr, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseByteEmpty() {
-    byte[] arr = new byte[0];
-    asInt(arr, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseStringNull() {
-    String s = null;
-    asInt(s, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseStringEmpty() {
-    String s = "";
-    asInt(s, 1000);
-  }
-
-  @Test (expectedExceptions = SketchesArgumentException.class)
-  public void checkAsIntCornerCaseNTooSmall() {
-    String s = "abc";
-    asInt(s, 1);
-  }
-
-  @Test
-  public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
-  }
-
-  /**
-   * @param s value to print
-   */
-  static void println(String s) {
-    //System.out.println(s); //disable here
-  }
-
-}
diff --git a/src/test/java/org/apache/datasketches/hash/MurmurHash3v4Test.java 
b/src/test/java/org/apache/datasketches/hash/MurmurHash3FFM21Test.java
similarity index 83%
rename from src/test/java/org/apache/datasketches/hash/MurmurHash3v4Test.java
rename to src/test/java/org/apache/datasketches/hash/MurmurHash3FFM21Test.java
index 6cd4d624..d9771d30 100644
--- a/src/test/java/org/apache/datasketches/hash/MurmurHash3v4Test.java
+++ b/src/test/java/org/apache/datasketches/hash/MurmurHash3FFM21Test.java
@@ -28,13 +28,12 @@ import static org.testng.Assert.fail;
 import org.testng.annotations.Test;
 
 import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.memory.internal.MurmurHash3v4;
 import org.apache.datasketches.memory.WritableMemory;
 
 /**
  * @author Lee Rhodes
  */
-public class MurmurHash3v4Test {
+public class MurmurHash3FFM21Test {
   private Random rand = new Random();
   private static final int trials = 1 << 20;
 
@@ -154,25 +153,25 @@ public class MurmurHash3v4Test {
   }
 
   private static final long[] hashV2(long[] key, long seed) {
-    return MurmurHash3v4.hash(key, seed);
+    return MurmurHash3FFM21.hash(key, seed);
   }
 
   private static final long[] hashV2(int[] key2, long seed) {
-    return MurmurHash3v4.hash(key2, seed);
+    return MurmurHash3FFM21.hash(key2, seed);
   }
 
   private static final long[] hashV2(char[] key, long seed) {
-    return MurmurHash3v4.hash(key, seed);
+    return MurmurHash3FFM21.hash(key, seed);
   }
 
   private static final long[] hashV2(byte[] key, long seed) {
-    return MurmurHash3v4.hash(key, seed);
+    return MurmurHash3FFM21.hash(key, seed);
   }
 
   //V2 single primitives
 
   private static final long[] hashV2(long key, long seed, long[] out) {
-    return MurmurHash3v4.hash(key, seed, out);
+    return MurmurHash3FFM21.hash(key, seed, out);
   }
 
 //  private static final long[] hashV2(double key, long seed, long[] out) {
@@ -183,8 +182,6 @@ public class MurmurHash3v4Test {
 //    return MurmurHash3v4.hash(key, seed, out);
 //  }
 
-
-
   @Test
   public void offsetChecks() {
     long seed = 12345;
@@ -197,9 +194,9 @@ public class MurmurHash3v4Test {
     WritableMemory wmem = WritableMemory.allocate(cap);
     for (int i = 0; i < cap; i++) { wmem.putByte(i, (byte)(-128 + i)); }
 
-    for (int offset = 3; offset < 16; offset++) {
+    for (int offset = 0; offset < 16; offset++) {
       int arrLen = cap - offset;
-      hash1 = MurmurHash3v4.hash(wmem, offset, arrLen, seed, hash1);
+      hash1 = MurmurHash3FFM21.hash(wmem, offset, arrLen, seed, hash1);
       byte[] byteArr2 = new byte[arrLen];
       wmem.getByteArray(offset, byteArr2, 0, arrLen);
       hash2 = MurmurHash3.hash(byteArr2, seed);
@@ -222,8 +219,8 @@ public class MurmurHash3v4Test {
       for (int i = 0; i < j; i++) { wmem.putByte(i, (byte) (-128 + i)); }
 
       long[] hash1 = MurmurHash3.hash(in, 0);
-      hash2 = MurmurHash3v4.hash(wmem, offset, bytes, seed, hash2);
-      long[] hash3 = MurmurHash3v4.hash(in, seed);
+      hash2 = MurmurHash3FFM21.hash(wmem, offset, bytes, seed, hash2);
+      long[] hash3 = MurmurHash3FFM21.hash(in, seed);
 
       assertEquals(hash1, hash2);
       assertEquals(hash1, hash3);
@@ -246,8 +243,8 @@ public class MurmurHash3v4Test {
       for (int i = 0; i < j; i++) { wmem.putInt(i, i); }
 
       long[] hash1 = MurmurHash3.hash(in, 0);
-      hash2 = MurmurHash3v4.hash(wmem, offset, bytes, seed, hash2);
-      long[] hash3 = MurmurHash3v4.hash(in, seed);
+      hash2 = MurmurHash3FFM21.hash(wmem, offset, bytes, seed, hash2);
+      long[] hash3 = MurmurHash3FFM21.hash(in, seed);
 
       assertEquals(hash1, hash2);
       assertEquals(hash1, hash3);
@@ -270,8 +267,8 @@ public class MurmurHash3v4Test {
       for (int i = 0; i < j; i++) { wmem.putInt(i, i); }
 
       long[] hash1 = MurmurHash3.hash(in, 0);
-      hash2 = MurmurHash3v4.hash(wmem, offset, bytes, seed, hash2);
-      long[] hash3 = MurmurHash3v4.hash(in, seed);
+      hash2 = MurmurHash3FFM21.hash(wmem, offset, bytes, seed, hash2);
+      long[] hash3 = MurmurHash3FFM21.hash(in, seed);
 
       assertEquals(hash1, hash2);
       assertEquals(hash1, hash3);
@@ -294,8 +291,8 @@ public class MurmurHash3v4Test {
       for (int i = 0; i < j; i++) { wmem.putLong(i, i); }
 
       long[] hash1 = MurmurHash3.hash(in, 0);
-      hash2 = MurmurHash3v4.hash(wmem, offset, bytes, seed, hash2);
-      long[] hash3 = MurmurHash3v4.hash(in, seed);
+      hash2 = MurmurHash3FFM21.hash(wmem, offset, bytes, seed, hash2);
+      long[] hash3 = MurmurHash3FFM21.hash(in, seed);
 
       assertEquals(hash1, hash2);
       assertEquals(hash1, hash3);
@@ -313,8 +310,8 @@ public class MurmurHash3v4Test {
     WritableMemory wmem = WritableMemory.writableWrap(in);
 
     long[] hash1 = MurmurHash3.hash(in, 0);
-    hash2 = MurmurHash3v4.hash(wmem, offset, bytes, seed, hash2);
-    long[] hash3 = MurmurHash3v4.hash(in, seed);
+    hash2 = MurmurHash3FFM21.hash(wmem, offset, bytes, seed, hash2);
+    long[] hash3 = MurmurHash3FFM21.hash(in, seed);
 
     assertEquals(hash1, hash2);
     assertEquals(hash1, hash3);
@@ -325,57 +322,57 @@ public class MurmurHash3v4Test {
     long seed = 123;
     long[] hashOut = new long[2];
     try {
-      MurmurHash3v4.hash(Memory.wrap(new long[0]), 0, 0, seed, hashOut);  
//mem empty
+      MurmurHash3FFM21.hash(Memory.wrap(new long[0]), 0, 0, seed, hashOut);  
//mem empty
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       String s = "";
-      MurmurHash3v4.hash(s, seed, hashOut); //string empty
+      MurmurHash3FFM21.hash(s, seed, hashOut); //string empty
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       String s = null;
-      MurmurHash3v4.hash(s, seed, hashOut); //string null
+      MurmurHash3FFM21.hash(s, seed, hashOut); //string null
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       byte[] barr = new byte[0];
-      MurmurHash3v4.hash(barr, seed); //byte[] empty
+      MurmurHash3FFM21.hash(barr, seed); //byte[] empty
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       byte[] barr = null;
-      MurmurHash3v4.hash(barr, seed); //byte[] null
+      MurmurHash3FFM21.hash(barr, seed); //byte[] null
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       char[] carr = new char[0];
-      MurmurHash3v4.hash(carr, seed); //char[] empty
+      MurmurHash3FFM21.hash(carr, seed); //char[] empty
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       char[] carr = null;
-      MurmurHash3v4.hash(carr, seed); //char[] null
+      MurmurHash3FFM21.hash(carr, seed); //char[] null
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       int[] iarr = new int[0];
-      MurmurHash3v4.hash(iarr, seed); //int[] empty
+      MurmurHash3FFM21.hash(iarr, seed); //int[] empty
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       int[] iarr = null;
-      MurmurHash3v4.hash(iarr, seed); //int[] null
+      MurmurHash3FFM21.hash(iarr, seed); //int[] null
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       long[] larr = new long[0];
-      MurmurHash3v4.hash(larr, seed); //long[] empty
+      MurmurHash3FFM21.hash(larr, seed); //long[] empty
       fail();
     } catch (final IllegalArgumentException e) { } //OK
     try {
       long[] larr = null;
-      MurmurHash3v4.hash(larr, seed); //long[] null
+      MurmurHash3FFM21.hash(larr, seed); //long[] null
       fail();
     } catch (final IllegalArgumentException e) { } //OK
   }
@@ -385,9 +382,9 @@ public class MurmurHash3v4Test {
     long seed = 123;
     long[] hashOut = new long[2];
     String s = "123";
-    assertTrue(MurmurHash3v4.hash(s, seed, hashOut)[0] != 0);
+    assertTrue(MurmurHash3FFM21.hash(s, seed, hashOut)[0] != 0);
     long v = 123;
-    assertTrue(MurmurHash3v4.hash(v, seed, hashOut)[0] != 0);
+    assertTrue(MurmurHash3FFM21.hash(v, seed, hashOut)[0] != 0);
   }
 
   @Test
@@ -415,8 +412,8 @@ public class MurmurHash3v4Test {
 
     WritableMemory wmem = WritableMemory.writableWrap(dataArr);
     long[] hash1 = MurmurHash3.hash(dataArr, 0);
-    hash2 = MurmurHash3v4.hash(wmem, offset, bytes, seed, hash2);
-    long[] hash3 = MurmurHash3v4.hash(dbl, seed, hash2);
+    hash2 = MurmurHash3FFM21.hash(wmem, offset, bytes, seed, hash2);
+    long[] hash3 = MurmurHash3FFM21.hash(dbl, seed, hash2);
 
     assertEquals(hash1, hash2);
     assertEquals(hash1, hash3);
diff --git 
a/src/test/java/org/apache/datasketches/hash/MurmurHash3FFM21bTest.java 
b/src/test/java/org/apache/datasketches/hash/MurmurHash3FFM21bTest.java
new file mode 100644
index 00000000..1e23772b
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/hash/MurmurHash3FFM21bTest.java
@@ -0,0 +1,419 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.hash;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.datasketches.hash.MurmurHash3FFM21.hash;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.Resource;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Tests the MurmurHash3 against specific, known hash results given known
+ * inputs obtained from the public domain C++ version 150.
+ *
+ * @author Lee Rhodes
+ */
+public class MurmurHash3FFM21bTest {
+  private static final MemoryRequestServer memReqSvr = 
Resource.defaultMemReqSvr;
+
+  @Test
+  public void checkByteArrRemainderGT8() { //byte[], remainder > 8
+    String keyStr = "The quick brown fox jumps over the lazy dog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe34bbc7bbc071b6cL;
+    long h2 = 0x7a433ca9c49a9347L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrRemainderGT8withSegment() { //byte[], remainder > 8
+    String keyStr = "The quick brown fox jumps over the lazy dog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] out = new long[2];
+    MemorySegment seg = MemorySegment.ofArray(key);
+    long[] result = hash(seg, 0, seg.byteSize(), 0, out);
+    //Should be:
+    long h1 = 0xe34bbc7bbc071b6cL;
+    long h2 = 0x7a433ca9c49a9347L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrChange1bit() { //byte[], change one bit
+    String keyStr = "The quick brown fox jumps over the lazy eog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0x362108102c62d1c9L;
+    long h2 = 0x3285cd100292b305L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrRemainderLt8() { //byte[], test a remainder < 8
+    String keyStr = "The quick brown fox jumps over the lazy dogdogdog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be;
+    long h1 = 0x9c8205300e612fc4L;
+    long h2 = 0xcbc0af6136aa3df9L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrReaminderEQ8() { //byte[], test a remainder = 8
+    String keyStr = "The quick brown fox jumps over the lazy1";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe3301a827e5cdfe3L;
+    long h2 = 0xbdbf05f8da0f0392L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * This test should have the exact same output as Test4
+   */
+  @Test
+  public void checkLongArrRemainderEQ8() { //long[], test a remainder = 8
+    String keyStr = "The quick brown fox jumps over the lazy1";
+    long[] key = stringToLongs(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe3301a827e5cdfe3L;
+    long h2 = 0xbdbf05f8da0f0392L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * This test should have the exact same output as Test4
+   */
+  @Test
+  public void checkIntArrRemainderEQ8() { //int[], test a remainder = 8
+    String keyStr = "The quick brown fox jumps over the lazy1"; //40B
+    int[] key = stringToInts(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe3301a827e5cdfe3L;
+    long h2 = 0xbdbf05f8da0f0392L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkIntArrRemainderEQ0() { //int[], test a remainder = 0
+    String keyStr = "The quick brown fox jumps over t"; //32B
+    int[] key = stringToInts(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xdf6af91bb29bdacfL;
+    long h2 = 0x91a341c58df1f3a6L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * Tests an odd remainder of int[].
+   */
+  @Test
+  public void checkIntArrOddRemainder() { //int[], odd remainder
+    String keyStr = "The quick brown fox jumps over the lazy dog"; //43B
+    int[] key = stringToInts(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0x1eb232b0087543f5L;
+    long h2 = 0xfc4c1383c3ace40fL;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * Tests an odd remainder of int[].
+   */
+  @Test
+  public void checkCharArrOddRemainder() { //char[], odd remainder
+    String keyStr = "The quick brown fox jumps over the lazy dog.."; //45B
+    char[] key = keyStr.toCharArray();
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xca77b498ea9ed953L;
+    long h2 = 0x8b8f8ec3a8f4657eL;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * Tests an odd remainder of int[].
+   */
+  @Test
+  public void checkCharArrRemainderEQ0() { //char[], remainder of 0
+    String keyStr = "The quick brown fox jumps over the lazy "; //40B
+    char[] key = keyStr.toCharArray();
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0x51b15e9d0887f9f1L;
+    long h2 = 0x8106d226786511ebL;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrAllOnesZeros() { //byte[], test a ones byte and a 
zeros byte
+    byte[] key = {
+      0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 
0x6f, 0x77, 0x6e,
+      0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 
0x76, 0x65,
+      0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 
0x6f, 0x67,
+      (byte) 0xff, 0x64, 0x6f, 0x67, 0x00
+    };
+    long[] result = MurmurHash3FFM21.hash(key, 0);
+    //Should be:
+    long h1 = 0xe88abda785929c9eL;
+    long h2 = 0x96b98587cacc83d6L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * This test demonstrates that the hash of byte[], char[], int[], or long[] 
will produce the
+   * same hash result if, and only if, all the arrays have the same exact 
length in bytes, and if
+   * the contents of the values in the arrays have the same byte endianness 
and overall order.
+   */
+  @Test
+  public void checkCrossTypeHashConsistency() {
+    long[] out;
+    println("Bytes");
+    byte[] bArr = {1,2,3,4,5,6,7,8,   9,10,11,12,13,14,15,16,  
17,18,19,20,21,22,23,24};
+    long[] out1 = hash(bArr, 0L);
+    println(longToHexBytes(out1[0]));
+    println(longToHexBytes(out1[1]));
+
+    println("Chars");
+    char[] cArr = {0X0201, 0X0403, 0X0605, 0X0807,   0X0a09, 0X0c0b, 0X0e0d, 
0X100f,
+        0X1211, 0X1413, 0X1615, 0X1817};
+    out = hash(cArr, 0L);
+    Assert.assertEquals(out, out1);
+    println(longToHexBytes(out[0]));
+    println(longToHexBytes(out[1]));
+
+    println("Ints");
+    int[] iArr = {0X04030201, 0X08070605,   0X0c0b0a09, 0X100f0e0d,   
0X14131211,   0X18171615};
+    out = hash(iArr, 0L);
+    Assert.assertEquals(out, out1);
+    println(longToHexBytes(out[0]));
+    println(longToHexBytes(out[1]));
+
+    println("Longs");
+    long[] lArr = {0X0807060504030201L, 0X100f0e0d0c0b0a09L, 
0X1817161514131211L};
+    out = hash(lArr, 0L);
+    Assert.assertEquals(out, out1);
+    println(longToHexBytes(out[0]));
+    println(longToHexBytes(out[1]));
+  }
+
+  @Test
+  public void checkEmptyOrNullExceptions() {
+    try {
+      long[] arr = null;
+      hash(arr, 1L);
+      fail();
+    }
+    catch (final IllegalArgumentException e) { }
+    try {
+      int[] arr = null; hash(arr, 1L); fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      char[] arr = null; hash(arr, 1L); fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      byte[] arr = null; hash(arr, 1L); fail();
+    } catch (final IllegalArgumentException e) { }
+
+    long[] out = new long[2];
+    try {
+      String in = null; hash(in, 1L, out); fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      Memory mem = Memory.wrap(new byte[0]);
+      hash(mem, 0L, 4L, 1L, out);
+    } catch (final IllegalArgumentException e) { }
+    try (Arena arena = Arena.ofConfined()) {
+      Memory mem = WritableMemory.allocateDirect(8, 1, 
ByteOrder.nativeOrder(), memReqSvr, arena);
+      out = hash(mem, 0L, 4L, 1L, out);
+    }
+    assertTrue((out[0] != 0) && (out[1] != 0));
+  }
+
+  @Test
+  public void checkHashTails() {
+    long[] out = new long[2];
+    WritableMemory mem = WritableMemory.allocate(32);
+    mem.fill((byte)85);
+
+    for (int i = 16; i <= 32; i++) {
+      out = hash(mem, 0, i, 1L, out);
+    }
+  }
+
+  @Test
+  public void checkSinglePrimitives() {
+    long[] out = new long[2];
+    out = hash(1L, 1L, out);
+    out = hash(0.0, 1L, out);
+    out = hash("123", 1L, out);
+  }
+
+  //Helper methods
+
+  private static long[] stringToLongs(String in) {
+    byte[] bArr = in.getBytes(UTF_8);
+    int inLen = bArr.length;
+    int outLen = (inLen / 8) + (((inLen % 8) != 0) ? 1 : 0);
+    long[] out = new long[outLen];
+
+    for (int i = 0; i < (outLen - 1); i++ ) {
+      for (int j = 0; j < 8; j++ ) {
+        out[i] |= ((bArr[(i * 8) + j] & 0xFFL) << (j * 8));
+      }
+    }
+    int inTail = 8 * (outLen - 1);
+    int rem = inLen - inTail;
+    for (int j = 0; j < rem; j++ ) {
+      out[outLen - 1] |= ((bArr[inTail + j] & 0xFFL) << (j * 8));
+    }
+    return out;
+  }
+
+  private static int[] stringToInts(String in) {
+    byte[] bArr = in.getBytes(UTF_8);
+    int inLen = bArr.length;
+    int outLen = (inLen / 4) + (((inLen % 4) != 0) ? 1 : 0);
+    int[] out = new int[outLen];
+
+    for (int i = 0; i < (outLen - 1); i++ ) {
+      for (int j = 0; j < 4; j++ ) {
+        out[i] |= ((bArr[(i * 4) + j] & 0xFFL) << (j * 8));
+      }
+    }
+    int inTail = 4 * (outLen - 1);
+    int rem = inLen - inTail;
+    for (int j = 0; j < rem; j++ ) {
+      out[outLen - 1] |= ((bArr[inTail + j] & 0xFFL) << (j * 8));
+    }
+    return out;
+  }
+
+  /**
+   * Returns a string of spaced hex bytes in Big-Endian order.
+   * @param v the given long
+   * @return string of spaced hex bytes in Big-Endian order.
+   */
+  private static String longToHexBytes(final long v) {
+    final long mask = 0XFFL;
+    final StringBuilder sb = new StringBuilder();
+    for (int i = 8; i-- > 0; ) {
+      final String s = Long.toHexString((v >>> (i * 8)) & mask);
+      sb.append(zeroPad(s, 2)).append(" ");
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Prepend the given string with zeros. If the given string is equal or 
greater than the given
+   * field length, it will be returned without modification.
+   * @param s the given string
+   * @param fieldLength desired total field length including the given string
+   * @return the given string prepended with zeros.
+   */
+  private static final String zeroPad(final String s, final int fieldLength) {
+    return characterPad(s, fieldLength, '0', false);
+  }
+
+  /**
+   * Prepend or postpend the given string with the given character to fill the 
given field length.
+   * If the given string is equal or greater than the given field length, it 
will be returned
+   * without modification.
+   * @param s the given string
+   * @param fieldLength the desired field length
+   * @param padChar the desired pad character
+   * @param postpend if true append the padCharacters to the end of the string.
+   * @return prepended or postpended given string with the given character to 
fill the given field
+   * length.
+   */
+  private static final String characterPad(final String s, final int 
fieldLength, final char padChar,
+      final boolean postpend) {
+    final char[] chArr = s.toCharArray();
+    final int sLen = chArr.length;
+    if (sLen < fieldLength) {
+      final char[] out = new char[fieldLength];
+      final int blanks = fieldLength - sLen;
+
+      if (postpend) {
+        for (int i = 0; i < sLen; i++) {
+          out[i] = chArr[i];
+        }
+        for (int i = sLen; i < fieldLength; i++) {
+          out[i] = padChar;
+        }
+      } else { //prepend
+        for (int i = 0; i < blanks; i++) {
+          out[i] = padChar;
+        }
+        for (int i = blanks; i < fieldLength; i++) {
+          out[i] = chArr[i - blanks];
+        }
+      }
+
+      return String.valueOf(out);
+    }
+    return s;
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git 
a/src/test/java/org/apache/datasketches/hll/DirectAuxHashMapTest.java 
b/src/test/java/org/apache/datasketches/hll/DirectAuxHashMapTest.java
index 75504bc8..ecebe453 100644
--- a/src/test/java/org/apache/datasketches/hll/DirectAuxHashMapTest.java
+++ b/src/test/java/org/apache/datasketches/hll/DirectAuxHashMapTest.java
@@ -26,11 +26,10 @@ import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
-import java.nio.ByteOrder;
+import java.lang.foreign.Arena;
 import java.util.HashMap;
 
 import org.apache.datasketches.common.SketchesStateException;
-import org.apache.datasketches.memory.DefaultMemoryRequestServer;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
@@ -47,7 +46,7 @@ public class DirectAuxHashMapTest {
     int n = 8; //put lgConfigK == 4 into HLL mode
     long bytes = HllSketch.getMaxUpdatableSerializationBytes(lgConfigK, 
tgtHllType);
     HllSketch hllSketch;
-    WritableMemory wmem = WritableMemory.allocateDirect(bytes, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes, 
Arena.ofConfined());
 
     hllSketch = new HllSketch(lgConfigK, tgtHllType, wmem);
     for (int i = 0; i < n; i++) {
@@ -56,7 +55,7 @@ public class DirectAuxHashMapTest {
     hllSketch.couponUpdate(HllUtil.pair(7, 15)); //mock extreme values
     hllSketch.couponUpdate(HllUtil.pair(8, 15));
     hllSketch.couponUpdate(HllUtil.pair(9, 15));
-    //println(hllSketch.toString(true, true, true, true));
+    println(hllSketch.toString(true, true, true, true));
     DirectHllArray dha = (DirectHllArray) hllSketch.hllSketchImpl;
     assertEquals(dha.getAuxHashMap().getLgAuxArrInts(), 2);
     assertTrue(hllSketch.isMemory());
@@ -74,14 +73,14 @@ public class DirectAuxHashMapTest {
     byteArray = hllSketch.toUpdatableByteArray();
     WritableMemory wmem2 = WritableMemory.writableWrap(byteArray);
     hllSketch2 = HllSketch.writableWrap(wmem2);
-    //println(hllSketch2.toString(true, true, true, true));
+    println(hllSketch2.toString(true, true, true, true));
     DirectHllArray dha2 = (DirectHllArray) hllSketch2.hllSketchImpl;
     assertEquals(dha2.getAuxHashMap().getLgAuxArrInts(), 2);
     assertEquals(dha2.getAuxHashMap().getAuxCount(), 3);
 
     //Check grow to on-heap
     hllSketch.couponUpdate(HllUtil.pair(10, 15)); //puts it over the edge, 
must grow
-    //println(hllSketch.toString(true, true, true, true));
+    println(hllSketch.toString(true, true, true, true));
     dha = (DirectHllArray) hllSketch.hllSketchImpl;
     assertEquals(dha.getAuxHashMap().getLgAuxArrInts(), 3);
     assertEquals(dha.getAuxHashMap().getAuxCount(), 4);
diff --git 
a/src/test/java/org/apache/datasketches/hll/DirectCouponListTest.java 
b/src/test/java/org/apache/datasketches/hll/DirectCouponListTest.java
index 1b00e030..6da2f05f 100644
--- a/src/test/java/org/apache/datasketches/hll/DirectCouponListTest.java
+++ b/src/test/java/org/apache/datasketches/hll/DirectCouponListTest.java
@@ -25,12 +25,11 @@ import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
-import org.testng.annotations.Test;
-
-import jdk.incubator.foreign.ResourceScope;
+import java.lang.foreign.Arena;
 
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
 
 /**
  * @author Lee Rhodes
@@ -71,7 +70,8 @@ public class DirectCouponListTest {
     //println("DIRECT");
     byte[] barr1;
     WritableMemory wmem;
-    try (ResourceScope scope = (wmem = 
WritableMemory.allocateDirect(bytes)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      wmem = WritableMemory.allocateDirect(bytes, arena);
       hllSketch = new HllSketch(lgConfigK, tgtHllType, wmem);
       assertTrue(hllSketch.isEmpty());
 
diff --git a/src/test/java/org/apache/datasketches/kll/KllItemsSketchTest.java 
b/src/test/java/org/apache/datasketches/kll/KllItemsSketchTest.java
index 9fc74d97..2e6cc1ea 100644
--- a/src/test/java/org/apache/datasketches/kll/KllItemsSketchTest.java
+++ b/src/test/java/org/apache/datasketches/kll/KllItemsSketchTest.java
@@ -599,15 +599,18 @@ public class KllItemsSketchTest {
   @Test
   public void checkIsSameResource() {
     int cap = 128;
-    WritableMemory wmem = WritableMemory.allocate(cap);
+    WritableMemory wmem = WritableMemory.allocate(cap); //heap
     WritableMemory reg1 = wmem.writableRegion(0, 64);
     WritableMemory reg2 = wmem.writableRegion(64, 64);
     assertFalse(reg1 == reg2);
-    assertFalse(reg1.isSameResource(reg2));
+    assertFalse(reg1.isSameResource(reg2)); //same original resource, but 
different offsets
 
     WritableMemory reg3 = wmem.writableRegion(0, 64);
     assertFalse(reg1 == reg3);
-    assertTrue(reg1.isSameResource(reg3));
+    assertTrue(reg1.isSameResource(reg3)); //same original resource, same 
offsets, different views.
+    reg1.putInt(0, -1);
+    assertEquals(-1, reg3.getInt(0)); //proof
+    reg1.putInt(0, 0);
 
     byte[] byteArr1 = KllItemsSketch.newHeapInstance(20, 
Comparator.naturalOrder(), serDe).toByteArray();
     reg1.putByteArray(0, byteArr1, 0, byteArr1.length);
@@ -615,11 +618,11 @@ public class KllItemsSketchTest {
 
     byte[] byteArr2 = KllItemsSketch.newHeapInstance(20, 
Comparator.naturalOrder(), serDe).toByteArray();
     reg2.putByteArray(0, byteArr2, 0, byteArr2.length);
-    assertFalse(sk1.isSameResource(reg2));
+    assertFalse(sk1.isSameResource(reg2)); //same original resource, but 
different offsets
 
     byte[] byteArr3 = KllItemsSketch.newHeapInstance(20, 
Comparator.naturalOrder(), serDe).toByteArray();
     reg3.putByteArray(0, byteArr3, 0, byteArr3.length);
-    assertTrue(sk1.isSameResource(reg3));
+    assertTrue(sk1.isSameResource(reg3)); //same original resource, same 
offsets, different views.
   }
 
   // New added tests specially for KllItemsSketch
diff --git 
a/src/test/java/org/apache/datasketches/quantiles/DebugUnionTest.java 
b/src/test/java/org/apache/datasketches/quantiles/DebugUnionTest.java
index e51be4b2..2b67f977 100644
--- a/src/test/java/org/apache/datasketches/quantiles/DebugUnionTest.java
+++ b/src/test/java/org/apache/datasketches/quantiles/DebugUnionTest.java
@@ -27,7 +27,8 @@ import java.util.HashSet;
 
 import org.testng.annotations.Test;
 
-import jdk.incubator.foreign.ResourceScope;
+import java.lang.foreign.Arena;
+import java.nio.ByteOrder;
 
 import org.apache.datasketches.memory.WritableMemory;
 import org.apache.datasketches.quantilescommon.QuantilesDoublesSketchIterator;
@@ -63,8 +64,8 @@ public class DebugUnionTest {
     DoublesSketch.setRandom(1); //make deterministic for test
     DoublesUnion dUnion;
     DoublesSketch dSketch;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = 
WritableMemory.allocateDirect(10_000_000)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(10_000_000, arena);
       dUnion = DoublesUnion.builder().setMaxK(8).build(wmem);
       for (int s = 0; s < numSketches; s++) { dUnion.union(sketchArr[s]); }
       dSketch = dUnion.getResult(); //result is on heap
diff --git 
a/src/test/java/org/apache/datasketches/quantiles/DirectQuantilesMemoryRequestTest.java
 
b/src/test/java/org/apache/datasketches/quantiles/DirectQuantilesMemoryRequestTest.java
index 5195f418..1c881998 100644
--- 
a/src/test/java/org/apache/datasketches/quantiles/DirectQuantilesMemoryRequestTest.java
+++ 
b/src/test/java/org/apache/datasketches/quantiles/DirectQuantilesMemoryRequestTest.java
@@ -24,6 +24,7 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
+import java.lang.foreign.Arena;
 import java.nio.ByteOrder;
 
 import org.apache.datasketches.memory.DefaultMemoryRequestServer;
@@ -47,7 +48,7 @@ public class DirectQuantilesMemoryRequestTest {
 
     //########## Owning Implementation
     // This part would actually be part of the Memory owning implementation so 
it is faked here
-    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 
Arena.ofConfined());
     WritableMemory wmem2 = wmem;
     println("Initial mem size: " + wmem.getCapacity());
 
@@ -80,7 +81,7 @@ public class DirectQuantilesMemoryRequestTest {
     final int u = 32; // don't need the BB to fill here
     final int initBytes = (4 + (u / 2)) << 3; // not enough to hold everything
 
-    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 
Arena.ofConfined());
     WritableMemory wmem2 = wmem;
     println("Initial mem size: " + wmem.getCapacity());
     final UpdateDoublesSketch usk1 = 
DoublesSketch.builder().setK(k).build(wmem);
@@ -99,7 +100,7 @@ public class DirectQuantilesMemoryRequestTest {
     final int u = (2 * k) - 1; //just to fill the BB
     final int initBytes = ((2 * k) + 4) << 3; //just room for BB
 
-    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 
Arena.ofConfined());
     WritableMemory wmem2 = wmem;
     println("Initial mem size: " + wmem.getCapacity());
     final UpdateDoublesSketch usk1 = 
DoublesSketch.builder().setK(k).build(wmem);
@@ -115,15 +116,28 @@ public class DirectQuantilesMemoryRequestTest {
     assertFalse(wmem2.isAlive());
   }
 
+  @Test
+  public void checkUpdatableStorageBytes() {
+    final int k = 16;
+    final int initBytes = DoublesSketch.getUpdatableStorageBytes(k, 1);
+    println("Predicted Updatable Storage Bytes: " + initBytes);
+    final UpdateDoublesSketch usk1 = DoublesSketch.builder().setK(k).build();
+    usk1.update(1.0);
+    byte[] uarr = usk1.toByteArray();
+    println("Actual Storage Bytes " + uarr.length);
+    assertEquals(initBytes, uarr.length); //64
+  }
+
+
   @Test
   public void checkGrowFromWrappedEmptySketch() {
     final int k = 16;
     final int n = 0;
-    final int initBytes = DoublesSketch.getUpdatableStorageBytes(k, n); //8 
bytes
+    final int initBytes = DoublesSketch.getUpdatableStorageBytes(k, n); 
//empty: 8 bytes
     final UpdateDoublesSketch usk1 = DoublesSketch.builder().setK(k).build();
-    final Memory origSketchMem = Memory.wrap(usk1.toByteArray());
+    final Memory origSketchMem = Memory.wrap(usk1.toByteArray()); //on heap
 
-    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(initBytes, 
Arena.ofConfined()); //off heap
     WritableMemory wmem2 = wmem;
     origSketchMem.copyTo(0, wmem, 0, initBytes);
     UpdateDoublesSketch usk2 = DirectUpdateDoublesSketch.wrapInstance(wmem);
@@ -133,11 +147,11 @@ public class DirectQuantilesMemoryRequestTest {
     assertTrue(usk2.isEmpty());
 
     //update the sketch forcing it to grow on-heap
-    for (int i = 1; i <= 5; i++) { usk2.update(i); }
-    assertEquals(usk2.getN(), 5);
+    usk2.update(1.0);
+    assertEquals(usk2.getN(), 1);
     WritableMemory mem2 = usk2.getMemory();
     assertFalse(wmem.isSameResource(mem2));
-    assertFalse(mem2.isDirect()); //should now be on-heap
+    assertFalse(mem2.isDirect()); //should now be on-heap //TODO
 
     final int expectedSize = COMBINED_BUFFER + ((2 * k) << 3);
     assertEquals(mem2.getCapacity(), expectedSize);
diff --git 
a/src/test/java/org/apache/datasketches/quantiles/DoublesSketchTest.java 
b/src/test/java/org/apache/datasketches/quantiles/DoublesSketchTest.java
index 8cdc7bf7..762cfc05 100644
--- a/src/test/java/org/apache/datasketches/quantiles/DoublesSketchTest.java
+++ b/src/test/java/org/apache/datasketches/quantiles/DoublesSketchTest.java
@@ -34,7 +34,7 @@ import 
org.apache.datasketches.quantilescommon.DoublesSortedViewIterator;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import jdk.incubator.foreign.ResourceScope;
+import java.lang.foreign.Arena;
 
 public class DoublesSketchTest {
 
@@ -141,7 +141,7 @@ public class DoublesSketchTest {
 
   @Test
   public void directSketchShouldMoveOntoHeapEventually() {
-    WritableMemory wmem = WritableMemory.allocateDirect(1000, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(1000, 
Arena.ofConfined());
     WritableMemory wmem2 = wmem;
     UpdateDoublesSketch sketch = DoublesSketch.builder().build(wmem);
     Assert.assertTrue(sketch.isSameResource(wmem));
@@ -155,7 +155,7 @@ public class DoublesSketchTest {
   @Test
   public void directSketchShouldMoveOntoHeapEventually2() {
     int i = 0;
-    WritableMemory wmem = WritableMemory.allocateDirect(50, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(50, 
Arena.ofConfined());
     WritableMemory wmem2 = wmem;
     UpdateDoublesSketch sketch = DoublesSketch.builder().build(wmem);
     Assert.assertTrue(sketch.isSameResource(wmem));
@@ -172,10 +172,8 @@ public class DoublesSketchTest {
 
   @Test
   public void checkEmptyDirect() {
-    WritableMemory wmem ;
-    try (ResourceScope scope = (wmem = WritableMemory.allocateDirect(1000, 1,
-            ByteOrder.nativeOrder(), new 
DefaultMemoryRequestServer())).scope()) {
-
+    try (Arena arena = Arena.ofConfined()) {
+       WritableMemory wmem = WritableMemory.allocateDirect(1000, 
Arena.ofConfined());
       UpdateDoublesSketch sketch = DoublesSketch.builder().build(wmem);
       sketch.toByteArray(); //exercises a specific path
     } catch (final Exception e) {
diff --git 
a/src/test/java/org/apache/datasketches/quantiles/PreambleUtilTest.java 
b/src/test/java/org/apache/datasketches/quantiles/PreambleUtilTest.java
index adf916ef..765d4d03 100644
--- a/src/test/java/org/apache/datasketches/quantiles/PreambleUtilTest.java
+++ b/src/test/java/org/apache/datasketches/quantiles/PreambleUtilTest.java
@@ -37,24 +37,19 @@ import static 
org.apache.datasketches.quantiles.PreambleUtil.insertPreLongs;
 import static org.apache.datasketches.quantiles.PreambleUtil.insertSerVer;
 import static org.testng.Assert.assertEquals;
 
-import java.nio.ByteOrder;
+import java.lang.foreign.Arena;
 
-import org.apache.datasketches.memory.DefaultMemoryRequestServer;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
-import jdk.incubator.foreign.ResourceScope;
-
 public class PreambleUtilTest {
 
   @Test
   public void checkInsertsAndExtracts() {
     final int bytes = 32;
-    WritableMemory offHeapMem;
-    try (ResourceScope scope = (offHeapMem = 
WritableMemory.allocateDirect(bytes, 1,
-            ByteOrder.nativeOrder(), new 
DefaultMemoryRequestServer())).scope()) {
-
+    try (Arena arena = Arena.ofConfined()) {
+        WritableMemory offHeapMem = WritableMemory.allocateDirect(bytes, 
arena);
       final WritableMemory onHeapMem = WritableMemory.writableWrap(new 
byte[bytes]);
 
       onHeapMem.clear();
diff --git a/src/test/java/org/apache/datasketches/theta/CompactSketchTest.java 
b/src/test/java/org/apache/datasketches/theta/CompactSketchTest.java
index e0f79087..cc5be6a8 100644
--- a/src/test/java/org/apache/datasketches/theta/CompactSketchTest.java
+++ b/src/test/java/org/apache/datasketches/theta/CompactSketchTest.java
@@ -32,7 +32,7 @@ import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
-import jdk.incubator.foreign.ResourceScope;
+import java.lang.foreign.Arena;
 
 /**
  * @author Lee Rhodes
@@ -79,8 +79,8 @@ public class CompactSketchTest {
     //Prepare Memory for direct
     int bytes = usk.getCompactBytes(); //for Compact
 
-    WritableMemory directMem;
-    try (ResourceScope scope = (directMem = 
WritableMemory.allocateDirect(bytes)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory directMem = WritableMemory.allocateDirect(bytes, arena);
 
       /**Via CompactSketch.compact**/
       refSk = usk.compact(ordered, directMem);
diff --git 
a/src/test/java/org/apache/datasketches/theta/DirectQuickSelectSketchTest.java 
b/src/test/java/org/apache/datasketches/theta/DirectQuickSelectSketchTest.java
index f36597b7..5f608113 100644
--- 
a/src/test/java/org/apache/datasketches/theta/DirectQuickSelectSketchTest.java
+++ 
b/src/test/java/org/apache/datasketches/theta/DirectQuickSelectSketchTest.java
@@ -38,6 +38,7 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
+import java.lang.foreign.Arena;
 import java.nio.ByteOrder;
 import java.util.Arrays;
 
@@ -52,8 +53,6 @@ import org.apache.datasketches.thetacommon.HashOperations;
 import org.apache.datasketches.thetacommon.ThetaUtil;
 import org.testng.annotations.Test;
 
-import jdk.incubator.foreign.ResourceScope;
-
 /**
  * @author Lee Rhodes
  */
@@ -62,8 +61,8 @@ public class DirectQuickSelectSketchTest {
   @Test//(expectedExceptions = SketchesArgumentException.class)
   public void checkBadSerVer() {
     int k = 512;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+        WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -88,8 +87,8 @@ public class DirectQuickSelectSketchTest {
   @Test
   public void checkConstructorKtooSmall() {
     int k = 8;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+        WritableMemory wmem = makeNativeMemory(k, arena);
       UpdateSketch.builder().setNominalEntries(k).build(wmem);
     } catch (final Exception e) {
       if (e instanceof SketchesArgumentException) {}
@@ -100,8 +99,8 @@ public class DirectQuickSelectSketchTest {
   @Test
   public void checkConstructorMemTooSmall() {
     int k = 16;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k/2)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+        WritableMemory wmem = makeNativeMemory(k/2, arena);
       UpdateSketch.builder().setNominalEntries(k).build(wmem);
     } catch (final Exception e) {
       if (e instanceof SketchesArgumentException) {}
@@ -126,10 +125,8 @@ public class DirectQuickSelectSketchTest {
   public void checkHeapifyMemoryEstimating() {
     int k = 512;
     int u = 2*k; //thus estimating
-
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
-
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
       UpdateSketch sk1 = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       for (int i=0; i<u; i++) { sk1.update(i); }
 
@@ -199,9 +196,8 @@ public class DirectQuickSelectSketchTest {
     int k = 512;
     long seed1 = 1021;
     long seed2 = ThetaUtil.DEFAULT_UPDATE_SEED;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
-
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
       UpdateSketch usk = 
UpdateSketch.builder().setSeed(seed1).setNominalEntries(k).build(wmem);
       byte[] byteArray = usk.toByteArray();
       Memory srcMem = Memory.wrap(byteArray);
@@ -215,8 +211,9 @@ public class DirectQuickSelectSketchTest {
   @Test
   public void checkCorruptLgNomLongs() {
     int k = 16;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
       UpdateSketch.builder().setNominalEntries(k).build(wmem);
       wmem.putByte(LG_NOM_LONGS_BYTE, (byte)2); //corrupt
       Sketch.heapify(wmem, ThetaUtil.DEFAULT_UPDATE_SEED);
@@ -229,8 +226,8 @@ public class DirectQuickSelectSketchTest {
   @Test
   public void checkHeapifyByteArrayExact() {
     int k = 512;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
 
@@ -262,8 +259,8 @@ public class DirectQuickSelectSketchTest {
   public void checkHeapifyByteArrayEstimating() {
     int k = 4096;
     int u = 2*k;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
 
       for (int i=0; i<u; i++) { usk.update(i); }
@@ -291,9 +288,8 @@ public class DirectQuickSelectSketchTest {
   public void checkWrapMemoryEst() {
     int k = 512;
     int u = 2*k; //thus estimating
-
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
       UpdateSketch sk1 = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       for (int i=0; i<u; i++) { sk1.update(i); }
 
@@ -318,8 +314,8 @@ public class DirectQuickSelectSketchTest {
   public void checkDQStoCompactForms() {
     int k = 512;
     int u = 4*k; //thus estimating
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -388,8 +384,8 @@ public class DirectQuickSelectSketchTest {
   @Test
   public void checkDQStoCompactEmptyForms() {
     int k = 512;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
 
@@ -434,8 +430,8 @@ public class DirectQuickSelectSketchTest {
     int k = 4096;
     int u = 2*k;
 
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -455,8 +451,8 @@ public class DirectQuickSelectSketchTest {
     int k = 4096;
     float p = (float)0.5;
 
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setP(p).setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -481,8 +477,8 @@ public class DirectQuickSelectSketchTest {
   @Test
   public void checkErrorBounds() {
     int k = 512;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
 
@@ -517,8 +513,8 @@ public class DirectQuickSelectSketchTest {
     //virgin, p = 1.0
     int k = 1024;
     float p = (float)1.0;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setP(p).setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -557,8 +553,8 @@ public class DirectQuickSelectSketchTest {
   public void checkUpperAndLowerBounds() {
     int k = 512;
     int u = 2*k;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
 
@@ -578,8 +574,8 @@ public class DirectQuickSelectSketchTest {
   public void checkRebuild() {
     int k = 512;
     int u = 4*k;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -607,8 +603,8 @@ public class DirectQuickSelectSketchTest {
   public void checkResetAndStartingSubMultiple() {
     int k = 512;
     int u = 4*k;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -638,8 +634,8 @@ public class DirectQuickSelectSketchTest {
   public void checkExactModeMemoryArr() {
     int k = 4096;
     int u = 4096;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -659,8 +655,8 @@ public class DirectQuickSelectSketchTest {
     int k = 4096;
     int u = 2*k;
 
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -681,8 +677,8 @@ public class DirectQuickSelectSketchTest {
     int u = 2*k;
     int memCapacity = (k << 4) + (Family.QUICKSELECT.getMinPreLongs() << 3);
 
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = 
WritableMemory.allocateDirect(memCapacity)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(memCapacity, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       DirectQuickSelectSketch sk1 = (DirectQuickSelectSketch)usk; //for 
internal checks
@@ -702,8 +698,8 @@ public class DirectQuickSelectSketchTest {
   public void checkConstructReconstructFromMemory() {
     int k = 4096;
     int u = 2*k;
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = makeNativeMemory(k)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+      WritableMemory wmem = makeNativeMemory(k, arena);
 
       UpdateSketch usk = 
UpdateSketch.builder().setNominalEntries(k).build(wmem);
       assertTrue(usk.isEmpty());
@@ -874,7 +870,7 @@ public class DirectQuickSelectSketchTest {
     int u = 2 * k;
     int bytes = Sketches.getMaxUpdateSketchBytes(k);
 
-    WritableMemory wmem = WritableMemory.allocateDirect(bytes / 2, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes / 2, 
Arena.ofConfined());
     WritableMemory wmem2 = wmem;
     UpdateSketch sketch = 
Sketches.updateSketchBuilder().setNominalEntries(k).build(wmem);
     assertTrue(sketch.isSameResource(wmem));
@@ -888,7 +884,7 @@ public class DirectQuickSelectSketchTest {
     int k = 1 << 12;
     int u = 2 * k;
     int bytes = Sketches.getMaxUpdateSketchBytes(k);
-    WritableMemory wmem = WritableMemory.allocateDirect(bytes / 2, 1, 
ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes / 2, 
Arena.ofConfined());
     WritableMemory wmem2 = wmem;
     UpdateSketch sketch = 
Sketches.updateSketchBuilder().setNominalEntries(k).build(wmem);
     for (int i = 0; i < u; i++) { sketch.update(i); }
@@ -929,8 +925,8 @@ public class DirectQuickSelectSketchTest {
     return (k << 4) + (Family.QUICKSELECT.getMinPreLongs() << 3);
   }
 
-  private static WritableMemory makeNativeMemory(int k) {
-    return WritableMemory.allocateDirect(getMaxBytes(k));
+  private static WritableMemory makeNativeMemory(int k, Arena arena) {
+    return WritableMemory.allocateDirect(getMaxBytes(k), arena);
   }
 
 }
diff --git 
a/src/test/java/org/apache/datasketches/theta/HeapifyWrapSerVer1and2Test.java 
b/src/test/java/org/apache/datasketches/theta/HeapifyWrapSerVer1and2Test.java
index 3d4e20fe..44e01c26 100644
--- 
a/src/test/java/org/apache/datasketches/theta/HeapifyWrapSerVer1and2Test.java
+++ 
b/src/test/java/org/apache/datasketches/theta/HeapifyWrapSerVer1and2Test.java
@@ -23,6 +23,8 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
+import java.lang.foreign.Arena;
+
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.apache.datasketches.thetacommon.ThetaUtil;
@@ -285,29 +287,29 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch csk = usk.compact();
 
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
+
 
-    
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
   @Test
@@ -322,28 +324,28 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch csk = usk.compact();
 
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), defaultSeedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
   @Test
@@ -356,30 +358,30 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch cskResult;
     WritableMemory offHeap;
     CompactSketch csk = usk.compact();
- 
+
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
   @Test
@@ -394,28 +396,28 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch csk = usk.compact();
 
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = Sketches.wrapCompactSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
   @Test
@@ -430,28 +432,28 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch csk = usk.compact();
 
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
   @Test
@@ -466,28 +468,28 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch csk = usk.compact();
 
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), defaultSeedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
   @Test
@@ -502,28 +504,28 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch csk = usk.compact();
 
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
   @Test
@@ -538,33 +540,33 @@ public class HeapifyWrapSerVer1and2Test {
     CompactSketch csk = usk.compact();
 
     //SerialVersion3 test
-    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()));
+    offHeap = putOffHeap(Memory.wrap(csk.toByteArray()), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertTrue(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion2 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer2(csk, 
seed), Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
 
     //SerialVersion1 test
-    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk));
+    offHeap = putOffHeap(BackwardConversions.convertSerVer3toSerVer1(csk), 
Arena.ofConfined());
     cskResult = (CompactSketch) Sketches.wrapSketch(offHeap, seed);
     assertEquals(cskResult.getEstimate(), usk.getEstimate());
     assertEquals(cskResult.getSeedHash(), seedHash);
     assertFalse(cskResult.isDirect());
-    if (offHeap.isAlive()) { offHeap.close(); }
+    if (offHeap.isAlive()) { offHeap.getArena().close(); }
   }
 
-  private static WritableMemory putOffHeap(Memory heapMem) {
+  private static WritableMemory putOffHeap(Memory heapMem, Arena arena) {
     final long cap = heapMem.getCapacity();
-    WritableMemory wmem = WritableMemory.allocateDirect(cap);
+    WritableMemory wmem = WritableMemory.allocateDirect(cap, arena);
     heapMem.copyTo(0, wmem, 0, cap);
     return wmem;
   }
diff --git a/src/test/java/org/apache/datasketches/theta/SetOperationTest.java 
b/src/test/java/org/apache/datasketches/theta/SetOperationTest.java
index 0c675f64..ee435074 100644
--- a/src/test/java/org/apache/datasketches/theta/SetOperationTest.java
+++ b/src/test/java/org/apache/datasketches/theta/SetOperationTest.java
@@ -317,19 +317,19 @@ public class SetOperationTest {
   @Test
   public void checkIsSameResource() {
     final int k = 16;
-    final WritableMemory wmem = WritableMemory.writableWrap(new byte[k*16 + 
32]);
-    final Memory roCompactMem = Memory.wrap(new byte[8]);
+    final WritableMemory wmem = WritableMemory.writableWrap(new byte[k*16 + 
32]);//288
+    final WritableMemory emptyMem = WritableMemory.writableWrap(new byte[8]);
     final Union union = 
Sketches.setOperationBuilder().setNominalEntries(k).buildUnion(wmem);
     assertTrue(union.isSameResource(wmem));
-    assertFalse(union.isSameResource(roCompactMem));
+    assertFalse(union.isSameResource(emptyMem));
 
     final Intersection inter = 
Sketches.setOperationBuilder().buildIntersection(wmem);
     assertTrue(inter.isSameResource(wmem));
-    assertFalse(inter.isSameResource(roCompactMem));
+    assertFalse(inter.isSameResource(emptyMem));
 
     final AnotB aNotB = Sketches.setOperationBuilder().buildANotB();
 
-    assertFalse(aNotB.isSameResource(roCompactMem));
+    assertFalse(aNotB.isSameResource(emptyMem));
   }
 
   @Test
diff --git a/src/test/java/org/apache/datasketches/theta/UnionImplTest.java 
b/src/test/java/org/apache/datasketches/theta/UnionImplTest.java
index 35ef0dcc..f7ec2d2e 100644
--- a/src/test/java/org/apache/datasketches/theta/UnionImplTest.java
+++ b/src/test/java/org/apache/datasketches/theta/UnionImplTest.java
@@ -25,6 +25,7 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
+import java.lang.foreign.Arena;
 import java.nio.ByteOrder;
 
 import org.apache.datasketches.common.SketchesArgumentException;
@@ -34,8 +35,6 @@ import org.apache.datasketches.memory.WritableMemory;
 import org.apache.datasketches.thetacommon.ThetaUtil;
 import org.testng.annotations.Test;
 
-import jdk.incubator.foreign.ResourceScope;
-
 public class UnionImplTest {
 
   @Test
@@ -196,14 +195,13 @@ public class UnionImplTest {
     final int k = 1 << 12;
     final int u = 2 * k;
     final int bytes = Sketches.getMaxUpdateSketchBytes(k);
-    ResourceScope scope = ResourceScope.newConfinedScope();
-
-    final WritableMemory wmem = WritableMemory.allocateDirect(bytes / 2, 1, 
scope, ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    final Arena arena = Arena.ofConfined();
+    final WritableMemory wmem = WritableMemory.allocateDirect(bytes / 2, 
arena);
     final WritableMemory wmemA = wmem;
     final UpdateSketch sketch = 
Sketches.updateSketchBuilder().setNominalEntries(k).build(wmem);
     assertTrue(sketch.isSameResource(wmem));
 
-    final WritableMemory wmem2 = WritableMemory.allocateDirect(bytes / 2, 1, 
scope, ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    final WritableMemory wmem2 = WritableMemory.allocateDirect(bytes / 2, 
arena);
     final WritableMemory wmemB = wmem2;
     final Union union = SetOperation.builder().buildUnion(wmem2);
     assertTrue(union.isSameResource(wmem2));
@@ -213,8 +211,9 @@ public class UnionImplTest {
 
     final Union union2 = SetOperation.builder().buildUnion(); //on-heap union
     assertFalse(union2.isSameResource(wmem2));  //obviously not
-    assertFalse(wmemA.isAlive());
-    assertFalse(wmemB.isAlive());
+    assertFalse(wmemB.isAlive()); //closed when DirectQuickSelectSketch 
expanded into heap.
+    assertFalse(wmemA.isAlive()); //closed as part of the same Arena
+
   }
 
   @Test
@@ -236,8 +235,8 @@ public class UnionImplTest {
     final double est1 = sk.getEstimate();
 
     final int bytes = Sketches.getCompactSketchMaxBytes(lgK);
-    WritableMemory wmem;
-    try (ResourceScope scope = (wmem = 
WritableMemory.allocateDirect(bytes)).scope()) {
+    try (Arena arena = Arena.ofConfined()) {
+        WritableMemory wmem = WritableMemory.allocateDirect(bytes, arena);
 
       final CompactSketch csk = sk.compact(true, wmem); //ordered, direct
       final Union union = Sketches.setOperationBuilder().buildUnion();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to