-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lock): support basic distributed lock api (#178)
- Loading branch information
1 parent
9e021bc
commit 3961ef4
Showing
14 changed files
with
1,234 additions
and
4 deletions.
There are no files selected for viewing
102 changes: 102 additions & 0 deletions
102
client-api/src/main/java/io/streamnative/oxia/client/api/AsyncLock.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
* Copyright © 2022-2024 StreamNative Inc. | ||
* | ||
* 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.streamnative.oxia.client.api; | ||
|
||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ExecutorService; | ||
|
||
public interface AsyncLock { | ||
|
||
/** Represents the different status of a lock. */ | ||
enum LockStatus { | ||
INIT, | ||
ACQUIRING, | ||
ACQUIRED, | ||
RELEASING, | ||
RELEASED; | ||
} | ||
|
||
LockStatus getStatus(); | ||
|
||
/** | ||
* Asynchronously acquires the lock. | ||
* | ||
* @return a CompletableFuture that completes when the lock is acquired | ||
*/ | ||
CompletableFuture<Void> lock(); | ||
|
||
/** | ||
* Tries to acquire the lock asynchronously. | ||
* | ||
* @return a CompletableFuture that completes when the lock is acquired or not. The future will | ||
* complete exceptionally with a {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException.LockBusyException} if the lock is | ||
* acquired by others, or with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException.IllegalLockStatusException} if the | ||
* current lock status is not {@link LockStatus#INIT} or {@link LockStatus#RELEASED}. | ||
* Additionally, the future will complete exceptionally with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException} in case of an unknown error. | ||
*/ | ||
CompletableFuture<Void> tryLock(); | ||
|
||
/** | ||
* Asynchronously releases the lock. | ||
* | ||
* @return a CompletableFuture that completes when the lock is acquired or not. The future will | ||
* complete exceptionally with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException.IllegalLockStatusException} if the | ||
* current lock status is {@link LockStatus#INIT}. In the case of an unknown error, the future | ||
* will complete exceptionally with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException}. | ||
*/ | ||
CompletableFuture<Void> unlock(); | ||
|
||
/** | ||
* Asynchronously acquires the lock using a specified ExecutorService. | ||
* | ||
* @param executorService the ExecutorService to use for acquiring the lock | ||
* @return a CompletableFuture that completes when the lock is acquired | ||
*/ | ||
CompletableFuture<Void> lock(ExecutorService executorService); | ||
|
||
/** | ||
* Tries to acquire the lock asynchronously using a specified ExecutorService. | ||
* | ||
* @param executorService the ExecutorService to use for acquiring the lock | ||
* @return a CompletableFuture that completes when the lock is acquired or not. The future will | ||
* complete exceptionally with a {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException.LockBusyException} if the lock is | ||
* acquired by others, or with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException.IllegalLockStatusException} if the | ||
* current lock status is not {@link LockStatus#INIT} or {@link LockStatus#RELEASED}. | ||
* Additionally, the future will complete exceptionally with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException} in case of an unknown error. | ||
*/ | ||
CompletableFuture<Void> tryLock(ExecutorService executorService); | ||
|
||
/** | ||
* Asynchronously releases the lock using a specified ExecutorService. | ||
* | ||
* @param executorService the ExecutorService to use for releasing the lock | ||
* @return a CompletableFuture that completes when the lock is acquired or not. The future will | ||
* complete exceptionally with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException.IllegalLockStatusException} if the | ||
* current lock status is {@link LockStatus#INIT}. In the case of an unknown error, the future | ||
* will complete exceptionally with an {@link | ||
* io.streamnative.oxia.client.api.exceptions.LockException}. | ||
*/ | ||
CompletableFuture<Void> unlock(ExecutorService executorService); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
client-api/src/main/java/io/streamnative/oxia/client/api/LockManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* Copyright © 2022-2024 StreamNative Inc. | ||
* | ||
* 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.streamnative.oxia.client.api; | ||
|
||
import java.io.Closeable; | ||
|
||
public interface LockManager extends Closeable { | ||
|
||
/** | ||
* Gets a lightweight asynchronous lock for the specified key with default backoff options. | ||
* | ||
* @param key the key associated with the lock | ||
* @return an AsyncLock instance for the specified key | ||
*/ | ||
default AsyncLock getLightWeightLock(String key) { | ||
return getLightWeightLock(key, OptionBackoff.DEFAULT); | ||
} | ||
|
||
/** | ||
* Gets a lightweight asynchronous lock for the specified key with custom backoff options. | ||
* | ||
* @param key the key associated with the lock | ||
* @param optionBackoff the backoff options to be used for lock acquisition retries | ||
* @return an AsyncLock instance for the specified key | ||
*/ | ||
AsyncLock getLightWeightLock(String key, OptionBackoff optionBackoff); | ||
} |
24 changes: 24 additions & 0 deletions
24
client-api/src/main/java/io/streamnative/oxia/client/api/OptionAutoRevalidate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright © 2022-2024 StreamNative Inc. | ||
* | ||
* 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.streamnative.oxia.client.api; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
public record OptionAutoRevalidate(boolean enabled, long initDelay, long delay, TimeUnit unit) { | ||
|
||
public static final OptionAutoRevalidate DEFAULT = | ||
new OptionAutoRevalidate(true, 15, 15, TimeUnit.MINUTES); | ||
} |
25 changes: 25 additions & 0 deletions
25
client-api/src/main/java/io/streamnative/oxia/client/api/OptionBackoff.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright © 2022-2024 StreamNative Inc. | ||
* | ||
* 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.streamnative.oxia.client.api; | ||
|
||
import static java.util.concurrent.TimeUnit.MILLISECONDS; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
public record OptionBackoff( | ||
long initDelay, TimeUnit initDelayUnit, long maxDelay, TimeUnit maxDelayUnit) { | ||
public static OptionBackoff DEFAULT = new OptionBackoff(10, MILLISECONDS, 500, MILLISECONDS); | ||
} |
71 changes: 71 additions & 0 deletions
71
client-api/src/main/java/io/streamnative/oxia/client/api/exceptions/LockException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright © 2022-2024 StreamNative Inc. | ||
* | ||
* 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.streamnative.oxia.client.api.exceptions; | ||
|
||
import io.streamnative.oxia.client.api.AsyncLock; | ||
import lombok.Getter; | ||
|
||
public sealed class LockException extends OxiaException { | ||
LockException(String message) { | ||
super(message); | ||
} | ||
|
||
LockException(Throwable cause) { | ||
super("", cause); | ||
} | ||
|
||
public static LockException wrap(Throwable ex) { | ||
if (ex instanceof LockException) { | ||
return (LockException) ex; | ||
} else { | ||
return new LockException(ex); | ||
} | ||
} | ||
|
||
public static final class LockBusyException extends LockException { | ||
public LockBusyException() { | ||
super("lock busy"); | ||
} | ||
} | ||
|
||
public static final class AcquireTimeoutException extends LockException { | ||
public AcquireTimeoutException() { | ||
super("lock acquire timeout"); | ||
} | ||
} | ||
|
||
@Getter | ||
public static final class IllegalLockStatusException extends LockException { | ||
private final AsyncLock.LockStatus expect; | ||
private final AsyncLock.LockStatus actual; | ||
|
||
public IllegalLockStatusException(AsyncLock.LockStatus expect, AsyncLock.LockStatus actual) { | ||
super("illegal lock status. expect: " + expect.name() + ", actual: " + actual.name()); | ||
this.expect = expect; | ||
this.actual = actual; | ||
} | ||
} | ||
|
||
@Getter | ||
public static final class UnknownLockStatusException extends LockException { | ||
private final AsyncLock.LockStatus actual; | ||
|
||
public UnknownLockStatusException(AsyncLock.LockStatus actual) { | ||
super("unknown lock status: " + actual.name()); | ||
this.actual = actual; | ||
} | ||
} | ||
} |
Oops, something went wrong.