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

com.hazelcast.map.impl.iterator.AbstractMapPartitionIterator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008-2024, 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.iterator;

import com.hazelcast.internal.iteration.IterationPointer;
import com.hazelcast.internal.serialization.Data;
import com.hazelcast.internal.serialization.InternalSerializationService;
import com.hazelcast.internal.serialization.SerializationService;
import com.hazelcast.internal.util.CollectionUtil;
import com.hazelcast.map.IMap;
import com.hazelcast.map.impl.LazyMapEntry;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * {@link AbstractMapPartitionIterator} provides the core iterator functionality
 * shared by its descendants.
 * Base class for iterating a partition. When iterating you can control:
 * 
    *
  • the fetch size
  • *
  • whether values are prefetched or fetched when iterating
  • *
*

*

The Hazelcast cluster is made out of partitions which holds a slice of * the cluster data. The partition count never increases or decreases in a * cluster. In order to implement an iterator over a partitioned data, we use * the following parameters. *

    *
  • the {@code partitionId}
  • *
  • Each partition may have a lot of entries, so we use a second parameter * to track the iteration of the partition.
  • *
*

*

* Iteration steps: *

    *
  • fetching fixed number of keys from the partition defined by {@code partitionId}.
  • *
  • iteration on fetched keys.
  • *
  • get value of a key when the {@link #next()} method is called.
  • *
  • when fetched keys are exhausted by calling {@link #next()}, more keys * are fetched from the cluster.
  • *
* This implementation iterates over partitions and for each partition it * iterates over the internal map using the {@link IterationPointer}s. *

*

*

Fetching data from cluster:

* Fetching is getting a fixed size of keys from the internal table of records * of a partition defined by {@code partitionId} and the * {@link IterationPointer}s. The fetch response is the keys and the * {@link IterationPointer}s used for the following fetch operation. *

*

*

Notes:

*
    *
  • Iterator fetches keys in batch with a fixed size that is configurable.
  • *
  • Fetched keys are cached in the iterator to be used in each iteration step.
  • *
  • {@link #hasNext()} may return {@code true} for a key already removed.
  • *
  • {@link #hasNext()} may only return {@code false} when all known keys * are fetched and iterated.
  • *
  • {@link #next()} may return {@code null} although the map does not * have a {@code null} value. This may happen, for example, when someone * removes the entry after the current thread has checked with * {@link #hasNext()}.
  • *
  • This implementation is not affected by value updates as each value is * retrieved from the cluster when {@link #next()} called.
  • *
*

* * @param the type of key. * @param the type of value. */ public abstract class AbstractMapPartitionIterator implements Iterator> { protected IMap map; protected final int fetchSize; protected final int partitionId; protected boolean prefetchValues; /** * The iteration pointers define the iteration state over a backing map. * Each array item represents an iteration state for a certain size of the * backing map structure (either allocated slot count for HD or table size * for on-heap). Each time the table is resized, this array will carry an * additional iteration pointer. */ protected IterationPointer[] pointers; protected int index; protected int currentIndex = -1; protected List result; public AbstractMapPartitionIterator(IMap map, int fetchSize, int partitionId, boolean prefetchValues) { this.map = map; this.fetchSize = fetchSize; this.partitionId = partitionId; this.prefetchValues = prefetchValues; resetPointers(); } @Override public boolean hasNext() { return (result != null && index < result.size()) || advance(); } @Override public Map.Entry next() { if (hasNext()) { currentIndex = index; index++; Data keyData = getKey(currentIndex); Object value = getValue(currentIndex, keyData); return new LazyMapEntry<>(keyData, value, (InternalSerializationService) getSerializationService()); } throw new NoSuchElementException(); } @Override public void remove() { if (result == null || currentIndex < 0) { throw new IllegalStateException("Iterator.next() must be called before remove()!"); } Data keyData = getKey(currentIndex); map.remove(keyData); currentIndex = -1; } protected boolean advance() { if (pointers[pointers.length - 1].getIndex() < 0) { resetPointers(); return false; } result = fetch(); if (CollectionUtil.isNotEmpty(result)) { index = 0; return true; } return false; } /** * Resets the iteration state. */ private void resetPointers() { pointers = new IterationPointer[]{new IterationPointer(Integer.MAX_VALUE, -1)}; } /** * Sets the iteration state to the state defined by the {@code pointers} * if the given response contains items. * * @param response the iteration response * @param pointers the pointers defining the state of iteration */ protected void setIterationPointers(List response, IterationPointer[] pointers) { if (CollectionUtil.isNotEmpty(response)) { this.pointers = pointers; } } protected abstract List fetch(); protected abstract SerializationService getSerializationService(); private Data getKey(int index) { if (result != null) { if (prefetchValues) { Map.Entry entry = (Map.Entry) result.get(index); return entry.getKey(); } else { return (Data) result.get(index); } } return null; } private Object getValue(int index, Data keyData) { if (result != null) { if (prefetchValues) { Map.Entry entry = (Map.Entry) result.get(index); return entry.getValue(); } else { return map.get(keyData); } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy