* @param foundAt
     *            The keyblock before which this record will be inserted
     */
    int putValue(Key key, ValueHelper valueHelper, int foundAt, boolean postSplit) {
        if (Debug.ENABLED) {
            assertVerify();
        }

        boolean exactMatch = (foundAt & EXACT_MASK) > 0;
        int p = foundAt & P_MASK;

        if (exactMatch) {
            return replaceValue(key, valueHelper, p);
        } else {
            int length;
            if (isIndexPage()) {
                length = 0;
            } else {
                length = valueHelper.requiredLength(_bytes, 0, -1);
            }

            int depth = (foundAt & DEPTH_MASK) >>> DEPTH_SHIFT;
            boolean fixupSuccessor = (foundAt & FIXUP_MASK) > 0;
            byte[] kbytes = key.getEncodedBytes();

            int ebcNew;
            int ebcSuccessor;
            int kbSuccessor = 0;
            int delta = 0;
            int successorTail = 0;
            int successorTailBlock = 0;
            int successorTailSize = 0;
            int free1 = 0;
            int free2 = 0;
            if (fixupSuccessor) {
                kbSuccessor = getInt(p);
                ebcNew = decodeKeyBlockEbc(kbSuccessor);
                ebcSuccessor = depth;
                delta = ebcSuccessor - ebcNew;
                successorTail = decodeKeyBlockTail(kbSuccessor);
                successorTailBlock = getInt(successorTail);
                successorTailSize = decodeTailBlockSize(successorTailBlock);
                free1 = (successorTailSize + ~TAILBLOCK_MASK) & TAILBLOCK_MASK;
                free2 = (successorTailSize - delta + ~TAILBLOCK_MASK) & TAILBLOCK_MASK;

            } else {
                ebcSuccessor = 0;
                ebcNew = depth;
            }
            int klength = key.getEncodedSize() - ebcNew - 1;
            int newTailSize = klength + length + _tailHeaderSize;

            if (getKeyCount() >= _pool.getMaxKeys() || !willFit(newTailSize + KEYBLOCK_LENGTH - (free1 - free2))) {
                Debug.$assert0.t(!postSplit);
                return -1;
            }

            //
            // Possibly increase the ebc value of the successor
            // (Needs to be done first so that computation of new run value
            // is correct.
            //
            if (fixupSuccessor && ebcNew != ebcSuccessor) {
                int successorKeyLength = decodeTailBlockKLength(successorTailBlock);
                int successorDb = getByte(successorTail + _tailHeaderSize + delta - 1);

                // Write updated successor tail block
                putInt(successorTail, encodeTailBlock(successorTailSize - delta, successorKeyLength - delta));

                System.arraycopy(_bytes, successorTail + _tailHeaderSize + delta, _bytes, successorTail
                        + _tailHeaderSize, successorTailSize - _tailHeaderSize - delta);

                if (free2 < free1) {
                    deallocTail(successorTail + free2, free1 - free2);
                }

                kbSuccessor = encodeKeyBlock(ebcSuccessor, successorDb, successorTail);

                putInt(p, kbSuccessor);
            }
            int dbNew = kbytes[ebcNew] & 0xFF;
            //
            // Allocate space for the new tail block
            //
            setKeyBlockEnd(getKeyBlockEnd() + KEYBLOCK_LENGTH);

            int newTail = allocTail(newTailSize);
            if (newTail == -1) {
                _keyBlockEnd -= KEYBLOCK_LENGTH;
                repack();
                setKeyBlockEnd(getKeyBlockEnd() + KEYBLOCK_LENGTH);
                newTail = allocTail(newTailSize);
                if (newTail == -1) {
                    _persistit.fatal("Insufficient space to insert record in " + this + " at =" + p, null);
                }
            }

            // Shift the subsequent key blocks
            System.arraycopy(_bytes, p, _bytes, p + KEYBLOCK_LENGTH, _keyBlockEnd - p - KEYBLOCK_LENGTH);

            // Write new key block
            int newKeyBlock = encodeKeyBlock(ebcNew, dbNew, newTail);
            putInt(p, newKeyBlock);

            // Write new tail block
            putInt(newTail, encodeTailBlock(newTailSize, klength));

            Debug.$assert0.t(klength >= 0 && ebcNew + 1 >= 0 && ebcNew + 1 + klength <= kbytes.length
                    && newTail + _tailHeaderSize >= 0 && newTail + _tailHeaderSize + klength <= _bytes.length);

            System.arraycopy(kbytes, ebcNew + 1, _bytes, newTail + _tailHeaderSize, klength);

            if (isIndexPage()) {
                int pointer = (int) valueHelper.getPointerValue();

                Debug.$assert0.t(p + KEYBLOCK_LENGTH < _keyBlockEnd ? pointer > 0 : true);
                putInt(newTail + TAILBLOCK_POINTER, pointer);
            } else {
                int storedLength = valueHelper.storeVersion(_bytes, newTail + _tailHeaderSize + klength, -1,
                        _bytes.length); // TODO limit
                incCountIfMvv(_bytes, newTail + _tailHeaderSize + klength, storedLength & MVV.STORE_LENGTH_MASK);
            }
            //
            // Correct not to call getFastIndex()
            //
            _fastIndex.insertKeyBlock(p, ebcSuccessor, fixupSuccessor);
            bumpGeneration();

            if (p > KEY_BLOCK_START) {
                Debug.$assert0.t(adjacentKeyCheck(p - KEYBLOCK_LENGTH));
            }
            if (p + KEYBLOCK_LENGTH < _keyBlockEnd) {
                Debug.$assert0.t(adjacentKeyCheck(p));
            }

            if (Debug.ENABLED) {
                assertVerify();
            }

            return p | (key.getEncodedSize() << DEPTH_SHIFT) | EXACT_MASK;
        }
    }