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

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

import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.metrics.MetricGroup;
import org.apache.flink.runtime.state.gemini.engine.dbms.GContext;
import org.apache.flink.runtime.state.gemini.engine.dbms.GContextImpl;
import org.apache.flink.runtime.state.gemini.engine.dbms.Supervisor;
import org.apache.flink.runtime.state.gemini.engine.dbms.SupervisorImpl;
import org.apache.flink.runtime.state.gemini.engine.exceptions.GeminiRuntimeException;
import org.apache.flink.runtime.state.gemini.engine.filter.CompositeStateFilter;
import org.apache.flink.runtime.state.gemini.engine.filter.RemoveAllStateFilter;
import org.apache.flink.runtime.state.gemini.engine.filter.TtlStateFilter;
import org.apache.flink.runtime.state.gemini.engine.metrics.CacheMetrics;
import org.apache.flink.runtime.state.gemini.engine.metrics.ExceptionMetrics;
import org.apache.flink.runtime.state.gemini.engine.metrics.FileCacheMetrics;
import org.apache.flink.runtime.state.gemini.engine.metrics.FileCleanerMetrics;
import org.apache.flink.runtime.state.gemini.engine.metrics.HandlerMetrics;
import org.apache.flink.runtime.state.gemini.engine.page.DataPage;
import org.apache.flink.runtime.state.gemini.engine.page.PageAddress;
import org.apache.flink.runtime.state.gemini.engine.snapshot.BackendSnapshotMeta;
import org.apache.flink.runtime.state.gemini.engine.snapshot.DBSnapshotResult;
import org.apache.flink.runtime.state.gemini.time.ProcessingTimeProvider;
import org.apache.flink.runtime.state.gemini.time.TimeProvider;

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

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;

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

/**
 * GeminiDB is a new multi-model data store, designed for using in Flink with single thread accessing manner.
 * it depends on all-in-memory-compaction to avoid file-compaction.
 * it supports snapshot/restore,computer-storage-desperation,ttl.
 * one instance with same dbDFSPath in a JVM.
 */
public class GeminiDB {

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

	/**
	 * DB status.
	 */
	public enum Status {
		INITIALIZE, OPENED, CLOSING, CLOSED, INTERNAL_ERROR
	}

	private String dbName;

	private Supervisor geminiSupervisor;

	private final Object lock = new Object();

	private volatile Status geminiDBStatus = Status.INITIALIZE;

	private volatile Throwable internalError;

	private final Map geminiTableMap = new ConcurrentHashMap<>();

	private GContext gContext;

	private MetricGroup dbMetricGroup;

	private GConfiguration configuration;

	/**
	 * This constructor is only used for tests.
	 */
	@VisibleForTesting
	public GeminiDB() {
		this.geminiDBStatus = Status.OPENED;
	}

