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

com.alibaba.nacos.config.server.service.dump.disk.ConfigRocksDbDiskService Maven / Gradle / Ivy

There is a newer version: 3.0.0-ALPHA.2
Show newest version
/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * 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.alibaba.nacos.config.server.service.dump.disk;

import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.utils.LogUtil;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.rocksdb.BlockBasedTableConfig;
import org.rocksdb.ColumnFamilyOptions;
import org.rocksdb.DBOptions;
import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.alibaba.nacos.config.server.constant.Constants.ENCODE_UTF8;

/**
 * config rocks db disk service.
 *
 * @author shiyiyue
 */
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class ConfigRocksDbDiskService implements ConfigDiskService {
    
    private static final String ROCKSDB_DATA = File.separator + "rocksdata" + File.separator;
    
    private static final String BASE_DIR = ROCKSDB_DATA + "config-data";
    
    private static final String BETA_DIR = ROCKSDB_DATA + "beta-data";
    
    private static final String TAG_DIR = ROCKSDB_DATA + "tag-data";
    
    private static final String BATCH_DIR = ROCKSDB_DATA + "batch-data";
    
    private static final long DEFAULT_WRITE_BUFFER_MB = 32;
    
    Map rocksDbMap = new HashMap<>();
    
    private void createDirIfNotExist(String dir) {
        File roskDataDir = new File(EnvUtil.getNacosHome(), "rocksdata");
        if (!roskDataDir.exists()) {
            roskDataDir.mkdirs();
        }
        File baseDir = new File(EnvUtil.getNacosHome(), dir);
        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }
    }
    
    private void deleteDirIfExist(String dir) {
        File rockskDataDir = new File(EnvUtil.getNacosHome(), "rocksdata");
        if (!rockskDataDir.exists()) {
            return;
        }
        File baseDir = new File(EnvUtil.getNacosHome(), dir);
        if (baseDir.exists()) {
            baseDir.delete();
        }
    }
    
    public ConfigRocksDbDiskService() {
        createDirIfNotExist(BASE_DIR);
        createDirIfNotExist(BETA_DIR);
        createDirIfNotExist(TAG_DIR);
        createDirIfNotExist(BATCH_DIR);
    }
    
    private byte[] getKeyByte(String dataId, String group, String tenant, String tag) throws IOException {
        String[] keys = new String[] {dataId, group, tenant, tag};
        StringBuilder stringBuilder = new StringBuilder();
        for (String key : keys) {
            if (StringUtils.isBlank(key)) {
                key = "";
            }
            urlEncode(key, stringBuilder);
            stringBuilder.append("+");
        }
        return stringBuilder.toString().getBytes(ENCODE_UTF8);
    }
    
    /**
     * + -> %2B % -> %25.
     */
    private static void urlEncode(String str, StringBuilder sb) {
        for (int idx = 0; idx < str.length(); ++idx) {
            char c = str.charAt(idx);
            if ('+' == c) {
                sb.append("%2B");
            } else if ('%' == c) {
                sb.append("%25");
            } else {
                sb.append(c);
            }
        }
    }
    
    /**
     * save config to disk.
     */
    public void saveToDiskInner(String type, String dataId, String group, String tenant, String tag, String content)
            throws IOException {
        try {
            initAndGetDB(type).put(getKeyByte(dataId, group, tenant, tag), content.getBytes(ENCODE_UTF8));
        } catch (RocksDBException e) {
            throw new IOException(e);
        }
    }
    
    /**
     * save config to disk.
     */
    public void saveToDiskInner(String type, String dataId, String group, String tenant, String content)
            throws IOException {
        saveToDiskInner(type, dataId, group, tenant, null, content);
    }
    
    /**
     * Save configuration information to disk.
     */
    public void saveToDisk(String dataId, String group, String tenant, String content) throws IOException {
        saveToDiskInner(BASE_DIR, dataId, group, tenant, content);
    }
    
    /**
     * Save beta information to disk.
     */
    public void saveBetaToDisk(String dataId, String group, String tenant, String content) throws IOException {
        saveToDiskInner(BETA_DIR, dataId, group, tenant, content);
        
    }
    
    /**
     * Save tag information to disk.
     */
    public void saveTagToDisk(String dataId, String group, String tenant, String tag, String content)
            throws IOException {
        saveToDiskInner(TAG_DIR, dataId, group, tenant, tag, content);
        
    }
    
    /**
     * Deletes configuration files on disk.
     */
    public void removeConfigInfo(String dataId, String group, String tenant) {
        removeContentInner(BASE_DIR, dataId, group, tenant, null);
    }
    
    /**
     * Deletes beta configuration files on disk.
     */
    public void removeConfigInfo4Beta(String dataId, String group, String tenant) {
        removeContentInner(BETA_DIR, dataId, group, tenant, null);
    }
    
    /**
     * Deletes tag configuration files on disk.
     */
    public void removeConfigInfo4Tag(String dataId, String group, String tenant, String tag) {
        removeContentInner(TAG_DIR, dataId, group, tenant, tag);
        
    }
    
    private String byte2String(byte[] bytes) throws IOException {
        if (bytes == null) {
            return null;
        }
        return new String(bytes, ENCODE_UTF8);
    }
    
    RocksDB initAndGetDB(String dir) throws RocksDBException {
        if (rocksDbMap.containsKey(dir)) {
            return rocksDbMap.get(dir);
        } else {
            synchronized (this) {
                if (rocksDbMap.containsKey(dir)) {
                    return rocksDbMap.get(dir);
                }
                createDirIfEmpty(EnvUtil.getNacosHome() + dir);
                rocksDbMap.put(dir, RocksDB.open(createOptions(dir), EnvUtil.getNacosHome() + dir));
                return rocksDbMap.get(dir);
            }
            
        }
    }
    
    private void createDirIfEmpty(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }
    
    private String getContentInner(String type, String dataId, String group, String tenant) throws IOException {
        byte[] bytes = null;
        try {
            bytes = initAndGetDB(type).get(getKeyByte(dataId, group, tenant, null));
            String string = byte2String(bytes);
            return string;
        } catch (RocksDBException e) {
            throw new IOException(e);
        }
    }
    
    private String getTagContentInner(String type, String dataId, String group, String tenant, String tag)
            throws IOException {
        byte[] bytes = null;
        try {
            bytes = initAndGetDB(type).get(getKeyByte(dataId, group, tenant, tag));
            return byte2String(bytes);
        } catch (RocksDBException e) {
            throw new IOException(e);
        }
    }
    
    private void removeContentInner(String type, String dataId, String group, String tenant, String tag) {
        try {
            initAndGetDB(type).delete(getKeyByte(dataId, group, tenant, tag));
        } catch (Exception e) {
            LogUtil.DEFAULT_LOG.warn("Remove dir=[{}] config fail,dataId={},group={},tenant={},error={}", type, dataId,
                    group, tenant, e.getCause());
        }
    }
    
    /**
     * Returns the path of cache file in server.
     */
    public String getBetaContent(String dataId, String group, String tenant) throws IOException {
        return getContentInner(BETA_DIR, dataId, group, tenant);
    }
    
    /**
     * Returns the path of the tag cache file in server.
     */
    public String getTagContent(String dataId, String group, String tenant, String tag) throws IOException {
        return getTagContentInner(TAG_DIR, dataId, group, tenant, tag);
    }
    
    public String getContent(String dataId, String group, String tenant) throws IOException {
        return getContentInner(BASE_DIR, dataId, group, tenant);
    }
    
    Options createOptions(String dir) {
        DBOptions dbOptions = new DBOptions();
        dbOptions.setMaxBackgroundJobs(Runtime.getRuntime().availableProcessors());
        Options options = new Options(dbOptions, createColumnFamilyOptions(dir));
        options.setCreateIfMissing(true);
        return options;
    }
    
    ColumnFamilyOptions createColumnFamilyOptions(String dir) {
        ColumnFamilyOptions columnFamilyOptions = new ColumnFamilyOptions();
        BlockBasedTableConfig tableFormatConfig = new BlockBasedTableConfig();
        columnFamilyOptions.setTableFormatConfig(tableFormatConfig);
        //set more write buffer size to formal config-data, reduce flush to sst file frequency.
        columnFamilyOptions.setWriteBufferSize(getSuitFormalCacheSizeMB(dir) * 1024 * 1024);
        //once a stt file is flushed, compact it immediately to avoid too many sst file which will result in read latency.
        columnFamilyOptions.setLevel0FileNumCompactionTrigger(1);
        return columnFamilyOptions;
    }
    
    /**
     * get suit formal buffer size.
     *
     * @return
     */
    @SuppressWarnings("PMD.UndefineMagicConstantRule")
    private long getSuitFormalCacheSizeMB(String dir) {
        
        boolean formal = BASE_DIR.equals(dir);
        long maxHeapSizeMB = Runtime.getRuntime().maxMemory() / 1024 / 1024;
        
        if (formal) {
            long formalWriteBufferSizeMB = 0;
            
            if (maxHeapSizeMB < 8 * 1024) {
                formalWriteBufferSizeMB = 32;
            } else if (maxHeapSizeMB < 16 * 1024) {
                formalWriteBufferSizeMB = 64;
            } else {
                formalWriteBufferSizeMB = 256;
            }
            LogUtil.DEFAULT_LOG.info("init formal rocksdb write buffer size {}M for dir {}, maxHeapSize={}M",
                    formalWriteBufferSizeMB, dir, maxHeapSizeMB);
            return formalWriteBufferSizeMB;
        } else {
            LogUtil.DEFAULT_LOG.info("init default rocksdb write buffer size {}M for dir {}, maxHeapSize={}M",
                    DEFAULT_WRITE_BUFFER_MB, dir, maxHeapSizeMB);
            return DEFAULT_WRITE_BUFFER_MB;
        }
        
    }
    
    /**
     * Clear all config file.
     */
    public void clearAll() {
        try {
            if (rocksDbMap.containsKey(BASE_DIR)) {
                rocksDbMap.get(BASE_DIR).close();
                RocksDB.destroyDB(EnvUtil.getNacosHome() + BASE_DIR, new Options());
            }
            deleteDirIfExist(BASE_DIR);
            LogUtil.DEFAULT_LOG.info("clear all config-info success.");
        } catch (RocksDBException e) {
            LogUtil.DEFAULT_LOG.warn("clear all config-info failed.", e);
        }
    }
    
    /**
     * Clear all beta config file.
     */
    public void clearAllBeta() {
        try {
            if (rocksDbMap.containsKey(BETA_DIR)) {
                rocksDbMap.get(BETA_DIR).close();
                RocksDB.destroyDB(EnvUtil.getNacosHome() + BETA_DIR, new Options());
            }
            deleteDirIfExist(BETA_DIR);
            LogUtil.DEFAULT_LOG.info("clear all config-info-beta success.");
        } catch (RocksDBException e) {
            LogUtil.DEFAULT_LOG.warn("clear all config-info-beta failed.", e);
        }
    }
    
    /**
     * Clear all tag config file.
     */
    public void clearAllTag() {
        
        try {
            if (rocksDbMap.containsKey(TAG_DIR)) {
                rocksDbMap.get(TAG_DIR).close();
                RocksDB.destroyDB(EnvUtil.getNacosHome() + TAG_DIR, new Options());
            }
            deleteDirIfExist(TAG_DIR);
            LogUtil.DEFAULT_LOG.info("clear all config-info-tag success.");
        } catch (RocksDBException e) {
            LogUtil.DEFAULT_LOG.warn("clear all config-info-tag failed.", e);
        }
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy