class StorageDirect implements Engine {

    @Override
    public void compact(){
        if(readOnly) throw new IllegalAccessError();
        if(index.getFile()==null) throw new UnsupportedOperationException("compact not supported for memory storage yet");
        lock.writeLock().lock();
        try{
            //create secondary files for compaction
            //TODO RAF
            //TODO memory based stores
            final File indexFile = index.getFile();
            final File physFile = phys.getFile();
            final boolean isRaf = index instanceof Volume.RandomAccessFileVol;
            Volume.Factory fab = Volume.fileFactory(false, isRaf, new File(indexFile+".compact"));
            StorageDirect store2 = new StorageDirect(fab);

            //transfer stack of free recids
            for(long recid =longStackTake(RECID_FREE_INDEX_SLOTS);
                recid!=0; recid=longStackTake(RECID_FREE_INDEX_SLOTS)){
                store2.longStackPut(recid, RECID_FREE_INDEX_SLOTS);
            }

            //iterate over recids and transfer physical records
            final long indexSize = index.getLong(RECID_CURRENT_INDEX_FILE_SIZE*8)/8;


            store2.lock.writeLock().lock();
            for(long recid = INDEX_OFFSET_START; recid<indexSize;recid++){
                //read data from first store
                long physOffset = index.getLong(recid*8);
                long physSize = physOffset >>> 48;
                //TODO linked records larger then 64KB
                physOffset = physOffset & PHYS_OFFSET_MASK;

                //write index value into second storage
                store2.index.ensureAvailable(recid*8+8);

                //get free place in second store, and write data there
                if(physSize!=0){
                    DataInput2 in = phys.getDataInput(physOffset, (int)physSize);
                    long physOffset2 =
                            store2.freePhysRecTake((int)physSize) & PHYS_OFFSET_MASK;

                    store2.phys.ensureAvailable((physOffset2 & PHYS_OFFSET_MASK)+physSize);
                    synchronized (in.buf){
                        //copy directly from buffer
                        in.buf.limit((int) (in.pos+physSize));
                        in.buf.position(in.pos);
                        store2.phys.putData(physOffset2, in.buf);
                    }
                    store2.index.putLong(recid*8, (physSize<<48)|physOffset2);
                }else{
                    //just write zeroes
                    store2.index.putLong(recid*8, 0);
                }
            }

            store2.index.putLong(RECID_CURRENT_INDEX_FILE_SIZE*8, indexSize*8);

            File indexFile2 = store2.index.getFile();
            File physFile2 = store2.phys.getFile();
            store2.lock.writeLock().unlock();
            store2.close();

            long time = System.currentTimeMillis();
            File indexFile_ = new File(indexFile.getPath()+"_"+time+"_orig");
            File physFile_ = new File(physFile.getPath()+"_"+time+"_orig");

            index.close();
            phys.close();
            if(!indexFile.renameTo(indexFile_))throw new InternalError();
            if(!physFile.renameTo(physFile_))throw new InternalError();

            if(!indexFile2.renameTo(indexFile))throw new InternalError();
            //TODO process may fail in middle of rename, analyze sequence and add recovery
            if(!physFile2.renameTo(physFile))throw new InternalError();

            indexFile_.delete();
            physFile_.delete();

            Volume.Factory fac2 = Volume.fileFactory(false, isRaf, indexFile);
            index = fac2.createIndexVolume();
            phys = fac2.createPhysVolume();

        }catch(IOException e){
            throw new IOError(e);
        }finally {
            lock.writeLock().unlock();
        }
    }

    public  StorageDirect(Volume.Factory volFac, boolean appendOnly,
                   boolean deleteFilesOnExit, boolean failOnWrongHeader, boolean readOnly);
    public  StorageDirect(Volume.Factory volFac);

}