com.hazelcast.map.impl.mapstore.writebehind.CoalescedWriteBehindQueue Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2015, 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static com.hazelcast.util.CollectionUtil.isEmpty;
import static com.hazelcast.util.Preconditions.checkNotNull;
/**
* A write-behind queue which supports write coalescing.
*/
class CoalescedWriteBehindQueue implements WriteBehindQueue {
protected Map map;
public CoalescedWriteBehindQueue() {
map = new LinkedHashMap();
}
@Override
public void addFirst(Collection collection) {
if (isEmpty(collection)) {
return;
}
int expectedCapacity = map.size() + collection.size();
Map newMap = createMapWithExpectedCapacity(expectedCapacity);
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
DelayedEntry next = iterator.next();
newMap.put((Data) next.getKey(), next);
}
newMap.putAll(map);
map = newMap;
}
@Override
public void addLast(DelayedEntry delayedEntry) {
if (delayedEntry == null) {
return;
}
calculateStoreTime(delayedEntry);
Data key = (Data) delayedEntry.getKey();
map.put(key, delayedEntry);
}
/**
* Removes the first occurrence of the specified element in this queue
* when searching it by starting from the head of this queue.
*
* @param entry element to be removed.
* @return true
if removed successfully, false
otherwise
*/
@Override
public boolean removeFirstOccurrence(DelayedEntry entry) {
Data key = (Data) entry.getKey();
Object value = entry.getValue();
DelayedEntry delayedEntry = map.get(key);
if (delayedEntry == null) {
return false;
}
Object existingValue = delayedEntry.getValue();
if (existingValue == value) {
map.remove(key);
return true;
}
return false;
}
@Override
public boolean contains(DelayedEntry entry) {
//noinspection SuspiciousMethodCalls
return map.containsKey(entry.getKey());
}
@Override
public int size() {
return map.size();
}
@Override
public void clear() {
map.clear();
}
@Override
public int drainTo(Collection collection) {
checkNotNull(collection, "collection can not be null");
Collection delayedEntries = map.values();
for (DelayedEntry delayedEntry : delayedEntries) {
collection.add(delayedEntry);
}
map.clear();
return collection.size();
}
@Override
public List asList() {
Collection values = map.values();
return Collections.unmodifiableList(new ArrayList(values));
}
@Override
public void getFrontByTime(long time, Collection collection) {
Collection values = map.values();
for (DelayedEntry e : values) {
if (e.getStoreTime() <= time) {
collection.add(e);
}
}
}
@Override
public void getFrontByNumber(int numberOfElements, Collection collection) {
int count = 0;
Collection values = map.values();
for (DelayedEntry e : values) {
if (count == numberOfElements) {
break;
}
collection.add(e);
count++;
}
}
/**
* If this is an existing key in this queue, use previously set store time;
* since we do not want to shift store time of an existing key on every update.
*/
private void calculateStoreTime(DelayedEntry delayedEntry) {
Data key = (Data) delayedEntry.getKey();
DelayedEntry currentEntry = map.get(key);
if (currentEntry != null) {
long currentStoreTime = currentEntry.getStoreTime();
delayedEntry.setStoreTime(currentStoreTime);
}
}
private static Map createMapWithExpectedCapacity(int expectedCapacity) {
final double defaultLoadFactor = 0.75;
int initialCapacity = (int) (expectedCapacity / defaultLoadFactor) + 1;
return new LinkedHashMap(initialCapacity);
}
}