public boolean putNewKey(Object keyBase, long keyOffset, int keyLength,
                                 Object valueBase, long valueOffset, int valueLength) {
            assert (!isDefined) : "Can only set value once for a key";
            assert (keyLength % 8 == 0);
            assert (valueLength % 8 == 0);
            assert (longArray != null);


            if (numElements == MAX_CAPACITY
                    // The map could be reused from last spill (because of no enough memory to grow),
                    // then we don't try to grow again if hit the `growthThreshold`.
                    || !canGrowArray && numElements > growthThreshold) {
                return false;
            }

            // Here, we'll copy the data into our data pages. Because we only store a relative offset from
            // the key address instead of storing the absolute address of the value, the key and value
            // must be stored in the same memory page.
            // (8 byte key length) (key) (value)
            final long recordLength = 8 + keyLength + valueLength;
            if (currentPage == null || currentPage.size() - pageCursor < recordLength) {
                if (!acquireNewPage(recordLength + 4L)) {
                    return false;
                }
            }

            // --- Append the key and value data to the current data page --------------------------------
            final Object base = currentPage.getBaseObject();
            long offset = currentPage.getBaseOffset() + pageCursor;
            final long recordOffset = offset;
            Platform.putInt(base, offset, keyLength + valueLength + 4);
            Platform.putInt(base, offset + 4, keyLength);
            offset += 8;
            Platform.copyMemory(keyBase, keyOffset, base, offset, keyLength);
            offset += keyLength;
            Platform.copyMemory(valueBase, valueOffset, base, offset, valueLength);

            // --- Update bookkeeping data structures -----------------------------------------------------
            offset = currentPage.getBaseOffset();
            Platform.putInt(base, offset, Platform.getInt(base, offset) + 1);
            pageCursor += recordLength;
            numElements++;
            final long storedKeyAddress = taskMemoryManager.encodePageNumberAndOffset(
                    currentPage, recordOffset);
            longArray.set(pos * 2, storedKeyAddress);
            longArray.set(pos * 2 + 1, keyHashcode);
            updateAddressesAndSizes(storedKeyAddress);
            isDefined = true;

            if (numElements > growthThreshold && longArray.size() < MAX_CAPACITY) {
                try {
                    growAndRehash();
                } catch (OutOfMemoryError oom) {
                    canGrowArray = false;
                }
            }
            return true;
        }
Store a new key and value. This method may only be called once for a given key; if you want
to update the value associated with a key, then you can directly manipulate the bytes stored
at the value address. The return value indicates whether the put succeeded or whether it
failed because additional memory could not be acquired.
<p>
It is only valid to call this method immediately after calling `lookup()` using the same key.
</p>
<p>
The key and value must be word-aligned (that is, their sizes must multiples of 8).
</p>
<p>
After calling this method, calls to `get[Key|Value]Address()` and `get[Key|Value]Length`
will return information on the data stored by this `putNewKey` call.
</p>
<p>
As an example usage, here's the proper way to store a new key:
</p>
<pre>
  Location loc = map.lookup(keyBase, keyOffset, keyLength);
  if (!loc.isDefined()) {
    if (!loc.putNewKey(keyBase, keyOffset, keyLength, ...)) {
      // handle failure to grow map (by spilling, for example)
    }
  }
</pre>
<p>
Unspecified behavior if the key is not defined.
</p>

@return true if the put() was successful and false if the put() failed because memory could
not be acquired.
indexr-query-opt/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java