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

org.apache.flink.runtime.state.gemini.engine.page.LogicalPageChainImpl 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.engine.page;

import org.apache.flink.runtime.state.gemini.engine.exceptions.GeminiRuntimeException;
import org.apache.flink.runtime.state.gemini.engine.page.bmap.GBinarySplitHashMap;
import org.apache.flink.runtime.state.gemini.engine.snapshot.RegionSnapshot;
import org.apache.flink.runtime.state.gemini.engine.snapshot.SnapshotMetaFile;
import org.apache.flink.util.Preconditions;

import org.apache.flink.shaded.guava18.com.google.common.base.MoreObjects;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterators;
import java.util.stream.StreamSupport;

import static org.apache.flink.runtime.state.gemini.engine.page.PageAddress.COMPOSITE_PAGE_ADDRESS;
import static org.apache.flink.runtime.state.gemini.engine.page.PageAddress.SINGLE_PAGE_ADDRESS;
import static org.apache.flink.runtime.state.gemini.engine.snapshot.SnapshotMetaFile.writerFunc;

/**
 * The default implementation of {@link LogicalPageChain}.
 */
public class LogicalPageChainImpl implements LogicalPageChain {
	private volatile int chainIndex = -1;
	private volatile PageAddress[] pageAddresses;
	// 1 byte indicates status, 3 bytes indicate page size
	private volatile byte pageStatus;
	private volatile int pageSize = 0;

	public LogicalPageChainImpl(PageStatus pageStatus) {
		this.pageStatus = pageStatus.getCode();
	}

	public LogicalPageChainImpl(PageStatus pageStatus, int defaultChainLen) {
		this.pageStatus = pageStatus.getCode();
		initChainPageImpl(defaultChainLen);
	}

	private LogicalPageChainImpl(
		LogicalPageChainImpl logicalPageChain,
		Map copiedDataPage) {

		this.chainIndex = logicalPageChain.chainIndex;
		// not copy the page in WaitSplitting status
		if (logicalPageChain.pageAddresses != null) {
			this.pageAddresses = new PageAddress[logicalPageChain.pageAddresses.length];
			System.arraycopy(logicalPageChain.pageAddresses, 0, this.pageAddresses, 0, this.chainIndex + 1);
		}
		//add Reference count.
		DataPage dataPage;
		for (int i = 0; i <= this.chainIndex; i++) {
			dataPage = this.pageAddresses[i].getDataPage();
			if (dataPage != null) {
				copiedDataPage.put(this.pageAddresses[i], dataPage);
			}
		}
		this.pageStatus = logicalPageChain.pageStatus;
	}

	private void initChainPageImpl(int defaultChainLen) {
		Preconditions.checkArgument(defaultChainLen >= 3, "defaultChainLen too small");
		pageAddresses = new PageAddress[defaultChainLen];
	}

	@Override
	public boolean compareAndSetStatus(
		PageStatus expectedPageStatus, PageStatus targetStatus) {

		if (expectedPageStatus == null) {
			pageStatus = targetStatus.getCode();
			return true;
		}
		if (pageStatus != expectedPageStatus.getCode()) {
			return false;
		}

		synchronized (this) {
			if (pageStatus != expectedPageStatus.getCode()) {
				return false;
			} else {
				pageStatus = targetStatus.getCode();
				return true;
			}
		}
	}

	@Override
	public void addPageSize(int pageSize) {
		this.pageSize += pageSize;
	}

	@Override
	public int getPageSize() {
		return this.pageSize;
	}

	@Override
	public int getSubPageNum() {
		int subPageNum = 0;
		for (int i = 0; i <= chainIndex; i++) {
			subPageNum += pageAddresses[i].getSubPageNum();
		}
		return subPageNum;
	}

	@Override
	public int getSubPageSize() {
		int subPageSize = 0;
		for (int i = 0; i <= chainIndex; i++) {
			subPageSize += pageAddresses[i].getSubPageDataLen();
		}
		return subPageSize;
	}

	@Override
	public PageStatus getPageStatus() {
		return PageStatus.valueOf(pageStatus);
	}

	@Override
	public PageAddress getPageAddress(int chainIndex) {
		Preconditions.checkArgument(chainIndex >= 0 && chainIndex <= this.chainIndex, "logicPage overflow");
		return this.pageAddresses[chainIndex];
	}

	@Override
	public PageAddress createPage(DataPage dataPage) {
		//no concurrence
		Preconditions.checkArgument(chainIndex < pageAddresses.length, "logicPage overflow");
		checkSpace();
		PageAddress pageAddress;
		if (dataPage.getGBinaryHashMap() instanceof GBinarySplitHashMap) {
			pageAddress = new PageAddressCompositeImpl(dataPage);
		} else {
			pageAddress = new PageAddressSingleImpl(dataPage);
		}
		pageAddresses[chainIndex + 1] = pageAddress;
		chainIndex++;
		pageAddress.setChainIndex(chainIndex);
		return pageAddress;
	}

	@Override
	public int insertPage(PageAddress pageAddress) {
		//no concurrence
		Preconditions.checkArgument(chainIndex < pageAddresses.length, "logicPage overflow");
		checkSpace();
		pageAddresses[++chainIndex] = pageAddress;
		pageAddress.setChainIndex(chainIndex);
		return chainIndex;
	}

	private void checkSpace() {
		// TODO: #SR optimize this deepcopy
		// change the deepcopy logic in PageIndexHashImpl().
		// do not new the logichainedpage, reference the chain and log the chainIndex.
		if (chainIndex == pageAddresses.length - 1) {
			PageAddress[] newpageAddresses = new PageAddress[pageAddresses.length + 1];
			System.arraycopy(pageAddresses, 0, newpageAddresses, 0, pageAddresses.length);
			pageAddresses = newpageAddresses;
		}
	}

	@Override
	public int getCurrentPageChainIndex() {
		return this.chainIndex;
	}

	@Override
	public int getPageChainCapacity() {
		return pageAddresses.length;
	}

	@Override
	public LogicalPageChain copy(Map copiedDataPage) {
		if (this == PageIndexHashImpl.WAIT_SPLITTING_PAGE) {
			return PageIndexHashImpl.WAIT_SPLITTING_PAGE;
		}
		return new LogicalPageChainImpl(this, copiedDataPage);
	}

	@Override
	public Iterator pageIterator() {
		// for WaitSplitting page
		if (pageAddresses == null) {
			return Collections.emptyIterator();
		}

		return Arrays.stream(pageAddresses).filter(Objects::nonNull)
			.flatMap(index -> StreamSupport.stream(
				Spliterators.spliteratorUnknownSize(
					index.pageIterator(), 0), false))
			.iterator();
	}

	@Override
	public void snapshot(Collection regionSnapshots) throws IOException {
		writerFunc(regionSnapshots, w -> w.writeInt(chainIndex));

		for (int i = 0; i <= chainIndex; i++) {
			PageAddress pageAddress = pageAddresses[i];
			writerFunc(regionSnapshots, w -> w.writeByte(pageAddress.getPageAddressType()));
			pageAddress.snapshot(regionSnapshots);
		}
	}

	@Override
	public void restore(SnapshotMetaFile.Reader reader, PageStoreStats pageStoreStats) throws IOException {
		chainIndex = reader.readInt();
		this.pageAddresses = new PageAddress[chainIndex + 1];
		for (int i = 0; i <= chainIndex; ++i) {
			PageAddress pageAddress;
			byte pageType = reader.readByte();
			switch (pageType) {
				case SINGLE_PAGE_ADDRESS:
					pageAddress = PageAddressSingleImpl.restore(reader, pageStoreStats);
					break;
				case COMPOSITE_PAGE_ADDRESS:
					pageAddress = PageAddressCompositeImpl.restore(reader, pageStoreStats);
					break;
				default:
					throw new GeminiRuntimeException("error pageAddress:" + pageType);
			}
			pageStoreStats.addLogicSubPageCount(pageAddress.getSubPageNum());
			pageStoreStats.addLogicSubPageSize(pageAddress.getSubPageDataLen());
			pageAddresses[i] = pageAddress;
			addPageSize(pageAddress.getDataLen());
		}
		pageStoreStats.addLogicPageChainLen(chainIndex + 1);
		pageStoreStats.addLogicPageChainCapacity(chainIndex + 1);
	}

	@Override
	public Set getAllDataPageReferenced() {
		Set set = new HashSet<>();
		for (PageAddress address : pageAddresses) {
			DataPage dataPage = address.getDataPage();
			if (dataPage != null) {
				set.add(dataPage);
			}
		}
		return set;
	}

	@Override
	public String toString() {
		return MoreObjects.toStringHelper(this).
			add("pageAddresses", Arrays.toString(pageAddresses)).
			toString();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy