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

com.hazelcast.map.impl.mapstore.writebehind.CyclicWriteBehindQueue Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2008-2020, Hazelcast, Inc. 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.
 */

package com.hazelcast.map.impl.mapstore.writebehind;

import com.hazelcast.map.impl.mapstore.writebehind.entry.DelayedEntry;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.util.MutableInteger;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static com.hazelcast.util.Preconditions.checkNotNull;

/**
 * Write behind queue impl. backed by a {@link java.util.Deque}.
 * Used when non-write-coalescing mode is on.
 * Intended to use when we need to store all changes on a key.
 */
class CyclicWriteBehindQueue implements WriteBehindQueue {

    private final Deque deque;

    /**
     * Index to fast check existence of a key.
     * Maps: key --> number of keys.
     * 

* Used to determine whether a key is loadable from store. Because there is a possibility that a key * is in {@link WriteBehindQueue} but it is not in {@link com.hazelcast.core.IMap} due to the eviction. * At that point if one tries to get that evicted key, {@link com.hazelcast.core.MapLoader} will * try to load it from store and that may cause data inconsistencies. * * @see WriteBehindStore#loadable(com.hazelcast.nio.serialization.Data) */ private final Map index; public CyclicWriteBehindQueue() { this.deque = new ArrayDeque(); this.index = new HashMap(); } /** * Add this collection to the front of the queue. * * @param collection collection to be added in front of this queue. */ @Override public void addFirst(Collection collection) { for (DelayedEntry entry : collection) { deque.addFirst(entry); } addCountIndex(collection); } @Override public void addLast(DelayedEntry entry) { deque.addLast(entry); addCountIndex(entry); } @Override public DelayedEntry peek() { return deque.peek(); } /** * Removes the first element of this queue instead of searching for it, * implementation of this method is strongly tied with {@link StoreWorker} implementation. * * @param entry element to be removed. * @return true if removed successfully, false otherwise */ @Override public boolean removeFirstOccurrence(DelayedEntry entry) { DelayedEntry removedEntry = deque.pollFirst(); if (removedEntry == null) { return false; } decreaseCountIndex(entry); return true; } /** * Checks whether an item exist in queue or not. * * @param entry item to be checked * @return true if exists, false otherwise */ @Override public boolean contains(DelayedEntry entry) { Data key = (Data) entry.getKey(); return index.containsKey(key); } @Override public int size() { return deque.size(); } @Override public void clear() { deque.clear(); resetCountIndex(); } /** * Removes all available elements from this queue and adds them * to the given collection. * * @param collection all elements to be added to this collection. * @return number of removed items from this queue. */ @Override public int drainTo(Collection collection) { checkNotNull(collection, "collection can not be null"); Iterator iterator = deque.iterator(); while (iterator.hasNext()) { DelayedEntry e = iterator.next(); collection.add(e); iterator.remove(); } resetCountIndex(); return collection.size(); } /** * Returns unmodifiable list representation of this queue. * * @return read-only list representation of this queue. */ @Override public List asList() { return Collections.unmodifiableList(new ArrayList(deque)); } @Override public void filter(IPredicate predicate, Collection collection) { Iterator iterator = deque.iterator(); while (iterator.hasNext()) { DelayedEntry e = iterator.next(); if (predicate.test(e)) { collection.add(e); } else { break; } } } private void addCountIndex(DelayedEntry entry) { Data key = (Data) entry.getKey(); Map index = this.index; MutableInteger count = index.get(key); if (count == null) { count = new MutableInteger(); } count.value++; index.put(key, count); } private void addCountIndex(Collection collection) { for (DelayedEntry entry : collection) { addCountIndex(entry); } } private void decreaseCountIndex(DelayedEntry entry) { Data key = (Data) entry.getKey(); Map index = this.index; MutableInteger count = index.get(key); if (count == null) { return; } count.value--; if (count.value == 0) { index.remove(key); } else { index.put(key, count); } } private void resetCountIndex() { index.clear(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy