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

org.redisson.misc.FastRemovalQueue Maven / Gradle / Ivy

Go to download

Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC

There is a newer version: 3.40.2
Show newest version
/**
 * Copyright (c) 2013-2024 Nikita Koksharov
 *
 * 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 org.redisson.misc;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Thread-safe queue with O(1) complexity for removal operation.
 *
 * @author Nikita Koksharov
 *
 * @param  element type
 */
public final class FastRemovalQueue {

    private final Map> index = new ConcurrentHashMap<>();
    private final DoublyLinkedList list = new DoublyLinkedList<>();

    public void add(E element) {
        Node newNode = new Node<>(element);
        if (index.putIfAbsent(element, newNode) == null) {
            list.add(newNode);
        }
    }

    public boolean moveToTail(E element) {
        Node node = index.get(element);
        if (node != null) {
            list.moveToTail(node);
            return true;
        }
        return false;
    }

    public boolean remove(E element) {
        Node node = index.remove(element);
        if (node != null) {
            return list.remove(node);
        }
        return false;
    }

    public int size() {
        return index.size();
    }

    public E poll() {
        Node node = list.removeFirst();
        if (node != null) {
            index.remove(node.value);
            return node.value;
        }
        return null;
    }

    public void clear() {
        index.clear();
        list.clear();
    }

    static class Node {
        private final E value;
        private Node prev;
        private Node next;
        private boolean deleted;

        Node(E value) {
            this.value = value;
        }

        public void setDeleted() {
            deleted = true;
        }

        public boolean isDeleted() {
            return deleted;
        }
    }

    static class DoublyLinkedList {
        private final WrappedLock lock = new WrappedLock();
        private Node head;
        private Node tail;

        DoublyLinkedList() {
        }

        public void clear() {
            lock.execute(() -> {
                head = null;
                tail = null;
            });
        }

        public void add(Node newNode) {
            lock.execute(() -> {
                addNode(newNode);
            });
        }

        private void addNode(Node newNode) {
            Node currentTail = tail;
            tail = newNode;
            if (currentTail == null) {
                head = newNode;
            } else {
                newNode.prev = currentTail;
                currentTail.next = newNode;
            }
        }

        public boolean remove(Node node) {
            Boolean r = lock.execute(() -> {
                if (node.isDeleted()) {
                    return false;
                }

                removeNode(node);
                node.setDeleted();
                return true;
            });
            return Boolean.TRUE.equals(r);
        }

        private void removeNode(Node node) {
            Node prevNode = node.prev;
            Node nextNode = node.next;

            if (prevNode != null) {
                prevNode.next = nextNode;
            } else {
                head = nextNode;
            }

            if (nextNode != null) {
                nextNode.prev = prevNode;
            } else {
                tail = prevNode;
            }
        }

        public void moveToTail(Node node) {
            lock.execute(() -> {
                if (node.isDeleted()) {
                    return;
                }

                removeNode(node);

                node.prev = null;
                node.next = null;
                addNode(node);
            });
        }

        public Node removeFirst() {
            return lock.execute(() -> {
                Node currentHead = head;
                if (head == tail) {
                    head = null;
                    tail = null;
                } else {
                    head = head.next;
                    head.prev = null;
                }
                if (currentHead != null) {
                    currentHead.setDeleted();
                }
                return currentHead;
            });
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy