You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ratis.apache.org by lj...@apache.org on 2020/01/08 06:43:00 UTC

[incubator-ratis] branch master updated: RATIS-781. Add ResourceSemaphore#acquire(int... permits) api. Contributed by Lokesh Jain.

This is an automated email from the ASF dual-hosted git repository.

ljain pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-ratis.git


The following commit(s) were added to refs/heads/master by this push:
     new 92dac6e  RATIS-781. Add ResourceSemaphore#acquire(int... permits) api. Contributed by Lokesh Jain.
92dac6e is described below

commit 92dac6e764266e1fe741d021619bf7ea7f88846a
Author: Lokesh Jain <lj...@apache.org>
AuthorDate: Wed Jan 8 12:12:30 2020 +0530

    RATIS-781. Add ResourceSemaphore#acquire(int... permits) api. Contributed by Lokesh Jain.
---
 .../org/apache/ratis/util/ResourceSemaphore.java   | 21 ++++++++++--
 .../test/java/org/apache/ratis/RaftTestUtil.java   | 22 +++++++++++++
 .../apache/ratis/util/TestResourceSemaphore.java   | 38 ++++++++++++++++++++--
 3 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/ratis-common/src/main/java/org/apache/ratis/util/ResourceSemaphore.java b/ratis-common/src/main/java/org/apache/ratis/util/ResourceSemaphore.java
