
io.atomix.concurrent.internal.LockState Maven / Gradle / Ivy
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.atomix.concurrent.internal;
import io.atomix.catalyst.concurrent.Scheduled;
import io.atomix.copycat.server.Commit;
import io.atomix.copycat.server.session.ServerSession;
import io.atomix.copycat.server.session.SessionListener;
import io.atomix.resource.ResourceStateMachine;
import java.time.Duration;
import java.util.*;
/**
* Lock state machine.
*
* @author Jordan Halterman
*/
public class LockState extends ResourceStateMachine implements SessionListener {
private Commit lock;
private final Queue> queue = new ArrayDeque<>();
private final Map timers = new HashMap<>();
public LockState(Properties config) {
super(config);
}
@Override
public void close(ServerSession session) {
if (lock != null && lock.session().id() == session.id()) {
lock.close();
lock = queue.poll();
while (lock != null) {
Scheduled timer = timers.remove(lock.index());
if (timer != null)
timer.cancel();
if (lock.session().state() == ServerSession.State.EXPIRED || lock.session().state() == ServerSession.State.CLOSED) {
lock = queue.poll();
} else {
lock.session().publish("lock", new LockCommands.LockEvent(lock.operation().id(), lock.index()));
break;
}
}
}
}
/**
* Applies a lock commit.
*/
public void lock(Commit commit) {
if (lock == null) {
lock = commit;
commit.session().publish("lock", new LockCommands.LockEvent(commit.operation().id(), commit.index()));
} else if (commit.operation().timeout() == 0) {
try {
commit.session().publish("fail", new LockCommands.LockEvent(commit.operation().id(), commit.index()));
} finally {
commit.close();
}
} else {
queue.add(commit);
if (commit.operation().timeout() > 0) {
timers.put(commit.index(), executor.schedule(Duration.ofMillis(commit.operation().timeout()), () -> {
try {
timers.remove(commit.index());
queue.remove(commit);
if (commit.session().state().active()) {
commit.session().publish("fail", new LockCommands.LockEvent(commit.operation().id(), commit.index()));
}
} finally {
commit.close();
}
}));
}
}
}
/**
* Applies an unlock commit.
*/
public void unlock(Commit commit) {
try {
if (lock != null) {
if (!lock.session().equals(commit.session()))
return;
lock.close();
lock = queue.poll();
while (lock != null) {
Scheduled timer = timers.remove(lock.index());
if (timer != null)
timer.cancel();
if (lock.session().state() == ServerSession.State.EXPIRED || lock.session().state() == ServerSession.State.CLOSED) {
lock = queue.poll();
} else {
lock.session().publish("lock", new LockCommands.LockEvent(lock.operation().id(), lock.index()));
break;
}
}
}
} finally {
commit.close();
}
}
@Override
public void delete() {
if (lock != null) {
lock.close();
}
queue.forEach(Commit::close);
queue.clear();
timers.values().forEach(Scheduled::cancel);
timers.clear();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy