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

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