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

net.java.truevfs.kernel.impl.LockController Maven / Gradle / Ivy

/*
 * Copyright © 2005 - 2021 Schlichtherle IT Services.
 * All rights reserved. Use is subject to license terms.
 */
package net.java.truevfs.kernel.impl;

import net.java.truecommons.cio.*;
import net.java.truecommons.io.DecoratingInputStream;
import net.java.truecommons.io.DecoratingOutputStream;
import net.java.truecommons.io.DecoratingSeekableChannel;
import net.java.truecommons.shed.BitField;
import net.java.truevfs.kernel.spec.*;

import javax.annotation.concurrent.ThreadSafe;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.SeekableByteChannel;
import java.util.Map;
import java.util.Optional;

import static net.java.truevfs.kernel.impl.LockingStrategy.*;

/**
 * Provides read/write locking for multi-threaded access by its clients.
 * 

* This controller is a barrier for {@link net.java.truevfs.kernel.impl.NeedsWriteLockException}s: * Whenever the decorated controller chain throws a {@code NeedsWriteLockException}, the read lock gets released before * the write lock gets acquired and the operation gets retried. *

* This controller is also an emitter of and a barrier for * {@link net.java.truevfs.kernel.impl.NeedsLockRetryException}s: * If a lock can't get immediately acquired, then a {@code NeedsLockRetryException} gets thrown. * This will unwind the stack of federated file systems until the {@code LockController} for the first visited file * system is found. * This controller will then pause the current thread for a small random amount of milliseconds before retrying the * operation. * * @author Christian Schlichtherle * @see LockingStrategy */ @ThreadSafe abstract class LockController implements DelegatingArchiveController { @Override public Optional node(BitField options, FsNodeName name) throws IOException { return timedReadOrWriteLocked(new Op, IOException>() { @Override public Optional call() throws IOException { return getController().node(options, name); } }); } @Override public void checkAccess(BitField options, FsNodeName name, BitField types) throws IOException { timedReadOrWriteLocked(new Op() { @Override public Void call() throws IOException { getController().checkAccess(options, name, types); return null; } }); } @Override public void setReadOnly(BitField options, FsNodeName name) throws IOException { timedLocked.using(writeLock()).call(new Op() { @Override public Void call() throws IOException { getController().setReadOnly(options, name); return null; } }); } @Override public boolean setTime(BitField options, FsNodeName name, Map times) throws IOException { return timedLocked.using(writeLock()).call(new Op() { @Override public Boolean call() throws IOException { return getController().setTime(options, name, times); } }); } @Override public boolean setTime(BitField options, FsNodeName name, BitField types, long time) throws IOException { return timedLocked.using(writeLock()).call(new Op() { @Override public Boolean call() throws IOException { return getController().setTime(options, name, types, time); } }); } @Override public InputSocket input(BitField options, FsNodeName name) { return new AbstractInputSocket() { final InputSocket socket = getController().input(options, name); @Override public Entry target() throws IOException { return fastLocked.using(writeLock()).call(new Op() { @Override public Entry call() throws IOException { return socket.target(); } }); } @Override public InputStream stream(OutputSocket peer) throws IOException { return timedLocked.using(writeLock()).call(new Op() { @Override public InputStream call() throws IOException { return new LockInputStream(socket.stream(peer)); } }); } @Override public SeekableByteChannel channel(OutputSocket peer) throws IOException { return timedLocked.using(writeLock()).call(new Op() { @Override public SeekableByteChannel call() throws IOException { return new LockSeekableChannel(socket.channel(peer)); } }); } }; } @Override public OutputSocket output(BitField options, FsNodeName name, Optional template) { return new AbstractOutputSocket() { final OutputSocket socket = getController().output(options, name, template); @Override public Entry target() throws IOException { return fastLocked.using(writeLock()).call(new Op() { @Override public Entry call() throws IOException { return socket.target(); } }); } @Override public OutputStream stream(InputSocket peer) throws IOException { return timedLocked.using(writeLock()).call(new Op() { @Override public OutputStream call() throws IOException { return new LockOutputStream(socket.stream(peer)); } }); } @Override public SeekableByteChannel channel(InputSocket peer) throws IOException { return timedLocked.using(writeLock()).call(new Op() { @Override public SeekableByteChannel call() throws IOException { return new LockSeekableChannel(socket.channel(peer)); } }); } }; } @Override public void make(BitField options, FsNodeName name, Entry.Type type, Optional template) throws IOException { timedLocked.using(writeLock()).call(new Op() { @Override public Void call() throws IOException { getController().make(options, name, type, template); return null; } }); } @Override public void unlink(BitField options, FsNodeName name) throws IOException { timedLocked.using(writeLock()).call(new Op() { @Override public Void call() throws IOException { getController().unlink(options, name); return null; } }); } @Override public void sync(BitField options) throws FsSyncException { timedLocked.using(writeLock()).call(new Op() { @Override public Void call() throws FsSyncException { getController().sync(options); return null; } }); } private T timedReadOrWriteLocked(final Op op) throws IOException { try { return timedLocked.using(readLock()).call(op); } catch (NeedsWriteLockException e) { if (readLockedByCurrentThread()) { throw e; } return timedLocked.using(writeLock()).call(op); } } private final class LockInputStream extends DecoratingInputStream { LockInputStream(InputStream in) { super(in); } @Override public void close() throws IOException { deadLocked.using(writeLock()).call(new Op() { @Override public Void call() throws IOException { in.close(); return null; } }); } } private final class LockOutputStream extends DecoratingOutputStream { LockOutputStream(OutputStream out) { super(out); } @Override public void close() throws IOException { deadLocked.using(writeLock()).call(new Op() { @Override public Void call() throws IOException { out.close(); return null; } }); } } private final class LockSeekableChannel extends DecoratingSeekableChannel { LockSeekableChannel(SeekableByteChannel channel) { super(channel); } @Override public void close() throws IOException { deadLocked.using(writeLock()).call(new Op() { @Override public Void call() throws IOException { channel.close(); return null; } }); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy