// Path: src/main/java/org/apache/jdbm/Storage.java
// interface Storage {
// 
//     /**
//      * Bite shift used to calculate page size.
//      * If you want to modify page size, do it here.
//      *
//      *  1<<9 = 512
//      *  1<<10 = 1024
//      *  1<<11 = 2048
//      *  1<<12 = 4096
//      */
//     int PAGE_SIZE_SHIFT = 12;
//     
//     /**
//      * the lenght of single page.
//      * <p>
//      *!!! DO NOT MODIFY THI DIRECTLY !!!
// 
//      */
//     int PAGE_SIZE = 1<< PAGE_SIZE_SHIFT;
// 
// 
//     /**
//      * use 'val & OFFSET_MASK' to quickly get offset within the page;
//      */
//     long OFFSET_MASK = 0xFFFFFFFFFFFFFFFFL >>> (64-Storage.PAGE_SIZE_SHIFT);
// 
// 
//     void write(long pageNumber, ByteBuffer data) throws IOException;
// 
//     ByteBuffer read(long pageNumber) throws IOException;
// 
//     void forceClose() throws IOException;
// 
//     boolean isReadonly();
// 
//     DataInputStream readTransactionLog();
// 
//     void deleteTransactionLog();
// 
//     void sync() throws IOException;
// 
//     DataOutputStream openTransactionLog() throws IOException;
// 
//     void deleteAllFiles() throws IOException;
// }


import java.io.IOException;
import static org.apache.jdbm.Storage.*;
/*******************************************************************************
 * Copyright 2010 Cees De Groot, Alex Boisvert, Jan Kotek
 *
 * Licensed 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.jdbm;



/**
 * This class manages physical row ids, and their data.
 */
final class PhysicalRowIdManager {

    // The file we're talking to and the associated page manager.
    final private PageFile file;
    final private PageManager pageman;
    final PhysicalFreeRowIdManager freeman;
    static final private short DATA_PER_PAGE = (short) (PAGE_SIZE - Magic.DATA_PAGE_O_DATA);
    //caches offset after last allocation. So we dont have to iterate throw page every allocation
    private long cachedLastAllocatedRecordPage = Long.MIN_VALUE;
    private short cachedLastAllocatedRecordOffset = Short.MIN_VALUE;

    /**
     * Creates a new rowid manager using the indicated record file. and page manager.
     */
    PhysicalRowIdManager(PageFile file, PageManager pageManager) throws IOException {
        this.file = file;
        this.pageman = pageManager;
        this.freeman = new PhysicalFreeRowIdManager(file, pageManager);

    }


    /**
     * Inserts a new record. Returns the new physical rowid.
     */
    long insert(final byte[] data, final int start, final int length) throws IOException {
        if (length < 1)
            throw new IllegalArgumentException("Length is <1");
        if (start < 0)
            throw new IllegalArgumentException("negative start");

        long retval = alloc(length);
        write(retval, data, start, length);
        return retval;
    }

    /**
     * Updates an existing record. Returns the possibly changed physical rowid.
     */
    long update(long rowid, final byte[] data, final int start, final int length) throws IOException {
        // fetch the record header
// Path: src/main/java/org/apache/jdbm/Storage.java
// interface Storage {
// 
//     /**
//      * Bite shift used to calculate page size.
//      * If you want to modify page size, do it here.
//      *
//      *  1<<9 = 512
//      *  1<<10 = 1024
//      *  1<<11 = 2048
//      *  1<<12 = 4096
//      */
//     int PAGE_SIZE_SHIFT = 12;
//     
//     /**
//      * the lenght of single page.
//      * <p>
//      *!!! DO NOT MODIFY THI DIRECTLY !!!
// 
//      */
//     int PAGE_SIZE = 1<< PAGE_SIZE_SHIFT;
// 
// 
//     /**
//      * use 'val & OFFSET_MASK' to quickly get offset within the page;
//      */
//     long OFFSET_MASK = 0xFFFFFFFFFFFFFFFFL >>> (64-Storage.PAGE_SIZE_SHIFT);
// 
// 
//     void write(long pageNumber, ByteBuffer data) throws IOException;
// 
//     ByteBuffer read(long pageNumber) throws IOException;
// 
//     void forceClose() throws IOException;
// 
//     boolean isReadonly();
// 
//     DataInputStream readTransactionLog();
// 
//     void deleteTransactionLog();
// 
//     void sync() throws IOException;
// 
//     DataOutputStream openTransactionLog() throws IOException;
// 
//     void deleteAllFiles() throws IOException;
// }


// Path: src/main/java/org/apache/jdbm/PhysicalRowIdManager.java
import java.io.IOException;
import static org.apache.jdbm.Storage.*;

/*******************************************************************************
 * Copyright 2010 Cees De Groot, Alex Boisvert, Jan Kotek
 *
 * Licensed 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.jdbm;



/**
 * This class manages physical row ids, and their data.
 */
final class PhysicalRowIdManager {

    // The file we're talking to and the associated page manager.
    final private PageFile file;
    final private PageManager pageman;
    final PhysicalFreeRowIdManager freeman;
    static final private short DATA_PER_PAGE = (short) (PAGE_SIZE - Magic.DATA_PAGE_O_DATA);
    //caches offset after last allocation. So we dont have to iterate throw page every allocation
    private long cachedLastAllocatedRecordPage = Long.MIN_VALUE;
    private short cachedLastAllocatedRecordOffset = Short.MIN_VALUE;

    /**
     * Creates a new rowid manager using the indicated record file. and page manager.
     */
    PhysicalRowIdManager(PageFile file, PageManager pageManager) throws IOException {
        this.file = file;
        this.pageman = pageManager;
        this.freeman = new PhysicalFreeRowIdManager(file, pageManager);

    }


    /**
     * Inserts a new record. Returns the new physical rowid.
     */
    long insert(final byte[] data, final int start, final int length) throws IOException {
        if (length < 1)
            throw new IllegalArgumentException("Length is <1");
        if (start < 0)
            throw new IllegalArgumentException("negative start");

        long retval = alloc(length);
        write(retval, data, start, length);
        return retval;
    }

    /**
     * Updates an existing record. Returns the possibly changed physical rowid.
     */
    long update(long rowid, final byte[] data, final int start, final int length) throws IOException {
        // fetch the record header
        PageIo page = file.get(rowid>>> Storage.PAGE_SIZE_SHIFT);