	public GeminiDB(
		String dbName, GConfiguration conf, int startRegionId, int endRegionId, MetricGroup metricGroup) {
		this.dbName = checkNotNull(dbName);
		this.configuration = checkNotNull(conf);
		this.gContext = new GContextImpl(this, startRegionId, endRegionId, conf);

		// TODO how to choose time provider according to TimeCharacteristic
		TimeProvider timeProvider = new ProcessingTimeProvider();
		this.gContext.setTimeProvider(timeProvider);

		// init metrics
		int sampleCount = conf.getMetricSampleCount();
		int histogramWindowSize = conf.getMetricHistogramWindowSize();
		this.dbMetricGroup = metricGroup;
		gContext.setDBMetricGroup(dbMetricGroup);

		MetricGroup fileManagerMetricGroup = dbMetricGroup.addGroup("fileManager");
		gContext.setFileManagerMetricGroup(fileManagerMetricGroup);

		CacheMetrics cacheMetric = new CacheMetrics(dbMetricGroup.addGroup("cache"), sampleCount, histogramWindowSize);
		this.gContext.setCacheMetric(cacheMetric);

		HandlerMetrics handlerMetric = new HandlerMetrics(dbMetricGroup.addGroup("handler"),
			sampleCount,
			histogramWindowSize);
		this.gContext.setHandlerMetric(handlerMetric);

		FileCacheMetrics fileCacheMetrics = new FileCacheMetrics(dbMetricGroup.addGroup("fileCache"), sampleCount, histogramWindowSize);
		gContext.setFileCacheMetrics(fileCacheMetrics);

		FileCleanerMetrics fileCleanerMetrics = new FileCleanerMetrics(dbMetricGroup.addGroup("fileCleaner"), sampleCount, histogramWindowSize);
		gContext.setFileCleanerMetrics(fileCleanerMetrics);

		ExceptionMetrics exceptionMetrics = new ExceptionMetrics(dbMetricGroup.addGroup("exception"), sampleCount, histogramWindowSize);
		gContext.setExceptionMetrics(exceptionMetrics);

		//initialize
		CompositeStateFilter stateFilter = new CompositeStateFilter();
		if (gContext.hasTtl()) {
			stateFilter.addStateFilter(new TtlStateFilter());
		}
		stateFilter.addStateFilter(new RemoveAllStateFilter());
		gContext.setStateFilter(stateFilter);

		this.geminiSupervisor = new SupervisorImpl(gContext);
		this.gContext.setSupervisor(geminiSupervisor);

		handlerMetric.registerMetricsCacheStat(this.geminiSupervisor.getWriteBufferManager());

		LOG.info("GeminiDB is created.");
	}

	public boolean setStatus(Status expected, Status target) {
		synchronized (lock) {
			if (expected != null && geminiDBStatus != expected) {
				return false;
			}
			geminiDBStatus = target;
			return true;
		}
	}

	public Status getStatus() {
		return geminiDBStatus;
	}

	public Throwable getInternalError() {
		return internalError;
	}

	public void setInternalError(Throwable throwable) {
		if (setStatus(Status.OPENED, Status.INTERNAL_ERROR)) {
			internalError = throwable;
		}
	}

	public synchronized void open() {
		if (!setStatus(Status.INITIALIZE, Status.OPENED)) {
			throw new GeminiRuntimeException("open db failed, current status is " + geminiDBStatus.toString());
		}
		geminiSupervisor.start();
		LOG.info("GeminiDB is opened");
	}

	public Future startSnapshot(BackendSnapshotMeta backendSnapshotMeta) {
		return this.geminiSupervisor.startSnapshot(backendSnapshotMeta);
	}

	public GTable getTableOrCreate(GTableDescription tableDescription) throws GeminiRuntimeException {
		return geminiTableMap.computeIfAbsent(tableDescription.getTableName(), (nothing) -> {
			GTable gTable = tableDescription.createTable(gContext);
			this.geminiSupervisor.getCacheManager().addTable(gTable);
			this.geminiSupervisor.getWriteBufferManager().addTableNum(tableDescription.getTableName());
			return gTable;
		});

	}

	public void close() {
		setStatus(null, Status.CLOSED);
		// Close sequence:
		// 1. stop all the executor, stop modifying the pages.
		// 2. clear up pages. Resource release manager will help release.
		// 3. stop resource release manager, clear all the remaining resources.
		geminiSupervisor.stop();
		forceCleanUpPages();
		geminiSupervisor.close();
		LOG.info("GeminiDB is closed");
	}

	public GContext getGContext() {
		return gContext;
	}

	public GConfiguration getConfiguration() {
		return configuration;
	}

	public Map getGeminiTableMap() {
		return geminiTableMap;
	}

	public DbPageIterator getDbPageIterator() {
		return new DbPageIteratorImpl(this);
	}

	/**
	 * Clean the remaining pages forcely. Called when close.
	 */
	private void forceCleanUpPages() {
		DbPageIterator iterator = getDbPageIterator();
		while (iterator.valid()) {
			PageAddress pa = iterator.currentPage();
			if (pa.hasDataPage()) {
				DataPage dataPage = pa.getDataPageNoReference();
				dataPage.release();
			}
			iterator.next();
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy