jext2.DataStructureAccessProvider.java Source code

Java tutorial

Introduction

Here is the source code for jext2.DataStructureAccessProvider.java

Source

/*
 * Copyright (c) 2011 Marcel Lauhoff.
 * 
 * This file is part of jext2.
 * 
 * jext2 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * jext2 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with jext2.  If not, see <http://www.gnu.org/licenses/>.
 */

package jext2;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.text.StrBuilder;

import fusejext2.FuseJExt2;

import jext2.exceptions.JExt2Exception;

public abstract class DataStructureAccessProvider<KEY, VAL> {
    protected Map<KEY, Data> table;

    Logger logger = Filesystem.getLogger();

    protected class Data {
        VAL value;
        long usage = 0;
        private ReentrantLock lock = new ReentrantLock(true);

        public void lock() {
            lock.lock();
        }

        public void unlock() {
            lock.unlock();
        }

        public String toString() {
            if (value instanceof Inode) {
                return "[Inode: " + ((Inode) value).getIno() + " #" + usage + "]";
            } else if (value instanceof DirectoryEntry) {
                return "[DirEntry: " + ((DirectoryEntry) value).getName() + " #" + usage + "]";
            } else {
                return "[" + value.getClass() + " #" + usage + "]";
            }
        }
    }

    private StackTraceElement[] filterStrackTraceForLog(StackTraceElement[] stack) {
        LinkedList<StackTraceElement> interresting = new LinkedList<StackTraceElement>();

        for (StackTraceElement element : stack) {
            if (element.getClassName().contains("jext2"))
                interresting.add(element);
        }

        return interresting.toArray(new StackTraceElement[0]);
    }

    protected void log(String op, String msg) {
        if (logger.isLoggable(Level.FINEST)) {
            StackTraceElement[] fullStack = Thread.currentThread().getStackTrace();
            StackTraceElement[] interrestingStackElements = filterStrackTraceForLog(fullStack);
            ArrayUtils.reverse(interrestingStackElements);

            String strstack = new StrBuilder().appendWithSeparators(interrestingStackElements, "->").toString();

            StringBuilder log = new StringBuilder();
            log.append(" class=");
            log.append(this.getClass().getSimpleName());
            log.append(" op=");
            log.append(op);
            log.append(" msg=");
            log.append(msg);
            log.append(" source=");
            log.append(strstack);

            logger.finest(log.toString());
        }

    }

    protected DataStructureAccessProvider(int initialCapacity) {
        table = new ConcurrentHashMap<KEY, Data>(initialCapacity, 0.75f,
                (int) (Math.ceil(FuseJExt2.numberOfThreads * 1.5f)));
    }

    protected abstract VAL createInstance(KEY key) throws JExt2Exception;

    protected long usageCounter(KEY key) {
        Data ds = getDataStructure(key);
        long usage;

        if (ds == null) {
            log("usageCounter", "key:" + key + " counter:-1");
            return -1;
        } else {
            ds.lock();

            log("usageCounter", "key:" + key + " counter:" + ds.usage);

            if (ds.usage < 0)
                usage = -1;
            else
                usage = ds.usage;

            ds.unlock();
            return usage;
        }
    }

    /**
     * Add new entry. Usage counter is zero
     */
    protected void add(KEY key, VAL value) {
        assert value != null;

        Data ds = new Data();
        ds.lock();
        ds.value = value;

        table.put(key, ds);
        log("add", "key:" + key);
        ds.unlock();
    }

    /**
     * Open the entry. Increases usage counter and creates an instance if necessary
     */
    protected VAL open(KEY key) throws JExt2Exception {
        Data ds = getDataStructure(key);
        VAL result;

        if (ds != null) {
            ds.lock();
            ds.usage += 1;
            result = ds.value;
            ds.unlock();

        } else {
            VAL val = createInstance(key);
            assert val != null;

            ds = new Data();
            ds.lock();
            ds.usage = 1;
            ds.value = val;
            result = val;

            add(key, val);
            ds.unlock();
        }

        assert result != null;

        log("open", ":" + key);
        return result;
    }

    /**
     * Retrieve entry already in table. Increase usage counter
     */
    protected VAL retain(KEY key) {
        Data ds = getDataStructure(key);

        if (ds == null) {
            log("retain", "nosuccess:" + key);
            return null;
        } else {
            ds.lock();
            ds.usage += 1;
            ds.unlock();

            assert ds.usage > 0;
            assert ds.value != null;

            log("retain", "success:" + key);
            return ds.value;
        }
    }

    private Data getDataStructure(KEY key) {
        Data ds = table.get(key);
        return ds;
    }

    /**
     * Retrieve entry already in table. Does not create a new one or change
     * the usage counter
     */
    protected VAL get(KEY key) {
        Data ds = getDataStructure(key);
        VAL result;

        if (ds == null) {
            log("get", "nosuccess:" + key);
            result = null;
        } else {
            ds.lock();
            assert ds.value != null;
            log("get", "success:" + key);
            result = ds.value;
            ds.unlock();
        }
        return result;
    }

    /**
     * Release entry. Decreases usage counter and might remove entry from table
     */
    protected void release(KEY key) {
        release(key, 1);
    }

    protected void release(KEY key, long times) {
        log("release", "key:" + key + " times=" + times);

        Data ds = table.get(key);
        if (ds != null) {
            ds.lock();

            ds.usage -= times;

            if (ds.usage <= 0) {
                table.remove(key);
                log("release", "removed:" + key);

            }
            ds.unlock();
        }
    }

    protected void remove(KEY key) {
        log("remove", "key:" + key);
        table.remove(key);
    }

    public String toString() {
        String s = new StringBuilder().append(this.getClass().getCanonicalName()).append(": ").append(table)
                .toString();
        return s;

    }
}