/******************************************************************************* * Copyright (c) 2007, 2010 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.indexing; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.queryparser.classic.ParseException; import org.eclipse.core.runtime.IProgressMonitor; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.exception.DatabaseException; import org.simantics.db.indexing.exception.IndexingException; import org.simantics.db.layer0.adapter.GenericRelation; import org.simantics.utils.datastructures.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Tuukka Lehtonen * @author Antti Villberg */ public class IndexedRelationsSearcher extends IndexedRelationsSearcherBase { private static final Logger LOGGER = LoggerFactory.getLogger(IndexedRelationsSearcher.class); IndexedRelationsMemorySearcher cache; IndexedRelationsSearcher(RequestProcessor session, Resource relation, Resource input, GenericRelation r) throws DatabaseException { super(session, relation, input); this.cache = new IndexedRelationsMemorySearcher(session, this, relation, input, r); } @Override String getDescriptor() { return "DISK: "; } @Override public void setProblem(Throwable t) { super.setProblem(t); cache.setProblem(t); } @Override boolean startAccess(IProgressMonitor monitor, Session session, boolean forWriting) { boolean success = super.startAccess(monitor, session, false); if(!success) return false; success = cache.startAccess(monitor, session, forWriting); if(!success) { setProblem(cache.getException()); return false; } else return true; } @Override void insertIndex(IProgressMonitor monitor, GenericRelation r, int boundLength, Collection documentsData) throws CorruptIndexException, IOException, DatabaseException { Collection keyValues = new ArrayList(); for(Object[] data : documentsData) { keyValues.add(data[1]); } cache.replaceIndex(monitor, "Resource", keyValues, r, boundLength, documentsData); //cache.commit(); } @Override void removeIndex(IProgressMonitor monitor, GenericRelation r, RequestProcessor processor, String key, Collection keyValues) throws DatabaseException,CorruptIndexException, IOException { Collection documentsData = new ArrayList(); Pair[] fields = r.getFields(); for(Object keyValue : keyValues) { Object[] data = new Object[fields.length-1]; int index = 0; for(int i=1;i keyValues, GenericRelation r, int boundLength, Collection documentsData) throws CorruptIndexException, IOException, DatabaseException { boolean result = cache.replaceIndex(monitor, key, keyValues, r, boundLength, documentsData); // cache.commit(); return result; } List> persistentCachedSearch(IProgressMonitor monitor, RequestProcessor processor, String search, int maxResultCount) throws ParseException, IOException, IndexingException { MemoryIndexing mem = MemoryIndexing.getInstance(session.getSession()); String key = indexPath.toAbsolutePath().toString(); Map>> cache = mem.persistentCache.get(key); if(cache != null) { List> result = cache.get(search); if(result != null) return result; } startAccess(monitor, processor.getSession(), false); List> results = super.doSearch(monitor, processor, search, maxResultCount); if(cache == null) { cache = new HashMap>>(); mem.persistentCache.put(key, cache); } if(results.size() < 500) cache.put(search, results); return results; } List persistentCachedSearchResources(IProgressMonitor monitor, RequestProcessor processor, String search, int maxResultCount) throws ParseException, IOException, IndexingException { MemoryIndexing mem = MemoryIndexing.getInstance(session.getSession()); String key = indexPath.toAbsolutePath().toString(); Map> cache = mem.persistentCacheResources.get(key); if(cache != null) { List result = cache.get(search); if(result != null) return result; } startAccess(monitor, processor.getSession(), false); List results = super.doSearchResources(monitor, processor, search, maxResultCount); if(cache == null) { cache = new HashMap>(); mem.persistentCacheResources.put(key, cache); } if(results.size() < 500) cache.put(search, results); return results; } List persistentCachedList(IProgressMonitor monitor, RequestProcessor processor) throws ParseException, IOException, IndexingException { startAccess(monitor, processor.getSession(), false); List results = super.doList(monitor, processor); return results; } @Override List> doSearch(IProgressMonitor monitor, RequestProcessor processor, String search, int maxResultCount) throws ParseException, IOException, IndexingException { List> persistent = persistentCachedSearch(monitor, processor, search, maxResultCount); List> cached = cache.doSearch(monitor, processor, search, maxResultCount); ArrayList> result = new ArrayList>(); for(Map m : persistent) { Resource r = (Resource)m.get("Resource"); if(!cache.changed.contains(r.getResourceId())) { result.add(m); } } result.addAll(cached); return result; } @Override List doSearchResources(IProgressMonitor monitor, RequestProcessor processor, String search, int maxResultCount) throws ParseException, IOException, IndexingException { List persistent = persistentCachedSearchResources(monitor, processor, search, maxResultCount); List cached = cache.doSearchResources(monitor, processor, search, maxResultCount); ArrayList result = new ArrayList(); for(Resource r : persistent) { if(!cache.changed.contains(r.getResourceId())) { result.add(r); } } result.addAll(cached); return result; } List doList(IProgressMonitor monitor, RequestProcessor processor) throws ParseException, IOException, IndexingException { List persistent = persistentCachedList(monitor, processor); // TODO: check that caches have been properly flushed //List cached = cache.doList(monitor, processor); //if(!cached.isEmpty()) throw new DatabaseException("doList does not support caching"); return persistent; } void applyChanges(IProgressMonitor monitor, Session session, GenericRelation r, Collection os) throws Exception { if(!os.isEmpty()) { ArrayList replaceKeys = new ArrayList(); ArrayList replaceValues = new ArrayList(); ArrayList removeKeys = new ArrayList(); for(Object[] o : os) { Long parent = (Long)o[0]; Long key = (Long)o[1]; if(parent != 0) { replaceKeys.add(key); replaceValues.add(o); } else { removeKeys.add(key); } } changeState(monitor, session, State.READY); super.startAccess(null, session, true); super.replaceIndex(null, "Resource", replaceKeys, r, 1, replaceValues); super.removeIndex(null, r, null, "Resource", removeKeys); } changeState(monitor, session, State.READY); } @Override Throwable bestEffortClear(IProgressMonitor monitor, Session session) { // Free the index changeState(monitor, session, State.NONE); Throwable t = clearDirectory(monitor, session); if(t != null) return t; t = cache.bestEffortClear(monitor, session); if(t != null) return t; String key = indexPath.toAbsolutePath().toString(); MemoryIndexing mem = MemoryIndexing.getInstance(session); mem.persistentCache.remove(key); mem.persistentCacheResources.remove(key); return null; } @Override protected Logger getLogger() { return LOGGER; } }