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

org.apache.flink.runtime.state.gemini.subkeyed.AbstractGeminiSubKeyedMapStateImpl Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.flink.runtime.state.gemini.subkeyed;

import org.apache.flink.api.common.functions.HashPartitioner;
import org.apache.flink.api.common.typeutils.TypeSerializer;
import org.apache.flink.core.memory.ByteArrayOutputStreamWithPos;
import org.apache.flink.core.memory.DataOutputView;
import org.apache.flink.core.memory.DataOutputViewStreamWrapper;
import org.apache.flink.runtime.state.StateAccessException;
import org.apache.flink.runtime.state.gemini.engine.GRegion;
import org.apache.flink.runtime.state.gemini.engine.GeminiPKey2;
import org.apache.flink.runtime.state.gemini.engine.hashtable.AbstractGRegionKMapImpl;
import org.apache.flink.runtime.state.gemini.engine.hashtable.AbstractGTableSubKeyedMapImpl;
import org.apache.flink.runtime.state.gemini.engine.hashtable.GRegionKMapImpl;
import org.apache.flink.runtime.state.subkeyed.AbstractSubKeyedMapState;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;

import static org.apache.flink.util.Preconditions.checkNotNull;

/**
 * The base implementation of {@link AbstractSubKeyedMapState} backed by an a state storage.
 * The pairs in the storage are formatted as {(K, N, MK) -> MV}. Because the pairs are
 * partitioned by K, the mappings under the same key will be assigned to the same group and
 * can be easily retrieved with the prefix iterator on the key.
 *
 * @param  Type of the keys in the state.
 * @param  Type of the namespaces in the state.
 * @param  Type of the map keys in the state.
 * @param  Type of the map values in the state.
 * @param  Type of the maps in the state.
 */
abstract class AbstractGeminiSubKeyedMapStateImpl> implements AbstractSubKeyedMapState {
	protected final AbstractGTableSubKeyedMapImpl table;
	private final Byte dummyByte = new Byte((byte) 0);

	/**
	 * The key serializer of current state.
	 */
	protected TypeSerializer keySerializer;

	/**
	 * Serializer for map key of current state.
	 */
	protected TypeSerializer mapKeySerializer;

	/**
	 * Serializer for map value of current state.
	 */
	protected TypeSerializer mapValueSerializer;

	/**
	 * Serializer for namespace of current state.
	 */
	protected TypeSerializer namespaceSerializer;

	private final Map emptyMap = new HashMap<>(0);
	protected ByteArrayOutputStreamWithPos outputStream = new ByteArrayOutputStreamWithPos();
	protected DataOutputView outputView = new DataOutputViewStreamWrapper(outputStream);

	/** partitioner used to get key group.**/
	protected final HashPartitioner partitioner = HashPartitioner.INSTANCE;

	//--------------------------------------------------------------------------

	AbstractGeminiSubKeyedMapStateImpl(AbstractGTableSubKeyedMapImpl table) {
		this.table = checkNotNull(table);
	}

	/**
	 * Creates a map under a key.
	 *
	 * @return A map under a key.
	 */
	abstract M createMap();

	//--------------------------------------------------------------------------

	@Override
	public boolean contains(K key, N namespace, MK mapKey) {
		if (key == null || namespace == null) {
			return false;
		}

		try {
			return getRegion(key, namespace).contains(table.getGeminiPKey2(key, namespace), mapKey);
		} catch (Exception e) {
			throw new StateAccessException(e.getCause());
		}
	}

	@Override
	public boolean contains(K key, N namespace) {
		if (key == null || namespace == null) {
			return false;
		}

		try {
			return getRegion(key, namespace).contains(table.getGeminiPKey2(key, namespace));
		} catch (Exception e) {
			throw new StateAccessException(e.getCause());
		}
	}

	@Override
	public MV get(K key, N namespace, MK mapKey) {
		return getOrDefault(key, namespace, mapKey, null);
	}

	@SuppressWarnings("unchecked")
	@Override
	public MV getOrDefault(K key, N namespace, MK mapKey, MV defaultMapValue) {
		if (key == null || namespace == null) {
			return defaultMapValue;
		}

		MV result = getRegion(key, namespace).get(table.getGeminiPKey2(key, namespace), mapKey);
		if (result == null) {
			result = defaultMapValue;
		}
		return result;
	}

	@Override
	public M get(K key, N namespace) {
		return getOrDefault(key, namespace, null);
	}

	@Override
	public M getOrDefault(K key, N namespace, M defaultMap) {
		if (key == null || namespace == null) {
			return defaultMap;
		}

		// we can not use region#getOrDefault because the default value has incompatible type.
		M result = (M) getRegion(key, namespace).get(table.getGeminiPKey2(key, namespace));
		return (result == null || result.isEmpty()) ? defaultMap : result;
	}

