All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gridkit.jvmtool.heapdump.io.ByteBufferPageManager Maven / Gradle / Ivy

package org.gridkit.jvmtool.heapdump.io;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ByteBufferPageManager implements PagePool {

    private List resourcePages = new ArrayList();
    private Map allPages = new IdentityHashMap();
    private Set freePages = new LinkedHashSet();
    
    private final long memoryLimit;
    private long memoryUsed;
    private boolean atLimit;

    protected final int resourcePageSize;
    private final int pageSize;
    
    public ByteBufferPageManager(int pageSize, long limit) {
        this(pageSize, pageSize, limit);
    }

    public ByteBufferPageManager(int pageSize, int allocSize, long limit) {
        this.memoryLimit = limit;
        this.resourcePageSize = allocSize;
        this.pageSize = pageSize;
        
        if (pageSize * (resourcePageSize / pageSize) != resourcePageSize) {
            throw new IllegalArgumentException("Alloc size should be divisible by page size");
        }
    }
    
    protected ByteBuffer allocatePage() {
        try {
            return ByteBuffer.allocate(resourcePageSize);
        }
        catch(OutOfMemoryError e) {
            return null;
        }
    }

    @Override
    public int getPageSize() {
        return pageSize;
    }

    @Override
    public boolean hasFreePages() {
        if (freePages.isEmpty()) {
            refill();
        }
        return !freePages.isEmpty();
    }

    private void refill() {
        if (!atLimit && (memoryUsed + resourcePageSize <= memoryLimit)) {
            ByteBuffer bb = allocatePage();
            if (bb == null) {
                atLimit = true;
            }
            else {
                memoryUsed += resourcePageSize;
                
                resourcePages.add(bb);
                int n = resourcePageSize / pageSize;
                for(int i = 0; i != n; ++i) {
                    int offs = i * pageSize;
                    bb.limit(offs + pageSize);
                    bb.position(offs);
                    ByteBuffer sb = bb.slice();
                    BW bw = new BW(sb);
                    freePages.add(bw);
                    allPages.put(sb, bw);
                }
            }
        }
    }

    @Override
    public ByteBuffer accurePage() throws NoMorePagesException {
        if (freePages.isEmpty()) {
            refill();
        }
        if (freePages.isEmpty()) {
            throw new NoMorePagesException();
        }
        Iterator it = freePages.iterator();
        ByteBuffer bb = it.next().pageBuffer;
        it.remove();
        return bb;
    }

    @Override
    public void releasePage(ByteBuffer bb) {
        BW bw = allPages.get(bb);
        if (bw == null) {
            throw new IllegalStateException("Buffer does not belong ot pool");
        }
        freePages.add(bw);
    }
    
    // need to use wrapper to suppress buffer equality
    private static class BW {
        ByteBuffer pageBuffer;
        
        public BW(ByteBuffer bb) {
            pageBuffer = bb;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy