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

org.eclipse.persistence.internal.helper.ReadLockManager Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 2020, 2023 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

package org.eclipse.persistence.internal.helper;

import org.eclipse.persistence.internal.helper.type.ReadLockAcquisitionMetadata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

public class ReadLockManager {

    public static final int FIRST_INDEX_OF_COLLECTION = 0;

    /**
     * This vector of read locks is essentially a basket of cache keys (classes that extend concurrency manager) that a
     * specific thread has acquired for reading. We need to create this additional logic in order to be able to reduce
     * the readers count on a cache key whenever
     *
     */
    private final Vector readLocks = new Vector<>(1);

    /**
     * We have seen that the read locks vector we have is very insufficient. We keep it for now due to the tracing code
     * that is making use of it. But we also want to have a new tracing map with a lot more metadata
     */
    private final Map> mapThreadToReadLockAcquisitionMetadata = new HashMap<>();

    /**
     * This is a field that will never be cleared. It will be getting ADDs if any problem is detected when we try remove
     * a read lock from our tracing.
     */
    private final List removeReadLockProblemsDetected = new ArrayList<>();

    /**
     * add a concurrency manager as deferred locks to the DLM
     */
    public synchronized void addReadLock(ConcurrencyManager concurrencyManager) {
        final Thread currentThread = Thread.currentThread();
        final long currentThreadId = currentThread.getId();
        ReadLockAcquisitionMetadata readLockAcquisitionMetadata = ConcurrencyUtil.SINGLETON.createReadLockAcquisitionMetadata(concurrencyManager);

        this.readLocks.add(FIRST_INDEX_OF_COLLECTION, concurrencyManager);
        if(!mapThreadToReadLockAcquisitionMetadata.containsKey(currentThreadId)) {
            List newList = Collections.synchronizedList(new ArrayList<>());
            mapThreadToReadLockAcquisitionMetadata.put(currentThreadId, newList );
        }
        List acquiredReadLocksInCurrentTransactionList = mapThreadToReadLockAcquisitionMetadata.get(currentThreadId);
        acquiredReadLocksInCurrentTransactionList.add(FIRST_INDEX_OF_COLLECTION, readLockAcquisitionMetadata);
    }

    /**
     * During normal operation of the concurrency manager, each time a cache key is decrement in the number of readers,
     * so must the corresponding read lock manager of the thread be told let go of the cache key object acquired for
     * reading.
     *
     * @param concurrencyManager
     *            the concurrency cache key that is about to be decrement in number of readers.
     */
    public synchronized void removeReadLock(ConcurrencyManager concurrencyManager) {
        final Thread currentThread = Thread.currentThread();
        final long currentThreadId = currentThread.getId();
        boolean readLockManagerHasTracingAboutAddedReadLocksForCurrentThread = mapThreadToReadLockAcquisitionMetadata.containsKey(currentThreadId);

        if (!readLockManagerHasTracingAboutAddedReadLocksForCurrentThread) {
            String errorMessage = ConcurrencyUtil.SINGLETON.readLockManagerProblem02ReadLockManageHasNoEntriesForThread(concurrencyManager, currentThreadId);
            removeReadLockProblemsDetected.add(errorMessage);
            return;
        }

        List readLocksAcquiredDuringCurrentThread = mapThreadToReadLockAcquisitionMetadata.get(currentThreadId);
        ReadLockAcquisitionMetadata readLockAquisitionMetadataToRemove = null;
        for (ReadLockAcquisitionMetadata currentReadLockAcquisitionMetadata : readLocksAcquiredDuringCurrentThread) {
            ConcurrencyManager currentCacheKeyObjectToCheck = currentReadLockAcquisitionMetadata.getCacheKeyWhoseNumberOfReadersThreadIsIncrementing();
            boolean dtoToRemoveFound = concurrencyManager.getConcurrencyManagerId() == currentCacheKeyObjectToCheck.getConcurrencyManagerId();
            if (dtoToRemoveFound) {
                readLockAquisitionMetadataToRemove = currentReadLockAcquisitionMetadata;
                break;
            }
        }

        if (readLockAquisitionMetadataToRemove == null) {
            String errorMessage = ConcurrencyUtil.SINGLETON.readLockManagerProblem03ReadLockManageHasNoEntriesForThread(concurrencyManager, currentThreadId);
            removeReadLockProblemsDetected.add(errorMessage);
            return;
        }
        this.readLocks.remove(concurrencyManager);
        readLocksAcquiredDuringCurrentThread.remove(readLockAquisitionMetadataToRemove);

        if (readLocksAcquiredDuringCurrentThread.isEmpty()) {
            mapThreadToReadLockAcquisitionMetadata.remove(currentThreadId);
        }
    }

    /**
     * Return a set of the deferred locks
     */
    public synchronized List getReadLocks() {
        return Collections.unmodifiableList(readLocks);
    }

    /**
     * Allow the concurrency manager to directly pump a message stating that there was a problem while decrementing the
     * number of readers.
     *
     * @param problemDetected
     *            the detected problem
     */
    public synchronized void addRemoveReadLockProblemsDetected(String problemDetected) {
        removeReadLockProblemsDetected.add(problemDetected);
    }

    /** Getter for {@link #mapThreadToReadLockAcquisitionMetadata} */
    public Map> getMapThreadToReadLockAcquisitionMetadata() {
        return mapThreadToReadLockAcquisitionMetadata;
    }

    /** Getter for {@link #removeReadLockProblemsDetected} */
    public List getRemoveReadLockProblemsDetected() {
        return removeReadLockProblemsDetected;
    }

    /**
     * True if the tracing the data on the object has been completely removed. If this is the case it is perfectly fine
     * to remove the read lock manager from from the hash map of Thread To tis ReadLockManager Tracing.
     *
     * @return true if the current read lock manger contains no information about acquired locks that were never
     *         released or any errors detected while attempting to remove a cache key. If there is any error detected or
     *         any read lock acquired in the tracing we definitely do not want this object instance to be thrown out
     *         from our main tracing. It is probably revealing problems in read lock acquisition and released.
     */
    public synchronized boolean isEmpty() {
        return readLocks.isEmpty() && removeReadLockProblemsDetected.isEmpty();
    }

    /**
     * Create a new instance {@link ReadLockManager} that is in all regards
     * equal to the current instance.
     *
     * 

USE CASE:
* This method is meant to be used by algorithms * that want to dump a snapshot of the current state of the system * or to go about doing */ @Override public synchronized ReadLockManager clone() { ReadLockManager clone = new ReadLockManager(); clone.readLocks.addAll(this.readLocks); for (Map.Entry> currentEntry : this.mapThreadToReadLockAcquisitionMetadata.entrySet()) { Long key = currentEntry.getKey(); List value = currentEntry.getValue(); clone.mapThreadToReadLockAcquisitionMetadata.put(key, new ArrayList<>(value)); } clone.removeReadLockProblemsDetected.addAll(this.removeReadLockProblemsDetected); return clone; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy