Package net.floodlightcontroller.storage

Source Code of net.floodlightcontroller.storage.AbstractStorageSource

/**
*    Copyright 2011, Big Switch Networks, Inc.
*    Originally created by David Erickson, Stanford University
*
*    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 net.floodlightcontroller.storage;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import net.floodlightcontroller.core.annotations.LogMessageCategory;
import net.floodlightcontroller.core.annotations.LogMessageDoc;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.counter.ICounter;
import net.floodlightcontroller.counter.CounterStore;
import net.floodlightcontroller.counter.ICounterStoreService;
import net.floodlightcontroller.counter.CounterValue.CounterType;
import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.storage.web.StorageWebRoutable;

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


@LogMessageCategory("System Database")
public abstract class AbstractStorageSource
    implements IStorageSourceService, IFloodlightModule {
    protected static Logger logger = LoggerFactory.getLogger(AbstractStorageSource.class);

    // Shared instance of the executor to use to execute the storage tasks.
    // We make this a single threaded executor, because if we used a thread pool
    // then storage operations could be executed out of order which would cause
    // problems in some cases (e.g. delete and update of a row getting reordered).
    // If we wanted to make this more multi-threaded we could have multiple
    // worker threads/executors with affinity of operations on a given table
    // to a single worker thread. But for now, we'll keep it simple and just have
    // a single thread for all operations.
    protected static ExecutorService defaultExecutorService = Executors.newSingleThreadExecutor();

    protected final static String STORAGE_QUERY_COUNTER_NAME = "StorageQuery";
    protected final static String STORAGE_UPDATE_COUNTER_NAME = "StorageUpdate";
    protected final static String STORAGE_DELETE_COUNTER_NAME = "StorageDelete";
   
    protected Set<String> allTableNames = new CopyOnWriteArraySet<String>();
    protected ICounterStoreService counterStore;
    protected ExecutorService executorService = defaultExecutorService;
    protected IStorageExceptionHandler exceptionHandler;

    private Map<String, Set<IStorageSourceListener>> listeners =
        new ConcurrentHashMap<String, Set<IStorageSourceListener>>();

    // Our dependencies
    protected IRestApiService restApi = null;
   
    protected static final String DB_ERROR_EXPLANATION =
            "An unknown error occurred while executing asynchronous " +
            "database operation";
   
    @LogMessageDoc(level="ERROR",
            message="Failure in asynchronous call to executeQuery",
            explanation=DB_ERROR_EXPLANATION,
            recommendation=LogMessageDoc.GENERIC_ACTION)
    abstract class StorageCallable<V> implements Callable<V> {
        public V call() {
            try {
                return doStorageOperation();
            }
            catch (StorageException e) {
                logger.error("Failure in asynchronous call to executeQuery", e);
                if (exceptionHandler != null)
                    exceptionHandler.handleException(e);
                throw e;
            }
        }
        abstract protected V doStorageOperation();
    }
   
    @LogMessageDoc(level="ERROR",
            message="Failure in asynchronous call to updateRows",
            explanation=DB_ERROR_EXPLANATION,
            recommendation=LogMessageDoc.GENERIC_ACTION)
    abstract class StorageRunnable implements Runnable {
        public void run() {
            try {
                doStorageOperation();
            }
            catch (StorageException e) {
                logger.error("Failure in asynchronous call to updateRows", e);
                if (exceptionHandler != null)
                    exceptionHandler.handleException(e);
                throw e;
            }
        }
        abstract void doStorageOperation();
    }
   
    public AbstractStorageSource() {
        this.executorService = defaultExecutorService;
    }

    public void setExecutorService(ExecutorService executorService) {
        this.executorService = (executorService != null) ?
                executorService : defaultExecutorService;
    }
   
    @Override
    public void setExceptionHandler(IStorageExceptionHandler exceptionHandler) {
        this.exceptionHandler = exceptionHandler;
    }
   
    @Override
    public abstract void setTablePrimaryKeyName(String tableName, String primaryKeyName);

    @Override
    public void createTable(String tableName, Set<String> indexedColumns) {
        allTableNames.add(tableName);
    }

    @Override
    public Set<String> getAllTableNames() {
        return allTableNames;
    }
   
    public void setCounterStore(CounterStore counterStore) {
        this.counterStore = counterStore;
    }
   
    protected void updateCounters(String baseName, String tableName) {
        if (counterStore != null) {
            String counterName;
            if (tableName != null) {
                updateCounters(baseName, null);
                counterName = baseName + CounterStore.TitleDelimitor + tableName;
            } else {
                counterName = baseName;
            }
            ICounter counter = counterStore.getCounter(counterName);
            if (counter == null) {
                counter = counterStore.createCounter(counterName, CounterType.LONG);
            }
            counter.increment();
        }
    }
   
    @Override
    public abstract IQuery createQuery(String tableName, String[] columnNames,
            IPredicate predicate, RowOrdering ordering);

    @Override
    public IResultSet executeQuery(IQuery query) {
        updateCounters(STORAGE_QUERY_COUNTER_NAME, query.getTableName());
        return executeQueryImpl(query);
    }
   
    protected abstract IResultSet executeQueryImpl(IQuery query);

    @Override
    public IResultSet executeQuery(String tableName, String[] columnNames,
            IPredicate predicate, RowOrdering ordering) {
        IQuery query = createQuery(tableName, columnNames, predicate, ordering);
        IResultSet resultSet = executeQuery(query);
        return resultSet;
    }

    @Override
    public Object[] executeQuery(String tableName, String[] columnNames,
            IPredicate predicate, RowOrdering ordering, IRowMapper rowMapper) {
        List<Object> objectList = new ArrayList<Object>();
        IResultSet resultSet = executeQuery(tableName, columnNames, predicate, ordering);
        while (resultSet.next()) {
            Object object = rowMapper.mapRow(resultSet);
            objectList.add(object);
        }
        return objectList.toArray();
    }
   
    @Override
    public Future<IResultSet> executeQueryAsync(final IQuery query) {
        Future<IResultSet> future = executorService.submit(
            new StorageCallable<IResultSet>() {
                public IResultSet doStorageOperation() {
                    return executeQuery(query);
                }
            });
        return future;
    }

    @Override
    public Future<IResultSet> executeQueryAsync(final String tableName,
            final String[] columnNames,  final IPredicate predicate,
            final RowOrdering ordering) {
        Future<IResultSet> future = executorService.submit(
            new StorageCallable<IResultSet>() {
                public IResultSet doStorageOperation() {
                    return executeQuery(tableName, columnNames,
                            predicate, ordering);
                }
            });
        return future;
    }

    @Override
    public Future<Object[]> executeQueryAsync(final String tableName,
            final String[] columnNames,  final IPredicate predicate,
            final RowOrdering ordering, final IRowMapper rowMapper) {
        Future<Object[]> future = executorService.submit(
            new StorageCallable<Object[]>() {
                public Object[] doStorageOperation() {
                    return executeQuery(tableName, columnNames, predicate,
                            ordering, rowMapper);
                }
            });
        return future;
    }

    @Override
    public Future<?> insertRowAsync(final String tableName,
            final Map<String,Object> values) {
        Future<?> future = executorService.submit(
            new StorageRunnable() {
                public void doStorageOperation() {
                    insertRow(tableName, values);
                }
            }, null);
        return future;
    }

    @Override
    public Future<?> updateRowsAsync(final String tableName, final List<Map<String,Object>> rows) {
        Future<?> future = executorService.submit(   
            new StorageRunnable() {
                public void doStorageOperation() {
                    updateRows(tableName, rows);
                }
            }, null);
        return future;
    }

    @Override
    public Future<?> updateMatchingRowsAsync(final String tableName,
            final IPredicate predicate, final Map<String,Object> values) {
        Future<?> future = executorService.submit(   
            new StorageRunnable() {
                public void doStorageOperation() {
                    updateMatchingRows(tableName, predicate, values);
                }
            }, null);
        return future;
    }

    @Override
    public Future<?> updateRowAsync(final String tableName,
            final Object rowKey, final Map<String,Object> values) {
        Future<?> future = executorService.submit(
            new StorageRunnable() {
                public void doStorageOperation() {
                    updateRow(tableName, rowKey, values);
                }
            }, null);
        return future;
    }

    @Override
    public Future<?> updateRowAsync(final String tableName,
            final Map<String,Object> values) {
        Future<?> future = executorService.submit(
            new StorageRunnable() {
                public void doStorageOperation() {
                    updateRow(tableName, values);
                }
            }, null);
        return future;
    }

    @Override
    public Future<?> deleteRowAsync(final String tableName, final Object rowKey) {
        Future<?> future = executorService.submit(
            new StorageRunnable() {
                public void doStorageOperation() {
                    deleteRow(tableName, rowKey);
                }
            }, null);
        return future;
    }

    @Override
    public Future<?> deleteRowsAsync(final String tableName, final Set<Object> rowKeys) {
        Future<?> future = executorService.submit(
                new StorageRunnable() {
                    public void doStorageOperation() {
                        deleteRows(tableName, rowKeys);
                    }
                }, null);
        return future;
    }

    @Override
    public Future<?> deleteMatchingRowsAsync(final String tableName, final IPredicate predicate) {
        Future<?> future = executorService.submit(
                new StorageRunnable() {
                    public void doStorageOperation() {
                        deleteMatchingRows(tableName, predicate);
                    }
                }, null);
        return future;
    }

    @Override
    public Future<?> getRowAsync(final String tableName, final Object rowKey) {
        Future<?> future = executorService.submit(
            new StorageRunnable() {
                public void doStorageOperation() {
                    getRow(tableName, rowKey);
                }
            }, null);
        return future;
    }
   
    @Override
    public Future<?> saveAsync(final IResultSet resultSet) {
        Future<?> future = executorService.submit(
            new StorageRunnable() {
                public void doStorageOperation() {
                    resultSet.save();
                }
            }, null);
        return future;
    }

    @Override
    public void insertRow(String tableName, Map<String, Object> values) {
        updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName);
        insertRowImpl(tableName, values);
    }

    protected abstract void insertRowImpl(String tableName, Map<String, Object> values);

   
    @Override
    public void updateRows(String tableName, List<Map<String,Object>> rows) {
        updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName);
        updateRowsImpl(tableName, rows);
    }

    protected abstract void updateRowsImpl(String tableName, List<Map<String,Object>> rows);

    @Override
    public void updateMatchingRows(String tableName, IPredicate predicate,
            Map<String, Object> values) {
        updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName);
        updateMatchingRowsImpl(tableName, predicate, values);
    }
   
    protected abstract void updateMatchingRowsImpl(String tableName, IPredicate predicate,
                                    Map<String, Object> values);

    @Override
    public void updateRow(String tableName, Object rowKey,
            Map<String, Object> values) {
        updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName);
        updateRowImpl(tableName, rowKey, values);
    }
   
    protected abstract void updateRowImpl(String tableName, Object rowKey,
                                   Map<String, Object> values);

    @Override
    public void updateRow(String tableName, Map<String, Object> values) {
        updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName);
        updateRowImpl(tableName, values);
    }
   
    protected abstract void updateRowImpl(String tableName, Map<String, Object> values);

    @Override
    public void deleteRow(String tableName, Object rowKey) {
        updateCounters(STORAGE_DELETE_COUNTER_NAME, tableName);
        deleteRowImpl(tableName, rowKey);
    }
   
    protected abstract void deleteRowImpl(String tableName, Object rowKey);

    @Override
    public void deleteRows(String tableName, Set<Object> rowKeys) {
        updateCounters(STORAGE_DELETE_COUNTER_NAME, tableName);
        deleteRowsImpl(tableName, rowKeys);
    }

    protected abstract void deleteRowsImpl(String tableName, Set<Object> rowKeys);

    @Override
    public void deleteMatchingRows(String tableName, IPredicate predicate) {
        IResultSet resultSet = null;
        try {
            resultSet = executeQuery(tableName, null, predicate, null);
            while (resultSet.next()) {
                resultSet.deleteRow();
            }
            resultSet.save();
        }
        finally {
            if (resultSet != null)
                resultSet.close();
        }
    }
   
    @Override
    public IResultSet getRow(String tableName, Object rowKey) {
        updateCounters(STORAGE_QUERY_COUNTER_NAME, tableName);
        return getRowImpl(tableName, rowKey);
    }

    protected abstract IResultSet getRowImpl(String tableName, Object rowKey);

    @Override
    public synchronized void addListener(String tableName, IStorageSourceListener listener) {
        Set<IStorageSourceListener> tableListeners = listeners.get(tableName);
        if (tableListeners == null) {
            tableListeners = new CopyOnWriteArraySet<IStorageSourceListener>();
            listeners.put(tableName, tableListeners);
        }
        tableListeners.add(listener);
    }
 
    @Override
    public synchronized void removeListener(String tableName, IStorageSourceListener listener) {
        Set<IStorageSourceListener> tableListeners = listeners.get(tableName);
        if (tableListeners != null) {
            tableListeners.remove(listener);
        }
    }

    @LogMessageDoc(level="ERROR",
            message="Exception caught handling storage notification",
            explanation="An unknown error occured while trying to notify" +
                " storage listeners",
            recommendation=LogMessageDoc.GENERIC_ACTION)
    protected synchronized void notifyListeners(StorageSourceNotification notification) {
        if (logger.isTraceEnabled()) {
            logger.trace("Notifying storage listeneres: {}", notification);
        }
        String tableName = notification.getTableName();
        Set<Object> keys = notification.getKeys();
        Set<IStorageSourceListener> tableListeners = listeners.get(tableName);
        if (tableListeners != null) {
            for (IStorageSourceListener listener : tableListeners) {
                try {
                    switch (notification.getAction()) {
                        case MODIFY:
                            listener.rowsModified(tableName, keys);
                            break;
                        case DELETE:
                            listener.rowsDeleted(tableName, keys);
                            break;
                    }
                }
                catch (Exception e) {
                    logger.error("Exception caught handling storage notification", e);
                }
            }
        }
    }
   
    @Override
    public void notifyListeners(List<StorageSourceNotification> notifications) {
        for (StorageSourceNotification notification : notifications)
            notifyListeners(notification);
    }
   
    // IFloodlightModule

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
        Collection<Class<? extends IFloodlightService>> l =
                new ArrayList<Class<? extends IFloodlightService>>();
        l.add(IStorageSourceService.class);
        return l;
    }
   
    @Override
    public Map<Class<? extends IFloodlightService>,
               IFloodlightService> getServiceImpls() {
        Map<Class<? extends IFloodlightService>,
            IFloodlightService> m =
                new HashMap<Class<? extends IFloodlightService>,
                            IFloodlightService>();
        m.put(IStorageSourceService.class, this);
        return m;
    }
   
    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
        Collection<Class<? extends IFloodlightService>> l =
                new ArrayList<Class<? extends IFloodlightService>>();
        l.add(IRestApiService.class);
        l.add(ICounterStoreService.class);
        return l;
    }

    @Override
    public void init(FloodlightModuleContext context)
            throws FloodlightModuleException {
        restApi =
           context.getServiceImpl(IRestApiService.class);
        counterStore =
            context.getServiceImpl(ICounterStoreService.class);
    }

    @Override
    public void startUp(FloodlightModuleContext context) {
        restApi.addRestletRoutable(new StorageWebRoutable());
    }
}
TOP

Related Classes of net.floodlightcontroller.storage.AbstractStorageSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.