From 7d1e89a9fae9c86a238e5ec2896b5baeda46cc13 Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Tue, 28 Mar 2006 16:22:54 +0000 Subject: [PATCH] A smarter way to deal with readers/writers of PDOM database, i.e. using scheduling rules and priorities. --- .../eclipse/cdt/core/dom/IPDOMIndexer.java | 26 +++ .../cdt/internal/core/pdom/PDOMDatabase.java | 83 ++++--- .../core/pdom/indexer/fast/PDOMFastAddTU.java | 48 ++++ .../pdom/indexer/fast/PDOMFastChangeTU.java | 49 ++++ .../pdom/indexer/fast/PDOMFastIndexer.java | 214 ++++++++++++++++++ .../pdom/indexer/fast/PDOMFastRemoveTU.java | 51 +++++ 6 files changed, 428 insertions(+), 43 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/IPDOMIndexer.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastAddTU.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastChangeTU.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastIndexer.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastRemoveTU.java diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/IPDOMIndexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/IPDOMIndexer.java new file mode 100644 index 00000000000..4146682cbc3 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/IPDOMIndexer.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2006 QNX Software Systems and others. + * 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: + * QNX - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.dom; + +import org.eclipse.cdt.core.model.IElementChangedListener; + +/** + * @author Doug Schaefer + * + */ +public interface IPDOMIndexer extends IElementChangedListener { + + public void setPDOM(IPDOM pdom); + + public void reindex(); + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMDatabase.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMDatabase.java index 4ff0d397d3d..854224a6426 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMDatabase.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMDatabase.java @@ -38,6 +38,7 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.core.runtime.jobs.ISchedulingRule; /** * The PDOM Database. @@ -46,6 +47,8 @@ import org.eclipse.core.runtime.QualifiedName; */ public class PDOMDatabase implements IPDOM { + private final IProject project; + private final IPath dbPath; private Database db; @@ -60,6 +63,7 @@ public class PDOMDatabase implements IPDOM { = new QualifiedName(CCorePlugin.PLUGIN_ID, "dbName"); //$NON-NLS-1$ public PDOMDatabase(IProject project, PDOMManager manager) throws CoreException { + this.project = project; String dbName = project.getPersistentProperty(dbNameProperty); if (dbName == null) { dbName = project.getName() + "_" @@ -71,6 +75,10 @@ public class PDOMDatabase implements IPDOM { db = new Database(dbPath.toOSString(), VERSION); } + public IProject getProject() { + return project; + } + public static interface IListener { public void handleChange(PDOMDatabase pdom); } @@ -241,54 +249,43 @@ public class PDOMDatabase implements IPDOM { return PDOMLinkage.getLinkage(this, record).getBinding(record); } - // Read-write lock. Since we want to allow reads during a long - // running index, readers take precidence. - private Object lockMutex = new Object(); - private int lockCount; - private int waitingReaders; - private int waitingWriters; - - public void getReadLock(boolean waitForWrites) throws InterruptedException { - synchronized (lockMutex) { - if (!waitForWrites) - ++waitingReaders; - while (lockCount < 0 || (waitForWrites && waitingWriters > 0)) - // wait for the writers to finish - lockMutex.wait(); - // free to go - ++lockCount; - if (!waitForWrites) - --waitingReaders; + // Read-write lock rules. Readers don't conflict with other readers, + // Writers conflict with readers, and everyone conflicts with writers. + private class ReaderLockRule implements ISchedulingRule { + public boolean isConflicting(ISchedulingRule rule) { + if (rule == this) + return false; + else if (rule == getWriterLockRule()) + return true; + else + return false; + } + public boolean contains(ISchedulingRule rule) { + return rule == this; + } + } + + private class WriterLockRule implements ISchedulingRule { + public boolean isConflicting(ISchedulingRule rule) { + if (rule == this || rule == getReaderLockRule()) + return true; + else + return false; + } + public boolean contains(ISchedulingRule rule) { + return rule == this; } } - public void getWriteLock() throws InterruptedException { - synchronized (lockMutex) { - ++waitingWriters; - while (lockCount != 0 || waitingReaders > 0) - // wait for everyone to finish - // readers get precidence - lockMutex.wait(); - - // free to go - --lockCount; - --waitingWriters; - } + private ReaderLockRule readerLockRule = new ReaderLockRule(); + private WriterLockRule writerLockRule = new WriterLockRule(); + + public ISchedulingRule getReaderLockRule() { + return readerLockRule; } - public void releaseReadLock() { - synchronized (lockMutex) { - if (lockCount > 0) - --lockCount; - lockMutex.notifyAll(); - } + public ISchedulingRule getWriterLockRule() { + return writerLockRule; } - public void releaseWriteLock() { - synchronized (lockMutex) { - if (lockCount < 0) - ++lockCount; - lockMutex.notifyAll(); - } - } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastAddTU.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastAddTU.java new file mode 100644 index 00000000000..fc3109c764a --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastAddTU.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2006 QNX Software Systems and others. + * 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: + * QNX - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.pdom.indexer.fast; + +import org.eclipse.cdt.core.dom.IPDOM; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.pdom.PDOMDatabase; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +/** + * @author Doug Schaefer + * + */ +public class PDOMFastAddTU extends Job { + + private final ITranslationUnit tu; + private final IPDOM pdom; + + public PDOMFastAddTU(IPDOM pdom, ITranslationUnit tu) { + super("PDOM Fast Add TU"); + this.pdom = pdom; + this.tu = tu; + } + + protected IStatus run(IProgressMonitor monitor) { + try { + PDOMDatabase mypdom = (PDOMDatabase)pdom; + mypdom.addSymbols(tu); + return Status.OK_STATUS; + } catch (CoreException e) { + return e.getStatus(); + } + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastChangeTU.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastChangeTU.java new file mode 100644 index 00000000000..0689d0e5569 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastChangeTU.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2006 QNX Software Systems and others. + * 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: + * QNX - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.pdom.indexer.fast; + +import org.eclipse.cdt.core.dom.IPDOM; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.pdom.PDOMDatabase; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +/** + * @author Doug Schaefer + * + */ +public class PDOMFastChangeTU extends Job { + + private final IPDOM pdom; + private final ITranslationUnit tu; + + public PDOMFastChangeTU(IPDOM pdom, ITranslationUnit tu) { + super("PDOM Fast Change TU"); + this.pdom = pdom; + this.tu = tu; + } + + protected IStatus run(IProgressMonitor monitor) { + try { + PDOMDatabase mypdom = (PDOMDatabase)pdom; + mypdom.removeSymbols(tu); + mypdom.addSymbols(tu); + return Status.OK_STATUS; + } catch (CoreException e) { + return e.getStatus(); + } + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastIndexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastIndexer.java new file mode 100644 index 00000000000..0d32b1b5f64 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastIndexer.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright (c) 2006 QNX Software Systems and others. + * 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: + * QNX - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.pdom.indexer.fast; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.IPDOM; +import org.eclipse.cdt.core.dom.IPDOMIndexer; +import org.eclipse.cdt.core.dom.PDOM; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ElementChangedEvent; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICElementDelta; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.pdom.PDOMDatabase; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceProxy; +import org.eclipse.core.resources.IResourceProxyVisitor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.core.runtime.jobs.Job; + +/** + * @author Doug Schaefer + * + */ +public class PDOMFastIndexer implements IPDOMIndexer { + + private PDOMDatabase pdom; + + public void setPDOM(IPDOM pdom) { + if (pdom instanceof PDOMDatabase) + this.pdom = (PDOMDatabase)pdom; + } + + private class ChangeHandler extends Job { + private final ICElementDelta delta; + private List addedTUs; + private List changedTUs; + private List removedTUs; + + public ChangeHandler(ElementChangedEvent event) { + super("Change Handler"); + delta = event.getDelta(); + } + + protected IStatus run(IProgressMonitor monitor) { + long start = System.currentTimeMillis(); + + String taskName = null; + processDelta(delta); + taskName = "Update PDOM"; + +// if (project != null) { +// processNewProject(project); +// taskName = "Rebuild PDOM"; +// } + + int count + = (addedTUs != null ? addedTUs.size() : 0) + + (changedTUs != null ? changedTUs.size() : 0) + + (removedTUs != null ? removedTUs.size() : 0); + + if (taskName == null || count == 0) + return Status.OK_STATUS; + + monitor.beginTask(taskName, count); + + if (addedTUs != null) + for (Iterator i = addedTUs.iterator(); i.hasNext();) { + if (monitor.isCanceled()) + return Status.CANCEL_STATUS; + ITranslationUnit tu = (ITranslationUnit)i.next(); + monitor.subTask(String.valueOf(count--) + +" files remaining - " + + tu.getPath().toString()); + new PDOMFastAddTU(pdom, tu).schedule(); + } + + if (changedTUs != null) + for (Iterator i = changedTUs.iterator(); i.hasNext();) { + if (monitor.isCanceled()) + return Status.CANCEL_STATUS; + ITranslationUnit tu = (ITranslationUnit)i.next(); + monitor.subTask(String.valueOf(count--) + +" files remaining - " + + tu.getPath().toString()); + new PDOMFastChangeTU(pdom, tu).schedule(); + monitor.worked(1); + } + + if (removedTUs != null) + for (Iterator i = removedTUs.iterator(); i.hasNext();) { + if (monitor.isCanceled()) + return Status.CANCEL_STATUS; + ITranslationUnit tu = (ITranslationUnit)i.next(); + monitor.subTask(String.valueOf(count--) + +" files remaining - " + + tu.getPath().toString()); + new PDOMFastRemoveTU(pdom, tu).schedule(); + monitor.worked(1); + } + + String showTimings = Platform.getDebugOption(CCorePlugin.PLUGIN_ID + "/debug/pdomtimings"); //$NON-NLS-1$ + if (showTimings!= null) + if (showTimings.equalsIgnoreCase("true")) //$NON-NLS-1$ + System.out.println("Updator Time: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$ + + return Status.OK_STATUS; + } + + private void processDelta(ICElementDelta delta) { + // First make sure this project is PDOMable + ICElement element = delta.getElement(); + if (element instanceof ICProject && PDOM.getPDOM(((ICProject)element).getProject()) == null) + return; + + // process the children first + ICElementDelta[] children = delta.getAffectedChildren(); + for (int i = 0; i < children.length; ++i) + processDelta(children[i]); + + // what have we got + if (element.getElementType() == ICElement.C_PROJECT) { + switch (delta.getKind()) { + case ICElementDelta.ADDED: + processNewProject((ICProject)element); + break; + } + } else if (element.getElementType() == ICElement.C_UNIT) { + ITranslationUnit tu = (ITranslationUnit)element; + if (tu.isWorkingCopy()) + // Don't care about working copies either + return; + + switch (delta.getKind()) { + case ICElementDelta.ADDED: + if (addedTUs == null) + addedTUs = new LinkedList(); + addedTUs.add(element); + break; + case ICElementDelta.CHANGED: + if (changedTUs == null) + changedTUs = new LinkedList(); + changedTUs.add(element); + break; + case ICElementDelta.REMOVED: + if (removedTUs == null) + removedTUs = new LinkedList(); + removedTUs.add(element); + break; + } + } + } + + private void processNewProject(final ICProject project) { + try { + if (!PDOM.isEnabled(project.getProject())) + return; + project.getProject().accept(new IResourceProxyVisitor() { + public boolean visit(IResourceProxy proxy) throws CoreException { + if (proxy.getType() == IResource.FILE) { + String fileName = proxy.getName(); + IContentType contentType = Platform.getContentTypeManager().findContentTypeFor(fileName); + if (contentType == null) + return true; + String contentTypeId = contentType.getId(); + + if (CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(contentTypeId) + || CCorePlugin.CONTENT_TYPE_CSOURCE.equals(contentTypeId)) { + if (addedTUs == null) + addedTUs = new LinkedList(); + addedTUs.add(CoreModel.getDefault().create((IFile)proxy.requestResource())); + } + // TODO handle header files + return false; + } else { + return true; + } + } + }, 0); + } catch (CoreException e) { + CCorePlugin.log(e); + } + } + } + + public void elementChanged(ElementChangedEvent event) { + new ChangeHandler(event).schedule(); + } + + public void reindex() { + + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastRemoveTU.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastRemoveTU.java new file mode 100644 index 00000000000..5fdab656a31 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/fast/PDOMFastRemoveTU.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2006 QNX Software Systems and others. + * 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: + * QNX - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.pdom.indexer.fast; + +import org.eclipse.cdt.core.dom.IPDOM; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.pdom.PDOMDatabase; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +/** + * @author Doug Schaefer + * + */ +public class PDOMFastRemoveTU extends Job { + + private final IPDOM pdom; + private final ITranslationUnit tu; + + public PDOMFastRemoveTU(IPDOM pdom, ITranslationUnit tu) { + super("PDOM Fast Remove TU"); + this.pdom = pdom; + this.tu = tu; + } + + protected IStatus run(IProgressMonitor monitor) { + try { + PDOMDatabase mypdom = (PDOMDatabase)pdom; + mypdom.removeSymbols(tu); + // TODO delete the file itself from the database + // the removeSymbols only removes the names in the file + // TODO Auto-generated method stub + return Status.OK_STATUS; + } catch (CoreException e) { + return e.getStatus(); + } + } + +}