1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

A smarter way to deal with readers/writers of PDOM database, i.e. using scheduling rules and priorities.

This commit is contained in:
Doug Schaefer 2006-03-28 16:22:54 +00:00
parent 595dadd8b4
commit 7d1e89a9fa
6 changed files with 428 additions and 43 deletions

View file

@ -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();
}

View file

@ -38,6 +38,7 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
/** /**
* The PDOM Database. * The PDOM Database.
@ -46,6 +47,8 @@ import org.eclipse.core.runtime.QualifiedName;
*/ */
public class PDOMDatabase implements IPDOM { public class PDOMDatabase implements IPDOM {
private final IProject project;
private final IPath dbPath; private final IPath dbPath;
private Database db; private Database db;
@ -60,6 +63,7 @@ public class PDOMDatabase implements IPDOM {
= new QualifiedName(CCorePlugin.PLUGIN_ID, "dbName"); //$NON-NLS-1$ = new QualifiedName(CCorePlugin.PLUGIN_ID, "dbName"); //$NON-NLS-1$
public PDOMDatabase(IProject project, PDOMManager manager) throws CoreException { public PDOMDatabase(IProject project, PDOMManager manager) throws CoreException {
this.project = project;
String dbName = project.getPersistentProperty(dbNameProperty); String dbName = project.getPersistentProperty(dbNameProperty);
if (dbName == null) { if (dbName == null) {
dbName = project.getName() + "_" dbName = project.getName() + "_"
@ -71,6 +75,10 @@ public class PDOMDatabase implements IPDOM {
db = new Database(dbPath.toOSString(), VERSION); db = new Database(dbPath.toOSString(), VERSION);
} }
public IProject getProject() {
return project;
}
public static interface IListener { public static interface IListener {
public void handleChange(PDOMDatabase pdom); public void handleChange(PDOMDatabase pdom);
} }
@ -241,54 +249,43 @@ public class PDOMDatabase implements IPDOM {
return PDOMLinkage.getLinkage(this, record).getBinding(record); return PDOMLinkage.getLinkage(this, record).getBinding(record);
} }
// Read-write lock. Since we want to allow reads during a long // Read-write lock rules. Readers don't conflict with other readers,
// running index, readers take precidence. // Writers conflict with readers, and everyone conflicts with writers.
private Object lockMutex = new Object(); private class ReaderLockRule implements ISchedulingRule {
private int lockCount; public boolean isConflicting(ISchedulingRule rule) {
private int waitingReaders; if (rule == this)
private int waitingWriters; return false;
else if (rule == getWriterLockRule())
public void getReadLock(boolean waitForWrites) throws InterruptedException { return true;
synchronized (lockMutex) { else
if (!waitForWrites) return false;
++waitingReaders; }
while (lockCount < 0 || (waitForWrites && waitingWriters > 0)) public boolean contains(ISchedulingRule rule) {
// wait for the writers to finish return rule == this;
lockMutex.wait(); }
// free to go }
++lockCount;
if (!waitForWrites) private class WriterLockRule implements ISchedulingRule {
--waitingReaders; 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 { private ReaderLockRule readerLockRule = new ReaderLockRule();
synchronized (lockMutex) { private WriterLockRule writerLockRule = new WriterLockRule();
++waitingWriters;
while (lockCount != 0 || waitingReaders > 0) public ISchedulingRule getReaderLockRule() {
// wait for everyone to finish return readerLockRule;
// readers get precidence
lockMutex.wait();
// free to go
--lockCount;
--waitingWriters;
}
} }
public void releaseReadLock() { public ISchedulingRule getWriterLockRule() {
synchronized (lockMutex) { return writerLockRule;
if (lockCount > 0)
--lockCount;
lockMutex.notifyAll();
}
} }
public void releaseWriteLock() {
synchronized (lockMutex) {
if (lockCount < 0)
++lockCount;
lockMutex.notifyAll();
}
}
} }

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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() {
}
}

View file

@ -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();
}
}
}