/******************************************************************************* * Copyright (c) 2012 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.db.common; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import org.simantics.db.Resource; import org.simantics.db.WriteOnlyGraph; import org.simantics.db.common.utils.Logger; /** * A internal temporary store for database indexing-related low-level utilities * and static data. * * This will be moved to more a more logical location at some point. * * @author Antti Villberg * @author Tuukka Lehtonen * @since 1.8 */ public class Indexing { private static final boolean PROFILE = false; private static Set indexPendings = new HashSet(); private static AtomicBoolean dependenciesIndexingDisabled = new AtomicBoolean(); private static int indexPendingCounter = 0; private static Map, Object>> caches = new HashMap, Object>>(); private static boolean useIndexing = true; @SuppressWarnings("unchecked") public static T getCache(Resource root, Class clazz) { Map,Object> cache = caches.get(root); if(cache == null) return null; return (T)cache.get(clazz); } public static T createCache(Resource root, T object) { Map,Object> cache = caches.get(root); if(cache == null) { cache = new HashMap,Object>(); caches.put(root, cache); } cache.put(object.getClass(), object); return object; } public static void clearCaches(Resource root) { caches.remove(root); } public static UUID makeIndexPending() { synchronized (indexPendings) { UUID guid = UUID.randomUUID(); indexPendings.add(guid); return guid; } } public static void releaseIndexPending(UUID guid) { synchronized (indexPendings) { indexPendings.remove(guid); if (indexPendings.isEmpty()) { indexPendings.notifyAll(); indexPendingCounter++; } } } public static int getIndexPendingCounter() { synchronized (indexPendings) { return indexPendingCounter; } } public static boolean isIndexPending() { synchronized (indexPendings) { return !indexPendings.isEmpty(); } } private static long totalWaitTime = 0; public static void waitIndexPending() { long startTime = PROFILE ? System.nanoTime() : 0; boolean waited = false; int time = 1; synchronized (indexPendings) { while (isIndexPending()) { try { waited = true; indexPendings.wait(time++); if (time > 10) time = 10; } catch (InterruptedException e) { Logger.defaultLogError(e); } } } if (PROFILE) { if (waited) { long endTime = System.nanoTime(); long waitTime = endTime - startTime; totalWaitTime += waitTime; System.out.println("Indexing wait time " + (waitTime*1e-6) + " ms (total " + (totalWaitTime*1e-6) + " ms)"); } } } /** * @param graph an active database write handle to prove one is in a write * transaction and wants to disable dependencies indexing for this * transaction only. * @return previous value */ public static boolean setDependenciesIndexingDisabled(WriteOnlyGraph graph, boolean disabled) { if (graph == null) throw new NullPointerException("null write graph"); // TODO: check that graph is valid once made possible return dependenciesIndexingDisabled.getAndSet(disabled); } public static boolean resetDependenciesIndexingDisabled() { return dependenciesIndexingDisabled.compareAndSet(true, false); } public static boolean isDependenciesIndexingDisabled() { if (!useIndexing) return true; return dependenciesIndexingDisabled.get(); } public static void setDefaultDependenciesIndexingEnabled(boolean b) { useIndexing = b; } }