/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.github.geophile.erdo.segmentfilemanager.pagememorymanager; import com.github.geophile.erdo.Configuration; import java.nio.ByteBuffer; import java.util.IdentityHashMap; // Memory is organized into Slabs, each wrapping a ByteBuffer. public class SubAllocatingPageMemoryManager extends PageMemoryManager { // PageMemoryManager interface @Override public ByteBuffer takePageBuffer() { ByteBuffer pageBuffer; for (int s = 0; s < slabs.length; s++) { pageBuffer = slabs[s].takePageBuffer(); if (pageBuffer != null) { observer.takePageBuffer(s, pageBuffer.arrayOffset()); return pageBuffer; } } throw new PageMemoryManagerException("No pages available!"); } @Override public void returnPageBuffer(ByteBuffer pageBuffer) { Slab slab = slabMap.get(pageBuffer.array()); assert slab != null; observer.returnPageBuffer(slab.slabId(), pageBuffer.arrayOffset()); slab.returnPageBuffer(pageBuffer); } public void reset() { slabMap.clear(); for (int s = 0; s < slabs.length; s++) { slabs[s].clear(); } } // SubAllocatingPageMemoryManager interface public SubAllocatingPageMemoryManager(Configuration configuration) { this(configuration, DEFAULT_OBSERVER); } public SubAllocatingPageMemoryManager(Configuration configuration, Observer observer) { super(configuration); this.observer = observer; int maxSlabSize = configuration.diskCacheSlabSizeBytes(); int nSlabs = (int) ((cacheSize + maxSlabSize - 1) / maxSlabSize); this.slabs = new Slab[nSlabs]; this.slabMap = new IdentityHashMap<>(); long remaining = (cacheSize / pageSize) * pageSize; for (int slabId = 0; slabId < nSlabs; slabId++) { int slabSize = (int) Math.min(remaining, maxSlabSize); Slab slab = new Slab(slabId, slabSize, pageSize); this.slabs[slabId] = slab; this.slabMap.put(slab.byteArray(), slab); remaining -= slabSize; } } // Class state private static Observer DEFAULT_OBSERVER = new Observer() { @Override public void takePageBuffer(int slabId, int offset) { } @Override public void returnPageBuffer(int slabId, int offset) { } }; // Object state private final Observer observer; private final Slab[] slabs; private final IdentityHashMap<byte[], Slab> slabMap; // Inner classes public interface Observer { void takePageBuffer(int slabId, int offset); void returnPageBuffer(int slabId, int offset); } }