	@SuppressWarnings("unchecked")
	@Override
	public M getAll(K key, N namespace, Collection mapKeys) {
		if (key == null || namespace == null || mapKeys == null || mapKeys.isEmpty()) {
			return null;
		}

		M result = createMap();
		for (MK mapKey : mapKeys) {
			if (mapKey != null) {
				MV value = get(key, namespace, mapKey);
				if (value != null) {
					result.put(mapKey, value);
				}
			}
		}
		return result.isEmpty() ? null : result;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Map getAll(K key) {
		if (key == null) {
			return Collections.emptyMap();
		}

		Iterator namespaceIter = table.getSecondaryKeyByFirstKey(key);
		Map result = new HashMap<>();
		Set visitedNamespace = new HashSet<>();
		while (namespaceIter.hasNext()) {
			N namespace = namespaceIter.next();
			if (visitedNamespace.contains(namespace)) {
				continue;
			}
			M innerMap = get(key, namespace);
			visitedNamespace.add(namespace);
			if (innerMap != null) {
				result.put(namespace, get(key, namespace));
			}
		}
		return result;
	}

	@Override
	public void add(K key, N namespace, MK mapKey, MV mapValue) {
		checkNotNull(key);
		checkNotNull(namespace);
		checkNotNull(mapKey);
		checkNotNull(mapValue);

		getRegion(key, namespace).add(table.getGeminiPKey2(key, namespace), mapKey, mapValue);
		getIndexRegion(key).add(key, namespace, dummyByte);
	}

	@Override
	public void addAll(K key, N namespace, Map mappings) {
		checkNotNull(key);
		checkNotNull(namespace);

		if (mappings == null || mappings.isEmpty()) {
			return;
		}

		getRegion(key, namespace).addAll(table.getGeminiPKey2(key, namespace), mappings);
		getIndexRegion(key).add(key, namespace, dummyByte);
	}

	@Override
	public void remove(K key, N namespace) {
		if (key == null || namespace == null) {
			return;
		}

		getRegion(key, namespace).remove(table.getGeminiPKey2(key, namespace));
		getIndexRegion(key).remove(key, namespace);
	}

	@Override
	public void remove(K key, N namespace, MK mapKey) {
		if (key == null || namespace == null) {
			return;
		}

		getRegion(key, namespace).remove(table.getGeminiPKey2(key, namespace), mapKey);
		// do not update index here.
	}

	@Override
	public void removeAll(K key, N namespace, Collection mapKeys) {
		if (key == null || namespace == null || mapKeys.isEmpty()) {
			return;
		}

		for (MK mapKey : mapKeys) {
			remove(key, namespace, mapKey);
		}
		// do not update index here for now.
	}

	@Override
	public void removeAll(K key) {
		if (key == null) {
			return;
		}

		Iterator iterator = table.getSecondaryKeyByFirstKey(key);
		while (iterator.hasNext()) {
			remove(key, iterator.next());
		}
	}

	@Override
	public Iterator> iterator(K key, N namespace) {
		checkNotNull(key);

		return getRegion(key, namespace).get(table.getGeminiPKey2(key, namespace)).entrySet().iterator();
	}

	@Override
	public Iterable> entries(K key, N namespace) {
		checkNotNull(key);
		checkNotNull(namespace);

		Map values = getRegion(key, namespace).get(table.getGeminiPKey2(key, namespace));
		return values == null ? emptyMap.entrySet() : values.entrySet();
	}

	@Override
	public Iterable keys(K key, N namespace) {
		checkNotNull(key);
		checkNotNull(namespace);

		Map result = getRegion(key, namespace).get(table.getGeminiPKey2(key, namespace));
		return result == null ? emptyMap.keySet() : result.keySet();
	}

	@Override
	public Iterable values(K key, N namespace) {
		checkNotNull(key);
		checkNotNull(namespace);

		Map result = getRegion(key, namespace).get(table.getGeminiPKey2(key, namespace));
		return result == null ? emptyMap.values() : result.values();
	}

	@Override
	public Iterator iterator(K key) {
		checkNotNull(key);

		Iterator namespaceIter = table.getSecondaryKeyByFirstKey(key);
		return new Iterator() {
			N nextNamespace = null;
			N lastNamespace = null;
			@Override
			public boolean hasNext() {
				while (nextNamespace == null && namespaceIter.hasNext()) {
					nextNamespace = namespaceIter.next();
					if (!contains(key, nextNamespace)) {
						// set the flag to move on.
						nextNamespace = null;
					}
				}
				return nextNamespace != null;
			}

			@Override
			public N next() {
				if (!hasNext()) {
					throw new NoSuchElementException();
				}

				lastNamespace = nextNamespace;
				nextNamespace = null;
				return lastNamespace;
			}

			@Override
			public void remove() {
				AbstractGeminiSubKeyedMapStateImpl.this.remove(key, lastNamespace);
			}
		};
	}

	@Override
	public Iterable keys(N namespace) {
		Iterator iterator = table.regionIterator();
		Set result = new HashSet<>();
		while (iterator.hasNext()) {
			AbstractGRegionKMapImpl, MK, MV, ?> cur = (AbstractGRegionKMapImpl, MK, MV, ?>) iterator.next();
			result.addAll(
				cur.getAll().entrySet().stream()
				.map(a -> a.getKey())
				.filter(x -> namespace.equals(x.getSecondKey()))
				.map(y -> y.getFirstKey())
				.collect(Collectors.toSet()));
		}
		return result.isEmpty() ? null : result;
	}

	@Override
	public byte[] getSerializedValue(
		byte[] serializedKeyAndNamespace,
		TypeSerializer safeKeySerializer,
		TypeSerializer safeNamespaceSerializer,
		TypeSerializer safeValueSerializer) throws Exception {
		// TODO
		throw new UnsupportedOperationException();
	}

	@SuppressWarnings("unchecked")
	protected AbstractGRegionKMapImpl, MK, MV, ? extends Map> getRegion(K key, N namespace) {
		return (AbstractGRegionKMapImpl, MK, MV, ? extends Map>) table.getRegion(table.getGeminiPKey2(key, namespace));
	}

	protected GRegionKMapImpl getIndexRegion(K key) {
		return table.getIndexRegion(key);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy