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

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

import org.apache.flink.runtime.state.gemini.engine.GRegionContext;
import org.apache.flink.runtime.state.gemini.engine.dbms.GContext;
import org.apache.flink.runtime.state.gemini.engine.filecache.FileCache;
import org.apache.flink.runtime.state.gemini.engine.handler.GeminiEventExecutorGroup;
import org.apache.flink.runtime.state.gemini.engine.page.LogicalPageChain;
import org.apache.flink.runtime.state.gemini.engine.page.PageAddress;
import org.apache.flink.runtime.state.gemini.engine.page.PageAddressCompositeImpl;
import org.apache.flink.runtime.state.gemini.engine.page.PageContext;
import org.apache.flink.runtime.state.gemini.engine.rm.GByteBuffer;

import org.apache.flink.shaded.guava18.com.google.common.util.concurrent.ThreadFactoryBuilder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * FetchPolicyImpl.
 * aim to reduce the IO access num. for now only support preFetch pages which is belonged to a same logic page.
 * non thread safe.
 */
public class FetchPolicyImpl implements FetchPolicy {

	private static final Logger LOG = LoggerFactory.getLogger(FetchPolicyImpl.class);

	private final DataPageLRU readPageCacheLRU;
	private final CacheStats cacheStats;
	private final FileCache fileCache;
	private final ExecutorService preFetchExecutor;
	private final AtomicInteger currentPrefetchingNum = new AtomicInteger(0);
	private final int maxPrefchingNum;

	public FetchPolicyImpl(
		GContext gContext, CacheStats cacheStats, DataPageLRU readPageCacheLRU) {
		this.readPageCacheLRU = readPageCacheLRU;
		this.cacheStats = cacheStats;
		this.fileCache = gContext.getSupervisor().getFileCache();

		ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(gContext.getGConfiguration().getExecutorPrefixName() + "geminiPrefetch-%d").build();
		this.preFetchExecutor = new GeminiEventExecutorGroup(gContext.getGConfiguration().getFlushThreadNum(),
			namedThreadFactory,
			gContext.getGConfiguration().getFetchThreadSleepTimeNS(),
			gContext);
		this.maxPrefchingNum = gContext.getGConfiguration().getMaxCompactionThreshold();
	}

	void preFetch(LogicalPageChain logicalPageChain, int logicPageChainIndex, int startIndex, GRegionContext gRegionContext) {
		/**
		 * logicalPageChain and startIndex are pointed to other Pages needed to prefetch.
		 */
		while (startIndex >= 0 && gRegionContext.getGContext().isDBNormal()) {
			PageAddress pageAddressRequest = logicalPageChain.getPageAddress(startIndex);
			startIndex--;
			Iterator pageAddressIterable = pageAddressRequest.pageIteratorOrdered();
			//for preFetch, we pre-fetch subPage also.
			while (pageAddressIterable.hasNext()) {
				final PageAddress pageAddress = pageAddressIterable.next();
				if (pageAddress.hasDataPage()) {
					continue;
				}
				//too slow?
				if (currentPrefetchingNum.get() > maxPrefchingNum) {
					return;
				}
				DataPageLRU.PageWithContext pageWithContext = this.readPageCacheLRU.get(pageAddress);

				if (pageWithContext != null) {
					FutureDataPage futureDataPageOld = pageWithContext.getFutureDataPage();
					if (futureDataPageOld != null && !futureDataPageOld.isFail()) {
						return;
					}
				}

				currentPrefetchingNum.incrementAndGet();
				FutureDataPage futureDataPage = new FutureDataPage(pageAddress.getDataLen());
				//readPageCacheLRU is a small cache, and finally we should put this pages to Cache by commit this pages to RegionEvent,
				//for now, we have not implement this logic, and depends on compaction to update the Cache.
				this.readPageCacheLRU.put(pageAddress, new DataPageLRU.PageWithContext(PageContext.of(
					gRegionContext.getRegionId(),
					logicPageChainIndex,
					logicalPageChain.hashCode(),
					PageContext.CacheStatus.IN_LRU), futureDataPage));
				//TODO in the future, we should combine the preFetchExecutor and evictExecutor,
				//TODO that means when we preFetch some pages,evictHandler will skip these pages.
				this.preFetchExecutor.submit(() -> asyncFetch(futureDataPage, pageAddress, gRegionContext));
			}
		}
	}

	private void asyncFetch(
		FutureDataPage futureDataPage, PageAddress pageAddress, GRegionContext gRegionContext) {
		//todo to resuse dataPage need send to Region handler.
		try {
			GByteBuffer dataPage = this.fileCache.getPage(pageAddress,
				gRegionContext,
				gRegionContext.getGContext().getSupervisor().getFlushExecutorGroup().next());
			futureDataPage.complete(dataPage);
			dataPage.release();
		} catch (Exception e) {
			futureDataPage.completeExceptionally(e);
		} finally {
			currentPrefetchingNum.decrementAndGet();
		}
	}

	@Override
	public GByteBuffer fetch(
		PageAddress pageAddressRequested,
		LogicalPageChain logicalPageChain,
		int logicPageChainIndex,
		int startIndex,
		GRegionContext gRegionContext,
		boolean prefetch,
		boolean doCache) {
		PageAddress pageAddress = pageAddressRequested;
		//we only fetch mainPageAddress, subPageAddress is fetched by the main pageAddress.
		if (pageAddressRequested instanceof PageAddressCompositeImpl) {
			pageAddress = ((PageAddressCompositeImpl) pageAddressRequested).getMainPageAddress();
		}
		//PageAddress can not be updated, so can be as Key.
		DataPageLRU.PageWithContext pageWithContext = this.readPageCacheLRU.get(pageAddress);
		if (pageWithContext != null) {
			final FutureDataPage futureDataPage = pageWithContext.getFutureDataPage();
			if (futureDataPage != null) {
				if (futureDataPage.isDone()) {
					try {
						GByteBuffer dataPage = futureDataPage.get();
						dataPage.retain();
						this.cacheStats.addPageCacheLRUHitCount();
						return dataPage;
					} catch (Exception e) {
						//futureDataPage fail. try new.
					}
				}
			}
		}
		if (prefetch) {
			preFetch(logicalPageChain, logicPageChainIndex, startIndex - 1, gRegionContext);
		}
		GByteBuffer dataPage = this.fileCache.getPage(pageAddress,
			gRegionContext,
			gRegionContext.getGContext().getSupervisor().getFlushExecutorGroup().next());
		if (doCache) {
			DataPageLRU.PageWithContext node = new DataPageLRU.PageWithContext(PageContext.of(
				gRegionContext.getRegionId(),
				logicPageChainIndex,
				logicalPageChain.hashCode(),
				PageContext.CacheStatus.IN_LRU), new FutureDataPage(dataPage));
			this.readPageCacheLRU.put(pageAddress, node);
		}
		return dataPage;
	}

	@Override
	public GByteBuffer fetchSubPage(
		PageAddress pageAddress, PageContext pageContext, GRegionContext gRegionContext, boolean doCache) {

		//PageAddress can not be updated, so can be as Key.
		DataPageLRU.PageWithContext pageWithContext = this.readPageCacheLRU.get(pageAddress);
		if (pageWithContext != null) {
			final FutureDataPage futureDataPage = pageWithContext.getFutureDataPage();
			if (futureDataPage != null) {
				if (futureDataPage.isDone()) {
					try {
						GByteBuffer dataPage = futureDataPage.get();
						dataPage.retain();
						this.cacheStats.addSubPageCacheHitCount();
						return dataPage;
					} catch (Exception e) {
						//futureDataPage fail. try new.
					}
				}
			}
		}
		this.cacheStats.addSubPageCacheMissCount();
		GByteBuffer dataPage = this.fileCache.getPage(pageAddress,
			gRegionContext,
			gRegionContext.getGContext().getSupervisor().getFlushExecutorGroup().next());
		if (doCache) {
			DataPageLRU.PageWithContext node = new DataPageLRU.PageWithContext(pageContext, new FutureDataPage(dataPage));
			this.readPageCacheLRU.put(pageAddress, node);
		}
		return dataPage;
	}

	@Override
	public DataPageLRU getDataPageLRU() {
		return this.readPageCacheLRU;
	}

	@Override
	public void close() {
		this.preFetchExecutor.shutdownNow();
		this.readPageCacheLRU.clear();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy