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

com.dell.doradus.service.olap.OLAPService Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014 Dell, Inc.
 * 
 * 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.dell.doradus.service.olap;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.dell.doradus.common.AggregateResult;
import com.dell.doradus.common.ApplicationDefinition;
import com.dell.doradus.common.BatchResult;
import com.dell.doradus.common.BatchResult.Status;
import com.dell.doradus.common.CommonDefs;
import com.dell.doradus.common.FieldDefinition;
import com.dell.doradus.common.TableDefinition;
import com.dell.doradus.common.UNode;
import com.dell.doradus.common.Utils;
import com.dell.doradus.olap.MergeOptions;
import com.dell.doradus.olap.Olap;
import com.dell.doradus.olap.OlapAggregate;
import com.dell.doradus.olap.OlapBatch;
import com.dell.doradus.olap.OlapQuery;
import com.dell.doradus.olap.OlapStatistics;
import com.dell.doradus.olap.Olapp;
import com.dell.doradus.olap.aggregate.AggregateResultConverter;
import com.dell.doradus.olap.aggregate.AggregationResult;
import com.dell.doradus.olap.store.CubeSearcher;
import com.dell.doradus.olap.store.SegmentStats;
import com.dell.doradus.search.SearchResultList;
import com.dell.doradus.service.StorageService;
import com.dell.doradus.service.db.Tenant;
import com.dell.doradus.service.rest.RESTCallback;
import com.dell.doradus.service.rest.RESTService;
import com.dell.doradus.service.schema.SchemaService;
import com.dell.doradus.service.taskmanager.Task;
import com.dell.doradus.service.taskmanager.TaskFrequency;
import com.dell.doradus.service.taskmanager.TaskManagerService;

/**
 * The OLAP storage service for Doradus.
 */
public class OLAPService extends StorageService {
    private static final OLAPService INSTANCE = new OLAPService();
    
    private Olap m_olap = null;

    // OLAPService-specific commands
    private static final List> CMD_CLASSES = Arrays.asList(
        // Object retrieval:
        QueryURICmd.class,
        QueryDocCmd.class,
        AggregateURICmd.class,
        AggregateDocCmd.class,
        
        // Object updates:
        AddObjectsCmd.class,
        DeleteObjectsCmd.class,
        
        // Shard management:
        MergeSegmentCmd.class,
        SetShardPropertiesCmd.class,
        DeleteSegmentCmd.class,
        ListShardsCmd.class,
        ShardStatsCmd.class,
        
        // Troubleshooting & repair
        ShardStatisticsCmd.class,
        DuplicatesCmd.class,
        ShardVerifyCmd.class,
        DeleteSegmentCmd2.class
    );
    
    private static final List> SYSTEM_CMD_CLASSES = Arrays.asList(
        OlappCmd.class
    );
    
    //----- Service methods
    
    /**
     * Get the singleton instance of the StorageService. The object may or may not have
     * been initialized yet.
     * 
     * @return  The singleton instance of the OLAPService.
     */
    public static OLAPService instance() {
        return INSTANCE;
    }   // instance

    @Override
    public void initService() {
        RESTService.instance().registerCommands(CMD_CLASSES, this);
        RESTService.instance().registerCommands(SYSTEM_CMD_CLASSES);
    }   // initService
    
    @Override
    public void startService() {
        SchemaService.instance().waitForFullService();
        m_olap = new Olap();
    }   // startService
    
    @Override
    public void stopService() {
        m_olap = null;
    }   // stopService

    //----- StorageService: Schema update methods
    
    @Override
    public void deleteApplication(ApplicationDefinition appDef) {
        checkServiceState();
        m_olap.deleteApplication(appDef);
    }   // deleteApplication
    
    @Override
    public void initializeApplication(ApplicationDefinition oldAppDef,
                                      ApplicationDefinition appDef) {
        checkServiceState();
        m_olap.createApplication(Tenant.getTenant(appDef), appDef.getAppName());
    }   // initializeApplication
    
    @Override
    public void validateSchema(ApplicationDefinition appDef) {
        checkServiceState();
        validateApplication(appDef);
    }   // validateSchema
    
    @Override
    public Collection getAppTasks(ApplicationDefinition appDef) {
        checkServiceState();
        List appTasks = new ArrayList<>();
        String agingFreq = appDef.getOption(CommonDefs.OPT_AGING_CHECK_FREQ);
        if (agingFreq != null) {
            appTasks.add(new OLAPDataAger(appDef, agingFreq));
        }
        String autoMergeFreq = appDef.getOption("auto-merge");
        if (autoMergeFreq != null) {
            appTasks.add(new OLAPMerger(appDef, autoMergeFreq));
        }
        return appTasks;
    }   // getAppTasks
    
    //----- Object query methods
    
    /**
     * Perform an object query on the given table using the given query parameters.
     * 
     * @param tableDef  {@link TableDefinition} of table to query.
     * @param olapQuery {@link OlapQuery} containing query parameters.
     * @return          {@link SearchResultList} containing search results.
     */
    public SearchResultList objectQuery(TableDefinition tableDef, OlapQuery olapQuery) {
        checkServiceState();
        return m_olap.search(tableDef.getAppDef(), tableDef.getTableName(), olapQuery);
    }   // objectQueryDoc
    
    /**
     * Perform an aggregate query on the given table using the given request.
     * 
     * @param tableDef  {@link TableDefinition} of table to query.
     * @param request   {@link OlapAggregate} that defines query parameters.
     * @return          {@link AggregateResult} containing search results.
     */
    public AggregateResult aggregateQuery(TableDefinition tableDef, OlapAggregate request) {
        checkServiceState();
        AggregationResult result = m_olap.aggregate(tableDef.getAppDef(), tableDef.getTableName(), request);
        return AggregateResultConverter.create(result, request);
    }
    
    //----- StorageService: Object update methods

    /**
     * Add a batch of updates for the given application to the given shard. Objects can
     * new, updated, or deleted.
     * 
     * @param appDef    {@link ApplicationDefinition} of application to update.
     * @param shardName Shard to add batch to.
     * @param batch     {@link OlapBatch} containing object updates.
     * @return          {@link BatchResult} indicating results of update.
     */
    public BatchResult addBatch(ApplicationDefinition appDef, String shardName, OlapBatch batch) {
        return addBatch(appDef, shardName, batch, null);
    }   // addBatch
    
    /**
     * Same as {@link #addBatch(ApplicationDefinition, String, OlapBatch)} but allows
     * batch options to be passed. Currently, the only option supported is "overwrite",
     * which must be true or false. The default is true, which means field values for
     * existing objects are replaced. When overwrite is set to false, existing field
     * values are not overwritten with the values in this batch.
     * 
     * @param appDef    {@link ApplicationDefinition} of application to update.
     * @param shardName Shard to add batch to.
     * @param batch     {@link OlapBatch} containing object updates.
     * @param options   Map of option key/value pairs. Currently, only "overwrite" is
     *                  supported and must be true/false. 
     * @return          {@link BatchResult} indicating results of update.
     */
    public BatchResult addBatch(ApplicationDefinition appDef, String shardName,
                                OlapBatch batch, Map options) {
        checkServiceState();
        String guid = m_olap.addSegment(appDef, shardName, batch, getOverwriteOption(options));
        BatchResult result = new BatchResult();
        result.setStatus(Status.OK);
        result.setComment("GUID=" + guid);
        return result;
    }   // addBatch

    //----- OLAPService-specific public methods

    /**
     * Perform the given OLAP browser (_olapp) command.
     * 
     * @param tenant        Tenant context for command.
     * @param parameters    OLAP browser parameters. Should be empty to start the browser
     *                      at the home page.
     * @return              An HTML-formatted page containing the results of the given
     *                      OLAP browser command.
     */
    public String browseOlapp(Tenant tenant, Map parameters) {
        checkServiceState();
        return Olapp.process(tenant, m_olap, parameters);
    }   // browseOlapp
    
    /**
     * Delete the shard for the given application, including all of its data. This method
     * is a no-op if the given shard does not exist or has no data.
     * 
     * @param appDef        {@link ApplicationDefinition} of application.
     * @param shard         Shard name.
     */
    public void deleteShard(ApplicationDefinition appDef, String shard) {
        checkServiceState();
        m_olap.deleteShard(appDef, shard);
    }   // deleteShard

    /**
     * Get a list of {@link ApplicationDefinition}s that are assigned to the OLAP service
     * for the given tenant. An empty list is returned if there are no OLAP applications.
     * 
     * @param   tenant  {@link Tenant} that owns the OLAP applications.
     * @return  A list of {@link ApplicationDefinition}s that are assigned to the OLAP
     *          service.
     */
    public List getAllOLAPApplications(Tenant tenant) {
        List appDefs = new ArrayList<>();
        for (ApplicationDefinition appDef : SchemaService.instance().getAllApplications(tenant)) {
            if (OLAPService.class.getSimpleName().equals(appDef.getStorageService())) {
                appDefs.add(appDef);
            }
        }
        return appDefs;
    }   // getAllOLAPApplications
    
    /**
     * Get the internal {@link Olap} object; for internal/direct access only. Waits for the
     * database to be opened and OLAP to be fully initialized.
     * 
     * @return The internal {@link Olap} object.
     */
    public Olap getOlap() {
        checkServiceState();
        return m_olap;
    }   // getOlap
    
    /**
     * Get statistics for the given shard, owned by the given application. Statistics are
     * returned as a {@link SegmentStats} object. If there is no information for the given
     * shard, an IllegalArgumentException is thrown.
     *  
     * @param appDef        OLAP application definition.
     * @param shard         Shard name.
     * @return              Shard statistics as a {@link SegmentStats} object.
     */
    public SegmentStats getStats(ApplicationDefinition appDef, String shard) {
        checkServiceState();
        return m_olap.getStats(appDef, shard);
    }   // getStats 
    
    /**
     * Get detailed shard statistics for the given shard. This command is mostly used for
     * development and diagnostics.
     *   
     * @param appDef    {@link ApplicationDefinition} of application to query.
     * @param shard     Name of shard to query.
     * @param paramMap  Map of statistic option key/value pairs.
     * @return          Root of statistics information as a {@link UNode} tree. 
     */
    public UNode getStatistics(ApplicationDefinition appDef, String shard, Map paramMap) {
        checkServiceState();
        CubeSearcher searcher = m_olap.getSearcher(appDef, shard);
        String file = paramMap.get("file");
        if(file != null) {
            return OlapStatistics.getFileData(searcher, file);
        }
        String sort = paramMap.get("sort");
        boolean memStats = !"false".equals(paramMap.get("mem"));
        return OlapStatistics.getStatistics(searcher, sort, memStats);
    }   // getStats
    
    /**
     * List the names of all shards for the given OLAP application.
     * 
     * @param appDef        OLAP application definition.
     * @return              List of shard names. Empty if there are no shards.
     */
    public List listShards(ApplicationDefinition appDef) {
        checkServiceState();
        return m_olap.listShards(appDef);
    }   // listShards
    
    /**
     * Merge loaded batches for the given shard name and application, optionally assigning
     * an expire-date. If "auto-merge" is not set for the application and a merge is
     * already underway for the shard, an exception is thrown. If "auto-merge" is set, the
     * shard is merged via a {@link TaskManagerService} task, waiting for an existing
     * merge task, if any, to complete. If the given expireDate is not null, the shard is
     * updated with the given expire-date. If the given expireDate is null, the shard is
     * updated to not have an expire-date.
     * 
     * @param appDef        OLAP application definition.
     * @param shard         Shard name.
     * @param options    	Merge options
     */
    public void mergeShard(ApplicationDefinition appDef, String shard, MergeOptions options) {
        checkServiceState();
        if (appDef.getOption("auto-merge") != null) {
            TaskManagerService.instance().executeTask(appDef, new OLAPMerger(appDef, shard, options));
        } else {
            m_olap.merge(appDef, shard, options);
        }
    }
    
    /**
     * Get the expire-date for the given shard name and OLAP application. Null is returned
     * if the shard does not exist or has no expire-date.
     * 
     * @param appDef        OLAP application definition.
     * @param shard         Shard name.
     * @return              Shard's expire-date or null if it doesn't exist or has no
     *                      expire-date.
     */
    public Date getExpirationDate(ApplicationDefinition appDef, String shard) {
        checkServiceState();
        return m_olap.getExpirationDate(appDef, shard);
    }	// getExpirationDate
    
    /**
     * Search for and return duplicate object IDs for the given OLAP application and table
     * across the given shard range. The given shard range must be in the form of:
     * 
     *      from-shard[,to-shard]
     * 
* All shards whose name is greater than or equal to from-shard are searched. * If to-shard is given, shard searched will also be only those whose name is * less than or equal to it. * * @param application OLAP application name. * @param table Table name belonging to application. * @param range From shard name, optionally followed by to shard name. * @return List of object IDs in more than one shard within the given range, * returned as a {@link SearchResultList}. */ public SearchResultList getDuplicateIDs(ApplicationDefinition appDef, String table, String range) { checkServiceState(); return m_olap.getDuplicateIDs(appDef, table, range); } // getDuplicateIDs //----- Private methods // Singleton instantiation only. private OLAPService() { } // Get case-insensitive "overwrite" option. Default to "true". private boolean getOverwriteOption(Map options) { boolean bOverwrite = true; if (options != null) { for (String name : options.keySet()) { if ("overwrite".equals(name.toLowerCase())) { bOverwrite = Boolean.parseBoolean(options.get(name)); } else { Utils.require(false, "Unknown OLAP batch option: " + name); } } } return bOverwrite; } // getOverwriteOption // Validate the given application for OLAP constraints. private void validateApplication(ApplicationDefinition appDef) { boolean bSawAgingFreq = false; for (String optName : appDef.getOptionNames()) { String optValue = appDef.getOption(optName); switch (optName) { case CommonDefs.OPT_STORAGE_SERVICE: assert optValue.equals(this.getClass().getSimpleName()); break; case CommonDefs.OPT_TENANT: // Ignore break; case CommonDefs.OPT_AGING_CHECK_FREQ: new TaskFrequency(optValue); bSawAgingFreq = true; break; case "auto-merge": new TaskFrequency(optValue); break; default: throw new IllegalArgumentException("Unknown option for OLAPService application: " + optName); } } for (TableDefinition tableDef : appDef.getTableDefinitions().values()) { validateTable(tableDef); } if (!bSawAgingFreq) { appDef.setOption(CommonDefs.OPT_AGING_CHECK_FREQ, "1 DAY"); } } // validateApplication // Validate the given table for OLAP constraints. private void validateTable(TableDefinition tableDef) { // No options are currently allowed: for (String optName : tableDef.getOptionNames()) { Utils.require(false, "Unknown option for OLAPService table: " + optName); } for (FieldDefinition fieldDef : tableDef.getFieldDefinitions()) { validateField(fieldDef); } } // validateTable // Validate the given field for OLAP constraints. private void validateField(FieldDefinition fieldDef) { if (fieldDef.isScalarField()) { Utils.require(Utils.isEmpty(fieldDef.getAnalyzerName()), "'analyzer' not allowed for OLAP application fields:" + fieldDef); } else if (fieldDef.isLinkType()) { Utils.require(!fieldDef.isSharded(), "Link and xlink fields cannot be sharded: {}", fieldDef); } } // validateField } // class OLAPService




© 2015 - 2025 Weber Informatics LLC | Privacy Policy