index f16f5bd..8d89826 100644
--- a/ratis-common/src/main/java/org/apache/ratis/util/ResourceSemaphore.java
+++ b/ratis-common/src/main/java/org/apache/ratis/util/ResourceSemaphore.java
@@ -92,7 +92,7 @@ public class ResourceSemaphore extends Semaphore {
     private final List<ResourceSemaphore> resources;
 
     public Group(int... limits) {
-      Preconditions.assertTrue(limits.length > 1, () -> "limits.length = " + limits.length + " < 2");
+      Preconditions.assertTrue(limits.length >= 1, () -> "limits is empty");
       final List<ResourceSemaphore> list = new ArrayList<>(limits.length);
       for(int limit : limits) {
         list.add(new ResourceSemaphore(limit));
@@ -108,7 +108,7 @@ public class ResourceSemaphore extends Semaphore {
       return resources.get(i);
     }
 
-    protected boolean tryAcquire(int... permits) {
+    public boolean tryAcquire(int... permits) {
       Preconditions.assertTrue(permits.length == resources.size(),
           () -> "items.length = " + permits.length + " != resources.size() = " + resources.size());
       int i = 0;
@@ -129,6 +129,23 @@ public class ResourceSemaphore extends Semaphore {
       return false;
     }
 
+    public void acquire(int... permits) throws InterruptedException {
+      Preconditions.assertTrue(permits.length == resources.size(),
+          () -> "items.length = " + permits.length + " != resources.size() = "
+              + resources.size());
+      int i = 0;
+      try {
+        for (; i < permits.length; i++) {
+          resources.get(i).acquire(permits[i]);
+        }
+      } catch (Throwable t) {
+        for (; --i >= 0;) {
+          resources.get(i).release(permits[i]);
+        }
+        throw t;
+      }
+    }
+
     protected void release(int... permits) {
       for(int i = resources.size() - 1; i >= 0; i--) {
         resources.get(i).release(permits[i]);
diff --git a/ratis-server/src/test/java/org/apache/ratis/RaftTestUtil.java b/ratis-server/src/test/java/org/apache/ratis/RaftTestUtil.java
index 8339972..9df76cc 100644
--- a/ratis-server/src/test/java/org/apache/ratis/RaftTestUtil.java
+++ b/ratis-server/src/test/java/org/apache/ratis/RaftTestUtil.java
@@ -34,6 +34,7 @@ import org.apache.ratis.server.impl.RaftServerImpl;
 import org.apache.ratis.server.impl.ServerProtoUtils;
 import org.apache.ratis.server.protocol.TermIndex;
 import org.apache.ratis.server.raftlog.RaftLog;
+import org.apache.ratis.thirdparty.com.google.common.base.Preconditions;
 import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
 import org.apache.ratis.util.AutoCloseableLock;
 import org.apache.ratis.util.CollectionUtils;
@@ -55,6 +56,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.BooleanSupplier;
@@ -62,6 +64,7 @@ import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.IntSupplier;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 
 
 public interface RaftTestUtil {
@@ -119,6 +122,25 @@ public interface RaftTestUtil {
     return leader.getId();
   }
 
+  static void waitFor(Supplier<Boolean> check, int checkEveryMillis,
+      int waitForMillis) throws TimeoutException, InterruptedException {
+    Preconditions.checkNotNull(check);
+    Preconditions.checkArgument(waitForMillis >= checkEveryMillis);
+
+    long st = System.currentTimeMillis();
+    boolean result = check.get();
+
+    while (!result && (System.currentTimeMillis() - st < waitForMillis)) {
+      Thread.sleep(checkEveryMillis);
+      result = check.get();
+    }
+
+    if (!result) {
+      throw new TimeoutException("Timed out waiting for condition.");
+    }
+  }
+
+
   static boolean logEntriesContains(RaftLog log, SimpleMessage... expectedMessages) {
     return logEntriesContains(log, 0L, Long.MAX_VALUE, expectedMessages);
   }
diff --git a/ratis-test/src/test/java/org/apache/ratis/util/TestResourceSemaphore.java b/ratis-test/src/test/java/org/apache/ratis/util/TestResourceSemaphore.java
index 8b210ea..ac658d4 100644
--- a/ratis-test/src/test/java/org/apache/ratis/util/TestResourceSemaphore.java
+++ b/ratis-test/src/test/java/org/apache/ratis/util/TestResourceSemaphore.java
@@ -18,12 +18,15 @@
 package org.apache.ratis.util;
 
 import org.apache.ratis.BaseTest;
+import org.apache.ratis.RaftTestUtil;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.concurrent.TimeoutException;
+
 public class TestResourceSemaphore extends BaseTest {
-  @Test(timeout = 1000)
-  public void testGroup() {
+  @Test(timeout = 5000)
+  public void testGroup() throws InterruptedException, TimeoutException {
     final ResourceSemaphore.Group g = new ResourceSemaphore.Group(3, 1);
 
     assertUsed(g, 0, 0);
@@ -47,6 +50,27 @@ public class TestResourceSemaphore extends BaseTest {
     g.release(0, 0);
     assertUsed(g, 0, 0);
 
+    g.acquire(1, 1);
+    assertUsed(g, 1, 1);
+    final Thread t = new Thread(acquire(g, 1, 1));
+    t.start();
+    RaftTestUtil.waitFor(() -> Thread.State.WAITING == t.getState(), 100, 1000);
+    assertUsed(g, 2, 1);
+
+    g.release(0, 1);
+    RaftTestUtil.waitFor(() -> Thread.State.TERMINATED == t.getState(), 100, 1000);
+    assertUsed(g, 2, 1);
+
+    final Thread t1 = new Thread(acquire(g, 1, 1));
+    t1.start();
+    RaftTestUtil.waitFor(() -> Thread.State.WAITING == t1.getState(), 100, 1000);
+    assertUsed(g, 3, 1);
+
+    t1.interrupt();
+    RaftTestUtil.waitFor(() -> Thread.State.TERMINATED == t1.getState(), 100, 1000);
+    assertUsed(g, 2, 1);
+    g.release(2, 1);
+
     testFailureCase("release over limit-0", () -> g.release(1, 0), IllegalStateException.class);
     testFailureCase("release over limit-1", () -> g.release(0, 1), IllegalStateException.class);
   }
@@ -62,4 +86,14 @@ public class TestResourceSemaphore extends BaseTest {
     final boolean computed = g.tryAcquire(permits);
     Assert.assertEquals(expected, computed);
   }
+
+  static Runnable acquire(ResourceSemaphore.Group g, int... permits) {
+    return () -> {
+      try {
+        g.acquire(permits);
+      } catch (InterruptedException e) {
+        e.printStackTrace();
+      }
+    };
+  }
 }