Package org.auraframework.impl

Source Code of org.auraframework.impl.CachingServiceImpl

/*
* Copyright (C) 2013 salesforce.com, 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 org.auraframework.impl;

import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import org.apache.log4j.Logger;
import org.auraframework.Aura;
import org.auraframework.builder.CacheBuilder;
import org.auraframework.cache.Cache;
import org.auraframework.def.ApplicationDef;
import org.auraframework.def.ComponentDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.def.Definition;
import org.auraframework.def.DefDescriptor.DefType;
import org.auraframework.def.LibraryDef;
import org.auraframework.impl.cache.CacheImpl;
import org.auraframework.service.CachingService;
import org.auraframework.service.DefinitionService;
import org.auraframework.system.DependencyEntry;
import org.auraframework.system.SourceListener;

import com.google.common.base.Optional;

public class CachingServiceImpl implements CachingService {

    private static final long serialVersionUID = -3311707270226573084L;
    private final static int DEFINITION_CACHE_SIZE = 4096;
    private final static int DEPENDENCY_CACHE_SIZE = 1024;
    private final static int FILTER_CACHE_SIZE = 1024;
    private final static int STRING_CACHE_SIZE = 100;
    private final static int CLIENT_LIB_CACHE_SIZE = 30;

    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final WriteLock wLock = rwLock.writeLock();

    @Override
    public <K, T> CacheBuilder<K, T> getCacheBuilder() {
        return new CacheImpl.Builder<>();
    }

    private final Cache<DefDescriptor<?>, Boolean> existsCache;
    private final Cache<DefDescriptor<?>, Optional<? extends Definition>> defsCache;
    private final Cache<String, String> stringsCache;
    private final Cache<String, Set<DefDescriptor<?>>> descriptorFilterCache;
    private final Cache<String, DependencyEntry> depsCache;
    private final Cache<String, String> clientLibraryOutputCache;
    private final Cache<String, Set<String>> clientLibraryUrlsCache;
    private final Cache<DefDescriptor.DescriptorKey, DefDescriptor<? extends Definition>> defDescriptorByNameCache;

    private static final Logger logger = Logger.getLogger(CachingServiceImpl.class);

    public CachingServiceImpl() {
        existsCache = this.<DefDescriptor<?>, Boolean> getCacheBuilder()
                .setInitialSize(DEFINITION_CACHE_SIZE)
                .setMaximumSize(DEFINITION_CACHE_SIZE).setRecordStats(true)
                .setName("existsCache")
                .setSoftValues(true).build();

        defsCache = this
                .<DefDescriptor<?>, Optional<? extends Definition>> getCacheBuilder()
                .setInitialSize(DEFINITION_CACHE_SIZE)
                .setMaximumSize(DEFINITION_CACHE_SIZE).setRecordStats(true)
                .setName("defsCache")
                .setSoftValues(true).build();

        stringsCache = this.<String, String> getCacheBuilder()
                .setInitialSize(STRING_CACHE_SIZE)
                .setMaximumSize(STRING_CACHE_SIZE).setRecordStats(true)
                .setName("stringsCache")
                .setSoftValues(true).build();

        descriptorFilterCache = this
                .<String, Set<DefDescriptor<?>>> getCacheBuilder()
                .setInitialSize(FILTER_CACHE_SIZE)
                .setMaximumSize(FILTER_CACHE_SIZE).setRecordStats(true)
                .setName("descriptorFilterCache")
                .setSoftValues(true).build();

        depsCache = this.<String, DependencyEntry> getCacheBuilder()
                .setInitialSize(DEPENDENCY_CACHE_SIZE)
                .setMaximumSize(DEPENDENCY_CACHE_SIZE).setRecordStats(true)
                .setName("depsCache")
                .setSoftValues(true).build();

        clientLibraryOutputCache = this.<String, String> getCacheBuilder()
                .setInitialSize(CLIENT_LIB_CACHE_SIZE)
                .setMaximumSize(CLIENT_LIB_CACHE_SIZE).setSoftValues(true)
                .setName("clientLibraryOutputCache")
                .setRecordStats(true).build();

        clientLibraryUrlsCache = this.<String, Set<String>> getCacheBuilder()
                .setInitialSize(CLIENT_LIB_CACHE_SIZE)
                .setMaximumSize(CLIENT_LIB_CACHE_SIZE).setSoftValues(true)
                .setName("clientLibraryUrlsCache")
                .setRecordStats(true).build();

        defDescriptorByNameCache =
                this.<DefDescriptor.DescriptorKey, DefDescriptor<? extends Definition>> getCacheBuilder()
                        .setInitialSize(512)
                        .setMaximumSize(1024 * 10)
                        .setConcurrencyLevel(20)
                        .setName("defDescByNameCache")
                        .build();
    }

    @Override
    public final Cache<DefDescriptor<?>, Boolean> getExistsCache() {
        return existsCache;
    }

    @Override
    public final Cache<DefDescriptor<?>, Optional<? extends Definition>> getDefsCache() {
        return defsCache;
    }

    @Override
    public final Cache<String, String> getStringsCache() {
        return stringsCache;
    }

    @Override
    public final Cache<String, Set<DefDescriptor<?>>> getDescriptorFilterCache() {
        return descriptorFilterCache;
    }

    @Override
    public final Cache<String, DependencyEntry> getDepsCache() {
        return depsCache;
    }

    @Override
    public final Cache<String, String> getClientLibraryOutputCache() {
        return clientLibraryOutputCache;
    }

    @Override
    public final Cache<String, Set<String>> getClientLibraryUrlsCache() {
        return clientLibraryUrlsCache;
    }

    @Override
    public final Cache<DefDescriptor.DescriptorKey, DefDescriptor<? extends Definition>> getDefDescriptorByNameCache() {
        return defDescriptorByNameCache;
    }

    @Override
    public Lock getReadLock() {
        return rwLock.readLock();
    }

    @Override
    public Lock getWriteLock() {
        return rwLock.writeLock();
    }

    /**
     * The driver for cache-consistency management in response to source changes. MDR drives the process, will notify
     * all registered listeners while write blocking, then invalidate it's own caches. If this routine can't acquire the
     * lock , it will log it as an non-fatal error, as it only results in staleness.
     *
     * @param listeners - collections of listeners to notify of source changes
     * @param source - DefDescriptor that changed - for granular cache clear (currently not considered here, but other
     *            listeners may make use of it)
     * @param event - what type of event triggered the change
     */
    @Override
    public void notifyDependentSourceChange(
            Collection<WeakReference<SourceListener>> listeners,
            DefDescriptor<?> source, SourceListener.SourceMonitorEvent event,
            String filePath) {
        boolean haveLock = false;

        try {
            // We have now eliminated all known deadlocks, but for production
            // safety, we never want to block forever
            haveLock = wLock.tryLock(5, TimeUnit.SECONDS);

            // If this occurs, we have a new deadlock. But it only means
            // temporary cache staleness, so it is not fatal
            if (!haveLock) {
                logger.error("Couldn't acquire cache clear lock in a reasonable time.  Cache may be stale until next clear.");
                return;
            }

            // successfully acquired the lock, start clearing caches
            // notify provided listeners, presumably to clear caches
            for (WeakReference<SourceListener> i : listeners) {
                SourceListener sl = i.get();

                if (sl != null) {
                    sl.onSourceChanged(source, event, filePath);
                }
            }
            // lastly, clear MDR's static caches
            invalidateSourceRelatedCaches(source);

        } catch (InterruptedException e) {
        } finally {
            if (haveLock) {
                wLock.unlock();
            }
        }
    }

    private void invalidateSourceRelatedCaches(DefDescriptor<?> descriptor) {

        depsCache.invalidateAll();
        descriptorFilterCache.invalidateAll();
        stringsCache.invalidateAll();

        if (descriptor == null) {
            defsCache.invalidateAll();
            existsCache.invalidateAll();
        } else {
            DefinitionService ds = Aura.getDefinitionService();
            DefDescriptor<ComponentDef> cdesc = ds.getDefDescriptor(descriptor,
                    "markup", ComponentDef.class);
            DefDescriptor<ApplicationDef> adesc = ds.getDefDescriptor(
                    descriptor, "markup", ApplicationDef.class);

            defsCache.invalidate(descriptor);
            existsCache.invalidate(descriptor);
            defsCache.invalidate(cdesc);
            existsCache.invalidate(cdesc);
            defsCache.invalidate(adesc);
            existsCache.invalidate(adesc);

            switch (descriptor.getDefType()) {
            case NAMESPACE:
                // invalidate all DDs with the same namespace if its a namespace DD
                invalidateScope(descriptor, true, false);
                break;
            case LAYOUTS:
                invalidateScope(descriptor, true, true);
                break;
            case INCLUDE:
                invalidateSourceRelatedCaches(descriptor.getBundle());
                break;
            default:
            }
        }
    }

    private void invalidateScope(DefDescriptor<?> descriptor, boolean clearNamespace, boolean clearName) {

        final Set<DefDescriptor<?>> defsKeySet = defsCache.getKeySet();
        final String namespace = descriptor.getNamespace();
        final String name = descriptor.getName();

        for (DefDescriptor<?> dd : defsKeySet) {
            boolean sameNamespace = namespace.equals(dd.getNamespace());
            boolean sameName = name.equals(dd.getName());
            boolean shouldClear = (clearNamespace && clearName) ? (clearNamespace && sameNamespace)
                    && (clearName && sameName)
                    : (clearNamespace && sameNamespace)
                            || (clearName && sameName);

            if (shouldClear) {
                defsCache.invalidate(dd);
                existsCache.invalidate(dd);
            }
        }

    }

}
TOP

Related Classes of org.auraframework.impl.CachingServiceImpl

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.