This is an automated email from the ASF dual-hosted git repository. xyuanlu pushed a commit to branch metaclient in repository https://gitbox.apache.org/repos/asf/helix.git
commit 447c7e48e4f3f9ef988f0a65fbda1ba09a332a71 Author: Marcos Rico Peng <[email protected]> AuthorDate: Mon Apr 10 15:31:31 2023 -0400 Implementing LockInfo Object for LockClient in MetaClient Implementing LockInfo Object for LockClient in MetaClient --------- Co-authored-by: mapeng <[email protected]> --- .../LockInfo.java => datamodel/DataRecord.java} | 13 +- .../helix/metaclient/recipes/lock/LockInfo.java | 229 +++++++++++++++++++++ .../metaclient/recipes/lock/LockInfoTest.java | 70 +++++++ 3 files changed, 310 insertions(+), 2 deletions(-) diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/recipes/lock/LockInfo.java b/meta-client/src/main/java/org/apache/helix/metaclient/datamodel/DataRecord.java similarity index 69% copy from meta-client/src/main/java/org/apache/helix/metaclient/recipes/lock/LockInfo.java copy to meta-client/src/main/java/org/apache/helix/metaclient/datamodel/DataRecord.java index 85006cdf1..00fe44118 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/recipes/lock/LockInfo.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/datamodel/DataRecord.java @@ -1,4 +1,4 @@ -package org.apache.helix.metaclient.recipes.lock; +package org.apache.helix.metaclient.datamodel; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -19,6 +19,15 @@ package org.apache.helix.metaclient.recipes.lock; * under the License. */ +import org.apache.helix.zookeeper.datamodel.ZNRecord; -public class LockInfo { +/** + * The DataRecord object is a wrapper around ZNRecord. + * TODO: Create an interface to decouple DataRecord and have a pluggable record store. + */ +public class DataRecord extends ZNRecord { + public DataRecord(String znodeId) { + super(znodeId); + } } + diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/recipes/lock/LockInfo.java b/meta-client/src/main/java/org/apache/helix/metaclient/recipes/lock/LockInfo.java index 85006cdf1..d579427a9 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/recipes/lock/LockInfo.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/recipes/lock/LockInfo.java @@ -19,6 +19,235 @@ package org.apache.helix.metaclient.recipes.lock; * under the License. */ +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import org.apache.helix.metaclient.datamodel.DataRecord; + + +/** + * This structure represents a Lock node information, implemented using DataRecord + */ public class LockInfo { + + // Default values for each attribute if there are no current values set by user + public static final String DEFAULT_LOCK_ID_TEXT = ""; + public static final String DEFAULT_OWNER_ID_TEXT = ""; + public static final String DEFAULT_CLIENT_ID_TEXT = ""; + public static final String DEFAULT_CLIENT_DATA = ""; + public static final long DEFAULT_GRANTED_AT_LONG = -1L; + public static final long DEFAULT_LAST_RENEWED_AT_LONG = -1L; + public static final Duration DEFAULT_TIMEOUT_DURATION = Duration.ofMillis(-1L); + private static final String ZNODE_ID = "LOCK"; + private final DataRecord _record; + + /** + * The keys to lock information + */ + public enum LockInfoAttribute { + LOCK_ID, + OWNER_ID, + CLIENT_ID, + CLIENT_DATA, + GRANTED_AT, + LAST_RENEWED_AT, + TIMEOUT + } + + /** + * Initialize a default LockInfo instance + */ + private LockInfo() { + _record = new DataRecord(ZNODE_ID); + setLockInfoFields(DEFAULT_LOCK_ID_TEXT, DEFAULT_OWNER_ID_TEXT, DEFAULT_CLIENT_ID_TEXT, DEFAULT_CLIENT_DATA, DEFAULT_GRANTED_AT_LONG, + DEFAULT_LAST_RENEWED_AT_LONG, DEFAULT_TIMEOUT_DURATION); + } + + /** + * Initialize a LockInfo with a ZNRecord, set all info fields to default data + * @param dataRecord The dataRecord contains lock node data that used to initialize the LockInfo + */ + public LockInfo(DataRecord dataRecord) { + this(); + if (dataRecord != null) { + String lockId = dataRecord.getSimpleField(LockInfoAttribute.LOCK_ID.name()); + String ownerId = dataRecord.getSimpleField(LockInfoAttribute.OWNER_ID.name()); + String clientId = dataRecord.getSimpleField(LockInfoAttribute.CLIENT_ID.name()); + String clientData = dataRecord.getSimpleField(LockInfoAttribute.CLIENT_DATA.name()); + long grantTime = dataRecord.getLongField(LockInfoAttribute.GRANTED_AT.name(), DEFAULT_GRANTED_AT_LONG); + long lastRenewalTime = + dataRecord.getLongField(LockInfoAttribute.LAST_RENEWED_AT.name(), DEFAULT_LAST_RENEWED_AT_LONG); + long timeout = dataRecord.getLongField(LockInfoAttribute.TIMEOUT.name(), DEFAULT_TIMEOUT_DURATION.toMillis()); + Duration duration = Duration.of(timeout, ChronoUnit.MILLIS); + setLockInfoFields(lockId,ownerId, clientId, clientData, grantTime, + lastRenewalTime, duration); + } + } + + /** + * Initialize a LockInfo with data for each field, set all null info fields to default data + * @param lockId value of LOCK_ID attribute + * @param ownerId value of OWNER_ID attribute + * @param clientId value of CLIENT_ID attribute + * @param clientData value of CLIENT_DATA attribute + * @param grantTime the time the lock was granted + * @param lastRenewalTime the last time the lock was renewed + * @param timeout value of TIMEOUT attribute + */ + public LockInfo(String lockId, String ownerId, String clientId, + String clientData, long grantTime, long lastRenewalTime, Duration timeout) { + this(); + setLockInfoFields(lockId, ownerId, clientId, clientData, grantTime, lastRenewalTime, timeout); + } + + /** + * Set each field of lock info to user provided values if the values + * are not null, null values are set to default values + * @param lockId value of LOCK_ID attribute + * @param ownerId value of OWNER_ID attribute + * @param clientId value of CLIENT_ID attribute + * @param clientData value of CLIENT_DATA attribute + * @param grantTime the time the lock was granted + * @param lastRenewalTime the last time the lock was renewed + * @param timeout value of TIMEOUT attribute + */ + private void setLockInfoFields(String lockId, String ownerId, String clientId, String clientData, long grantTime, long lastRenewalTime, + Duration timeout) { + setLockId(lockId); + setOwnerId(ownerId); + setClientId(clientId); + setClientData(clientData); + setGrantedAt(grantTime); + setLastRenewedAt(lastRenewalTime); + setTimeout(timeout); + } + + /** + * Set the value for LOCK_ID attribute of the lock + * @param lockId Is a unique identifier representing the lock. + * It is created by the lockClient and a new one is created for each time the lock is acquired. + */ + public void setLockId(String lockId) { + _record.setSimpleField(LockInfoAttribute.LOCK_ID.name(), lockId == null ? DEFAULT_LOCK_ID_TEXT : lockId); + } + + /** + * Get the value for OWNER_ID attribute of the lock + * @param ownerId Represents the initiator of the lock, created by the client. + * A service can have multiple ownerId's as long as acquire and release are called + * by the same owner. + */ + public void setOwnerId(String ownerId) { + _record.setSimpleField(LockInfoAttribute.OWNER_ID.name(), ownerId == null ? DEFAULT_OWNER_ID_TEXT : ownerId); + } + + /** + * Get the value for CLIENT_ID attribute of the lock + * @param clientId Unique identifier that represents who will get the lock (the client). + */ + public void setClientId(String clientId) { + _record.setSimpleField(LockInfoAttribute.CLIENT_ID.name(), clientId == null ? DEFAULT_CLIENT_ID_TEXT : clientId); + } + + /** + * Get the value for CLIENT_DATA attribute of the lock + * @param clientData String representing the serialized data object + */ + public void setClientData(String clientData) { + _record.setSimpleField(LockInfoAttribute.CLIENT_DATA.name(), clientData == null ? DEFAULT_CLIENT_DATA : clientData); + } + + /** + * Get the value for GRANTED_AT attribute of the lock + * @param grantTime Long representing the time at which the lock was granted + */ + public void setGrantedAt(Long grantTime) { + _record.setLongField(LockInfoAttribute.GRANTED_AT.name(), grantTime); + } + + /** + * Get the value for LAST_RENEWED_AT attribute of the lock + * @param lastRenewalTime Long representing the time at which the lock was last renewed + */ + public void setLastRenewedAt(Long lastRenewalTime) { + _record.setLongField(LockInfoAttribute.LAST_RENEWED_AT.name(), lastRenewalTime); + } + + /** + * Get the value for TIMEOUT attribute of the lock + * @param timeout Duration object representing the duration of a lock. + */ + public void setTimeout(Duration timeout) { + // Always store the timeout value in milliseconds for the sake of simplicity + _record.setLongField(LockInfoAttribute.TIMEOUT.name(), timeout.toMillis()); + } + + /** + * Get the value for OWNER_ID attribute of the lock + * @return the owner id of the lock, {@link #DEFAULT_OWNER_ID_TEXT} if there is no owner id set + */ + public String getOwnerId() { + return _record.getStringField(LockInfoAttribute.OWNER_ID.name(), DEFAULT_OWNER_ID_TEXT); + } + + /** + * Get the value for CLIENT_ID attribute of the lock + * @return the client id of the lock, {@link #DEFAULT_CLIENT_ID_TEXT} if there is no client id set + */ + public String getClientId() { + return _record.getStringField(LockInfoAttribute.CLIENT_ID.name(), DEFAULT_CLIENT_ID_TEXT); + } + + /** + * Get the value for LOCK_ID attribute of the lock + * @return the id of the lock, {@link #DEFAULT_LOCK_ID_TEXT} if there is no lock id set + */ + public String getLockId() { + return _record.getStringField(LockInfoAttribute.LOCK_ID.name(), DEFAULT_LOCK_ID_TEXT); + } + + /** + * Get value of CLIENT_DATA + * @return the string representing the serialized client data, {@link #DEFAULT_CLIENT_DATA} + * if there is no client data set. + */ + public String getClientData() { + return _record.getStringField(LockInfoAttribute.CLIENT_DATA.name(), DEFAULT_CLIENT_DATA); + } + + /** + * Get the time the lock was granted on + * @return the grant time of the lock, {@link #DEFAULT_GRANTED_AT_LONG} + * if there is no grant time set + */ + public Long getGrantedAt() { + return _record.getLongField(LockInfoAttribute.GRANTED_AT.name(), DEFAULT_GRANTED_AT_LONG); + } + + /** + * Get the last time the lock was renewed + * @return the last renewal time of the lock, {@link #DEFAULT_LAST_RENEWED_AT_LONG} + * if there is no renewal time set + */ + public Long getLastRenewedAt() { + return _record + .getLongField(LockInfoAttribute.LAST_RENEWED_AT.name(), DEFAULT_LAST_RENEWED_AT_LONG); + } + + /** + * Get the value for TIMEOUT attribute of the lock + * @return the expiring time of the lock, {@link #DEFAULT_TIMEOUT_DURATION} if there is no timeout set + */ + public Duration getTimeout() { + long timeout = _record.getLongField(LockInfoAttribute.TIMEOUT.name(), DEFAULT_TIMEOUT_DURATION.toMillis()); + return Duration.of(timeout, ChronoUnit.MILLIS); + } + + /** + * Get the underlying DataRecord in a LockInfo + * @return lock information contained in a DataRecord + */ + public DataRecord getRecord() { + return _record; + } } diff --git a/meta-client/src/test/java/org/apache/helix/metaclient/recipes/lock/LockInfoTest.java b/meta-client/src/test/java/org/apache/helix/metaclient/recipes/lock/LockInfoTest.java new file mode 100644 index 000000000..c7f132174 --- /dev/null +++ b/meta-client/src/test/java/org/apache/helix/metaclient/recipes/lock/LockInfoTest.java @@ -0,0 +1,70 @@ +package org.apache.helix.metaclient.recipes.lock; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + + +import java.time.Duration; + +import org.apache.helix.metaclient.datamodel.DataRecord; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class LockInfoTest { + private static final String OWNER_ID = "urn:li:principal:UNKNOWN"; + private static final String CLIENT_ID = "test_client_id"; + private static final String CLIENT_DATA = "client_data"; + private static final String LOCK_ID = "794c8a4c-c14b-4c23-b83f-4e1147fc6978"; + private static final long GRANT_TIME = System.currentTimeMillis(); + private static final long LAST_RENEWAL_TIME = System.currentTimeMillis(); + private static final Duration TIMEOUT = Duration.ofMillis(100000); + + public static final String DEFAULT_LOCK_ID_TEXT = ""; + public static final String DEFAULT_OWNER_ID_TEXT = ""; + public static final String DEFAULT_CLIENT_ID_TEXT = ""; + public static final String DEFAULT_CLIENT_DATA = ""; + public static final long DEFAULT_GRANTED_AT_LONG = -1L; + public static final long DEFAULT_LAST_RENEWED_AT_LONG = -1L; + public static final Duration DEFAULT_TIMEOUT_DURATION = Duration.ofMillis(-1L); + + @Test + public void testLockInfo() { + LockInfo lockInfo = + new LockInfo(LOCK_ID, OWNER_ID, CLIENT_ID, CLIENT_DATA, GRANT_TIME, + LAST_RENEWAL_TIME, TIMEOUT); + + Assert.assertEquals(LOCK_ID, lockInfo.getLockId()); + Assert.assertEquals(OWNER_ID, lockInfo.getOwnerId()); + Assert.assertEquals(CLIENT_ID, lockInfo.getClientId()); + Assert.assertEquals(CLIENT_DATA, lockInfo.getClientData()); + Assert.assertEquals(GRANT_TIME, (long) lockInfo.getGrantedAt()); + Assert.assertEquals(LAST_RENEWAL_TIME, (long) lockInfo.getLastRenewedAt()); + Assert.assertEquals(TIMEOUT, lockInfo.getTimeout()); + + DataRecord dataRecord = new DataRecord("dataRecord"); + LockInfo lockInfo1 = new LockInfo(dataRecord); + Assert.assertEquals(DEFAULT_LOCK_ID_TEXT, lockInfo1.getLockId()); + Assert.assertEquals(DEFAULT_OWNER_ID_TEXT, lockInfo1.getOwnerId()); + Assert.assertEquals(DEFAULT_CLIENT_ID_TEXT, lockInfo1.getClientId()); + Assert.assertEquals(DEFAULT_CLIENT_DATA, lockInfo1.getClientData()); + Assert.assertEquals(DEFAULT_GRANTED_AT_LONG, (long) lockInfo1.getGrantedAt()); + Assert.assertEquals(DEFAULT_LAST_RENEWED_AT_LONG, (long) lockInfo1.getLastRenewedAt()); + Assert.assertEquals(DEFAULT_TIMEOUT_DURATION, lockInfo1.getTimeout()); + } +}
