From ac5c19ddbed1ff5905d16a6359ee23b4888c717a Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Fri, 27 Sep 2019 11:22:47 -0400 Subject: Modify drools-applications to use new Lock API Modified code to use new Lock API. Also deleted TargetLock and PolicyGuard, as they are no longer needed. Issue-ID: POLICY-2113 Signed-off-by: Jim Hahn Change-Id: I5bc9b7732f9cfc6056789b2902d9f6f838b560be --- .../eventmanager/ControlLoopEventManager.java | 133 +++++++++++---------- .../eventmanager/ControlLoopOperationManager.java | 24 ++-- .../eventmanager/LockCallbackWorkingMemory.java | 80 +++++++++++++ 3 files changed, 161 insertions(+), 76 deletions(-) create mode 100644 controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/LockCallbackWorkingMemory.java (limited to 'controlloop/common/eventmanager/src/main') diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java index f6cfe5594..6afb08d76 100644 --- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java @@ -58,18 +58,18 @@ import org.onap.policy.controlloop.VirtualControlLoopNotification; import org.onap.policy.controlloop.policy.FinalResult; import org.onap.policy.controlloop.policy.Policy; import org.onap.policy.controlloop.processor.ControlLoopProcessor; +import org.onap.policy.drools.core.lock.Lock; +import org.onap.policy.drools.core.lock.LockCallback; +import org.onap.policy.drools.core.lock.LockImpl; +import org.onap.policy.drools.core.lock.LockState; import org.onap.policy.drools.system.PolicyEngineConstants; -import org.onap.policy.guard.GuardResult; -import org.onap.policy.guard.LockCallback; -import org.onap.policy.guard.PolicyGuard; -import org.onap.policy.guard.PolicyGuard.LockResult; -import org.onap.policy.guard.TargetLock; +import org.onap.policy.drools.utils.Pair; import org.onap.policy.rest.RestManager; import org.onap.policy.so.util.Serialization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ControlLoopEventManager implements LockCallback, Serializable { +public class ControlLoopEventManager implements Serializable { public static final String PROV_STATUS_ACTIVE = "ACTIVE"; private static final String VM_NAME = "VM_NAME"; private static final String VNF_NAME = "VNF_NAME"; @@ -121,7 +121,7 @@ public class ControlLoopEventManager implements LockCallback, Serializable { private LinkedList controlLoopHistory = new LinkedList<>(); private ControlLoopOperationManager currentOperation = null; private ControlLoopOperationManager lastOperationManager = null; - private transient TargetLock targetLock = null; + private transient Lock targetLock = null; private AaiGetVnfResponse vnfResponse = null; private AaiGetVserverResponse vserverResponse = null; private boolean useTargetLock = true; @@ -140,6 +140,12 @@ public class ControlLoopEventManager implements LockCallback, Serializable { requiredAAIKeys.add(VM_NAME); } + /** + * Constructs the object. + * + * @param closedLoopControlName name of the control loop + * @param requestId ID of the request with which this manager is associated + */ public ControlLoopEventManager(String closedLoopControlName, UUID requestId) { this.closedLoopControlName = closedLoopControlName; this.requestId = requestId; @@ -472,9 +478,11 @@ public class ControlLoopEventManager implements LockCallback, Serializable { // this.lastOperationManager = this.currentOperation; this.currentOperation = null; + // - // TODO: Release our lock + // Don't release the lock - it may be re-used by the next operation // + return; } logger.debug("Cannot finish current operation {} does not match given operation {}", @@ -487,77 +495,75 @@ public class ControlLoopEventManager implements LockCallback, Serializable { /** * Obtain a lock for the current operation. * - * @return the lock result + * @param callback call-back to be invoked when the lock state changes + * @return a pair containing the old lock and the new lock, either of which may be null * @throws ControlLoopException if an error occurs */ - public synchronized LockResult lockCurrentOperation() throws ControlLoopException { + public synchronized Pair lockCurrentOperation(LockCallback callback) throws ControlLoopException { // // Sanity check // if (this.currentOperation == null) { throw new ControlLoopException("Do not have a current operation."); } + // - // Not using target locks? Create and return a lock w/o actually locking. + // Release the old lock if it's for a different resource. // - if (!this.useTargetLock) { - TargetLock lock = PolicyGuard.createTargetLock(this.currentOperation.policy.getTarget().getType(), - this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this); - this.targetLock = lock; - return LockResult.createLockResult(GuardResult.LOCK_ACQUIRED, lock); + Lock oldLock = null; + if (this.targetLock != null + && !this.targetLock.getResourceId().equals(this.currentOperation.getTargetEntity())) { + logger.debug("{}: different resource - releasing old lock", getClosedLoopControlName()); + oldLock = this.targetLock; + this.targetLock = null; } + + // keep the lock a little longer than the operation, including retries + int optimeout = Math.max(1, this.currentOperation.getOperationTimeout()); + int nattempts = 1 + Math.max(0, this.currentOperation.getMaxRetries()); + int holdSec = optimeout * nattempts + ADDITIONAL_LOCK_SEC; + // // Have we acquired it already? // if (this.targetLock != null) { - // - // TODO: Make sure the current lock is for the same target. - // Currently, it should be. But in the future it may not. - // - GuardResult result = PolicyGuard.lockTarget(targetLock, - this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC); - return new LockResult<>(result, this.targetLock); + // we have the lock - just extend it + this.targetLock.extend(holdSec, callback); + return new Pair<>(oldLock, null); + + } else if (this.useTargetLock) { + this.targetLock = createRealLock(this.currentOperation.getTargetEntity(), this.onset.getRequestId(), + holdSec, callback); + return new Pair<>(oldLock, this.targetLock); + } else { - // - // Ask the Guard - // - LockResult lockResult = PolicyGuard.lockTarget( - this.currentOperation.policy.getTarget().getType(), this.currentOperation.getTargetEntity(), - this.onset.getRequestId(), this, this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC); - // - // Was it acquired? - // - if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) { - // - // Yes, let's save it - // - this.targetLock = lockResult.getB(); - } - return lockResult; + // Not using target locks - create a lock w/o actually locking. + logger.debug("{}: not using target locking; using pseudo locks", getClosedLoopControlName()); + this.targetLock = createPseudoLock(this.currentOperation.getTargetEntity(), this.onset.getRequestId(), + holdSec, callback); + + // Note: no need to invoke callback, as the lock is already ACTIVE + + return new Pair<>(oldLock, this.targetLock); } } /** - * Release the lock for the current operation. + * Releases the lock for the current operation, deleting it from working memory. * - * @return the target lock + * @return the lock, if the operation was locked, {@code null} otherwise */ - public synchronized TargetLock unlockCurrentOperation() { + public synchronized Lock unlockCurrentOperation() { if (this.targetLock == null) { return null; } - TargetLock returnLock = this.targetLock; + Lock lock = this.targetLock; this.targetLock = null; - // - // if using target locking unlock before returning - // - if (this.useTargetLock) { - PolicyGuard.unlockTarget(returnLock); - } - // always return the old target lock so rules can retract it - return returnLock; + lock.free(); + + return lock; } public enum NewEventStatus { @@ -1032,18 +1038,6 @@ public class ControlLoopEventManager implements LockCallback, Serializable { return enginePropertyValue; } - @Override - public boolean isActive() { - // TODO - return true; - } - - @Override - public boolean releaseLock() { - // TODO - return false; - } - @Override public String toString() { return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestId=" + requestId @@ -1097,4 +1091,17 @@ public class ControlLoopEventManager implements LockCallback, Serializable { } + + // the following methods may be overridden by junit tests + + protected Lock createRealLock(String targetEntity, UUID requestId, int holdSec, LockCallback callback) { + return PolicyEngineConstants.getManager().createLock(targetEntity, requestId.toString(), holdSec, callback, + false); + } + + // note: the "callback" is required, because it will be invoked when lock.extend() is + // invoked + protected Lock createPseudoLock(String targetEntity, UUID requestId, int holdSec, LockCallback callback) { + return new LockImpl(LockState.ACTIVE, targetEntity, requestId.toString(), holdSec, callback); + } } diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java index eb1901937..62bd0c1e9 100644 --- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java @@ -963,7 +963,7 @@ public class ControlLoopOperationManager implements Serializable { // // Check if there were no retries specified // - if (policy.getRetry() == null || policy.getRetry() == 0) { + if (getMaxRetries() < 1) { // // The result is the failure // @@ -972,7 +972,7 @@ public class ControlLoopOperationManager implements Serializable { // // Check retries // - if (this.isRetriesMaxedOut()) { + if (this.attempts > getMaxRetries()) { // // No more attempts allowed, reset // that our actual result is failure due to retries @@ -1016,7 +1016,7 @@ public class ControlLoopOperationManager implements Serializable { // // Check if we have maxed out on retries // - if (this.policy.getRetry() == null || this.policy.getRetry() < 1) { + if (getMaxRetries() < 1) { // // No retries are allowed, so check have we even made // one attempt to execute the operation? @@ -1037,7 +1037,7 @@ public class ControlLoopOperationManager implements Serializable { // // Have we maxed out on retries? // - if (this.attempts > this.policy.getRetry()) { + if (this.attempts > getMaxRetries()) { if (this.policyResult == null) { this.policyResult = PolicyResult.FAILURE_RETRIES; } @@ -1046,15 +1046,13 @@ public class ControlLoopOperationManager implements Serializable { } } - private boolean isRetriesMaxedOut() { - if (policy.getRetry() == null || policy.getRetry() == 0) { - // - // There were NO retries specified, so declare - // this as completed. - // - return (this.attempts > 0); - } - return (this.attempts > policy.getRetry()); + /** + * Gets the maximum number of retries. + * + * @return the maximum number of retries, or {@code 0}, if not specified + */ + public int getMaxRetries() { + return (policy.getRetry() != null ? policy.getRetry() : 0); } private void storeOperationInDataBase() { diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/LockCallbackWorkingMemory.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/LockCallbackWorkingMemory.java new file mode 100644 index 000000000..738d3b922 --- /dev/null +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/LockCallbackWorkingMemory.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop.eventmanager; + +import lombok.Getter; +import org.drools.core.WorkingMemory; +import org.kie.api.runtime.rule.FactHandle; +import org.onap.policy.drools.core.lock.Lock; +import org.onap.policy.drools.core.lock.LockCallback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Lock call-back that updates working memory. + */ +@Getter +public class LockCallbackWorkingMemory implements LockCallback { + private static final Logger logger = LoggerFactory.getLogger(LockCallbackWorkingMemory.class); + + /** + * Name to be logged when the lock is updated. + */ + private final String name; + + /** + * Working memory to be updated when the lock is notified. + */ + private final WorkingMemory workingMemory; + + + /** + * Constructs the object. + * + * @param name name to be logged when the lock is updated + * @param workingMemory working memory to be updated when the lock is notified + */ + public LockCallbackWorkingMemory(String name, WorkingMemory workingMemory) { + this.name = name; + this.workingMemory = workingMemory; + } + + @Override + public void lockAvailable(Lock lock) { + notifySession(lock); + } + + @Override + public void lockUnavailable(Lock lock) { + notifySession(lock); + } + + /** + * Notifies the session that the lock has been updated. + */ + private void notifySession(Lock lock) { + FactHandle fact = workingMemory.getFactHandle(lock); + if (fact != null) { + logger.debug("{}: updating lock={}", name, lock); + workingMemory.update(fact, lock); + } + } +} -- cgit 1.2.3-korg