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

de.schlichtherle.truezip.fs.FsDefaultManager Maven / Gradle / Ivy

/*
 * Copyright (C) 2005-2015 Schlichtherle IT Services.
 * All rights reserved. Use is subject to license terms.
 */
package de.schlichtherle.truezip.fs;

import de.schlichtherle.truezip.util.BitField;
import de.schlichtherle.truezip.util.Link;
import de.schlichtherle.truezip.util.Link.Type;
import static de.schlichtherle.truezip.util.Link.Type.STRONG;
import static de.schlichtherle.truezip.util.Link.Type.WEAK;
import static de.schlichtherle.truezip.util.Links.getTarget;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import javax.annotation.concurrent.ThreadSafe;

/**
 * The default implementation of a file system manager.
 *
 * @author Christian Schlichtherle
 */
@ThreadSafe
public final class FsDefaultManager extends FsManager {

    /**
     * The map of all schedulers for composite file system controllers,
     * keyed by the mount point of their respective file system model.
     */
    private final Map>> controllers
            = new WeakHashMap>>();

    private final Type optionalScheduleType;

    private final ReadLock readLock;
    private final WriteLock writeLock;

    public FsDefaultManager() {
        this(WEAK);
    }

    /** Solely provided for unit testing. */
    FsDefaultManager(final Type optionalScheduleType) {
        assert null != optionalScheduleType;
        this.optionalScheduleType = optionalScheduleType;
        final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        this.readLock = lock.readLock();
        this.writeLock = lock.writeLock();
    }

    @Override
    public  FsController newController(
            final FsArchiveDriver driver,
            final FsModel model,
            final FsController parent) {
        assert !(model instanceof FsLockModel);
        // HC SVNT DRACONES!
        return new FsFalsePositiveArchiveController(
                    new FsFinalizeController(
                        driver.newController(model, parent)));
    }

    @Override
    public FsController getController(
            final FsMountPoint mp,
            final FsCompositeDriver d) {
        try {
            readLock.lock();
            try {
                return getController0(mp, d);
            } finally {
                readLock.unlock();
            }
        } catch (final FsNeedsWriteLockException ex) {
            writeLock.lock();
            try {
                return getController0(mp, d);
            } finally {
                writeLock.unlock();
            }
        }
    }

    private FsController getController0(
            final FsMountPoint mp,
            final FsCompositeDriver d) {
        FsController c = getTarget(controllers.get(mp));
        if (null != c) return c;
        if (!writeLock.isHeldByCurrentThread())
            throw FsNeedsWriteLockException.get();
        final FsMountPoint pmp = mp.getParent();
        final FsController p = null == pmp ? null : getController0(pmp, d);
        final ManagedModel m = new ManagedModel(mp, null == p ? null : p.getModel());
        c = d.newController(this, m, p);
        m.init(c);
        return c;
    }

    /**
     * A model which schedules its controller for
     * {@link #sync(BitField) synchronization} by "observing" its
     * {@code touched} property.
     * Extending its sub-class to register for updates to the {@code touched}
     * property is simpler, faster and requires a smaller memory footprint than
     * the alternative observer pattern.
     */
    private final class ManagedModel extends FsModel {
        FsController controller;
        volatile boolean mounted;

        ManagedModel(FsMountPoint mountPoint, FsModel parent) {
            super(mountPoint, parent);
        }

        void init(final FsController controller) {
            assert null != controller;
            assert !mounted;
            this.controller = controller;
            schedule(false);
        }

        @Override
        public boolean isMounted() {
            return mounted;
        }

        /**
         * Schedules the file system controller for synchronization according
         * to the given mount status.
         */
        @Override
        public void setMounted(final boolean mounted) {
            writeLock.lock();
            try {
                if (this.mounted != mounted) {
                    if (mounted)
                        FsSyncShutdownHook.register(FsDefaultManager.this);
                    schedule(mounted);
                    this.mounted = mounted;
                }
            } finally {
                writeLock.unlock();
            }
        }

        @SuppressWarnings("unchecked")
        void schedule(boolean mandatory) {
            assert(writeLock.isHeldByCurrentThread());
            final Type type = mandatory ? STRONG : optionalScheduleType;
            controllers.put(getMountPoint(),
                            (Link>) type.newLink(controller));
        }
    } // ManagedModel

    @Override
    public int getSize() {
        readLock.lock();
        try {
            return controllers.size();
        } finally {
            readLock.unlock();
        }
    }

    @Override
    public Iterator> iterator() {
        return sortedControllers().iterator();
    }

    private Set> sortedControllers() {
        readLock.lock();
        try {
            final Set> snapshot
                    = new TreeSet>(ReverseControllerComparator.INSTANCE);
            for (final Link> link : controllers.values()) {
                final FsController controller = getTarget(link);
                if (null != controller)
                    snapshot.add(controller);
            }
            return snapshot;
        } finally {
            readLock.unlock();
        }
    }

    @Override
    public void sync(BitField options) throws FsSyncException {
        FsSyncShutdownHook.cancel();
        super.sync(options);
    }

    /**
     * Orders file system controllers so that all file systems appear before
     * any of their parent file systems.
     */
    private static final class ReverseControllerComparator
    implements Comparator> {
        static final ReverseControllerComparator INSTANCE
                = new ReverseControllerComparator();

        @Override
        public int compare(FsController o1, FsController o2) {
            return o2.getModel().getMountPoint().toHierarchicalUri()
                    .compareTo(o1.getModel().getMountPoint().toHierarchicalUri());
        }
    } // ReverseControllerComparator
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy