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

Yielding of index write lock. Bug 287907.

This commit is contained in:
Sergey Prigogin 2010-01-23 22:42:24 +00:00
parent c3c9c83823
commit 1bb19098d3
19 changed files with 587 additions and 79 deletions

View file

@ -8,6 +8,7 @@
* Contributors:
* Andrew Ferguson (Symbian) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.index.tests;
@ -123,6 +124,11 @@ public class EmptyIndexFragment implements IIndexFragment {
}
public void releaseReadLock() {}
public boolean hasWaitingReaders() {
return false;
}
public void resetCacheCounters() {}
public IIndexFragmentFileSet createFileSet() {

View file

@ -9,6 +9,7 @@
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
* Bryan Wilkinson (QNX)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.core.index;
@ -91,6 +92,12 @@ public interface IIndex {
*/
public void releaseReadLock();
/**
* @return <code>true</code> if there are threads waiting for read locks.
* @since 5.2
*/
public boolean hasWaitingReaders();
/**
* Returns a timestamp of when the index was last written to. This can
* be used to figure out whether information read from the index is

View file

@ -10,6 +10,7 @@
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Anton Leherbauer (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.index;
@ -355,6 +356,15 @@ public class CIndex implements IIndex {
return fReadLock;
}
public boolean hasWaitingReaders() {
for (int i= 0; i < fFragments.length; i++) {
if (fFragments[i].hasWaitingReaders()) {
return true;
}
}
return false;
}
public long getLastWriteAccess() {
long result= 0;
for (int i = 0; i < fFragments.length; i++) {

View file

@ -9,6 +9,7 @@
* Markus Schorn - initial API and implementation
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.index;
@ -85,6 +86,10 @@ final public class EmptyCIndex implements IIndex {
public void releaseReadLock() {
}
public boolean hasWaitingReaders() {
return false;
}
public long getLastWriteAccess() {
return 0;
}

View file

@ -9,6 +9,7 @@
* Markus Schorn - initial API and implementation
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.index;
@ -190,6 +191,11 @@ public interface IIndexFragment {
*/
void releaseReadLock();
/**
* @return <code>true</code> if there are threads waiting for read locks.
*/
public boolean hasWaitingReaders();
/**
* Returns the timestamp of the last modification to the index.
*/

View file

@ -8,6 +8,7 @@
* Contributors:
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.index;
@ -21,6 +22,7 @@ import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver;
import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock;
import org.eclipse.core.runtime.CoreException;
/**
@ -65,7 +67,28 @@ public interface IWritableIndex extends IIndex {
/**
* Creates a file object for the given location or returns an existing one.
*/
IIndexFragmentFile addFile(int linkageID, IIndexFileLocation fileLocation) throws CoreException;
IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location) throws CoreException;
/**
* Creates a uncommitted file object for the given location.
*/
IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location) throws CoreException;
/**
* Makes an uncommitted file that was created earlier by calling
* {@link #addUncommittedFile(int, IIndexFileLocation)} method visible in the index.
*
* @return The file that was updated.
* @throws CoreException
*/
IIndexFragmentFile commitUncommittedFile() throws CoreException;
/**
* Removes an uncommitted file if there is one. Used to recover from a failed index update.
*
* @throws CoreException
*/
void clearUncommittedFile() throws CoreException;
/**
* Adds content to the given file.
@ -73,7 +96,7 @@ public interface IWritableIndex extends IIndex {
void setFileContent(IIndexFragmentFile sourceFile,
int linkageID, IncludeInformation[] includes,
IASTPreprocessorStatement[] macros, IASTName[][] names,
ASTFilePathResolver resolver) throws CoreException;
ASTFilePathResolver resolver, YieldableIndexLock lock) throws CoreException, InterruptedException;
/**
* Clears the entire index.

View file

@ -8,7 +8,8 @@
* Contributors:
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
*******************************************************************************/
* Sergey Prigogin (Google)
******************************************************************************/
package org.eclipse.cdt.internal.core.index;
@ -19,6 +20,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation;
import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver;
import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock;
import org.eclipse.core.runtime.CoreException;
/**
@ -41,18 +43,43 @@ public interface IWritableIndexFragment extends IIndexFragment {
/**
* Creates a file object for the given location and linkage or returns an existing one.
* @param fileLocation an IIndexFileLocation representing the location of the file
* @return the existing IIndexFragmentFile for this location, or a newly created one
* @param fileLocation an IIndexFileLocation representing the location of the file.
* @return the existing IIndexFragmentFile for this location, or a newly created one.
* @throws CoreException
*/
IIndexFragmentFile addFile(int linkageID, IIndexFileLocation fileLocation) throws CoreException;
/**
* Adds an include to the given file.
* Creates a file object for the given location and linkage. The created file object is not added to
* the file index.
* @param fileLocation an IIndexFileLocation representing the location of the file.
* @return a newly created IIndexFragmentFile.
* @throws CoreException
*/
void addFileContent(IIndexFragmentFile sourceFile,
IncludeInformation[] includes,
IASTPreprocessorStatement[] macros, IASTName[][] names, ASTFilePathResolver resolver) throws CoreException;
IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation fileLocation) throws CoreException;
/**
* Makes an uncommitted file that was created earlier by calling
* {@link #addUncommittedFile(int, IIndexFileLocation)} method visible in the index.
*
* @return The file that was updated.
* @throws CoreException
*/
IIndexFragmentFile commitUncommittedFile() throws CoreException;
/**
* Removes an uncommitted file if there is one. Used to recover from a failed index update.
*
* @throws CoreException
*/
void clearUncommittedFile() throws CoreException;
/**
* Adds includes, macros and names to the given file.
*/
void addFileContent(IIndexFragmentFile sourceFile, IncludeInformation[] includes,
IASTPreprocessorStatement[] macros, IASTName[][] names, ASTFilePathResolver resolver,
YieldableIndexLock lock) throws CoreException, InterruptedException;
/**
* Acquires a write lock, while giving up a certain amount of read locks.

View file

@ -8,6 +8,7 @@
* Contributors:
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.index;
@ -19,6 +20,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver;
import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock;
import org.eclipse.core.runtime.CoreException;
public class WritableCIndex extends CIndex implements IWritableIndex {
@ -50,17 +52,29 @@ public class WritableCIndex extends CIndex implements IWritableIndex {
return fWritableFragment.getFiles(location);
}
public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation fileLocation) throws CoreException {
return fWritableFragment.addFile(linkageID, fileLocation);
public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location) throws CoreException {
return fWritableFragment.addFile(linkageID, location);
}
public IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location) throws CoreException {
return fWritableFragment.addUncommittedFile(linkageID, location);
}
public IIndexFragmentFile commitUncommittedFile() throws CoreException {
return fWritableFragment.commitUncommittedFile();
}
public void clearUncommittedFile() throws CoreException {
fWritableFragment.clearUncommittedFile();
}
private boolean isWritableFragment(IIndexFragment frag) {
return frag == fWritableFragment;
}
public void setFileContent(IIndexFragmentFile file, int linkageID,
IncludeInformation[] includes,
IASTPreprocessorStatement[] macros, IASTName[][] names, ASTFilePathResolver resolver) throws CoreException {
public void setFileContent(IIndexFragmentFile file, int linkageID, IncludeInformation[] includes,
IASTPreprocessorStatement[] macros, IASTName[][] names, ASTFilePathResolver resolver,
YieldableIndexLock lock) throws CoreException, InterruptedException {
IIndexFragment indexFragment = file.getIndexFragment();
if (!isWritableFragment(indexFragment)) {
assert false : "Attempt to update file of read-only fragment"; //$NON-NLS-1$
@ -70,7 +84,7 @@ public class WritableCIndex extends CIndex implements IWritableIndex {
ii.fTargetFile= addFile(linkageID, ii.fLocation);
}
}
((IWritableIndexFragment) indexFragment).addFileContent(file, includes, macros, names, resolver);
((IWritableIndexFragment) indexFragment).addFileContent(file, includes, macros, names, resolver, lock);
}
}

View file

@ -11,6 +11,7 @@
* IBM Corporation
* Andrew Ferguson (Symbian)
* Anton Leherbauer (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
@ -96,6 +97,7 @@ import org.eclipse.core.runtime.Status;
public class PDOM extends PlatformObject implements IPDOM {
private static final int BLOCKED_WRITE_LOCK_OUTPUT_INTERVAL = 30000;
private static final int LONG_WRITE_LOCK_REPORT_THRESHOLD = 1000;
private static final int LONG_READ_LOCK_WAIT_REPORT_THRESHOLD = 1000;
static boolean sDEBUG_LOCKS= false; // initialized in the PDOMManager, because IBM needs PDOM independent of runtime plugin.
/**
@ -341,7 +343,7 @@ public class PDOM extends PlatformObject implements IPDOM {
}
}
private PDOMLinkage createLinkage(int linkageID) throws CoreException {
protected PDOMLinkage createLinkage(int linkageID) throws CoreException {
PDOMLinkage pdomLinkage= fLinkageIDCache.get(linkageID);
if (pdomLinkage == null) {
final String linkageName= Linkage.getLinkageName(linkageID);
@ -766,6 +768,7 @@ public class PDOM extends PlatformObject implements IPDOM {
private long timeWriteLockAcquired;
public void acquireReadLock() throws InterruptedException {
long t = sDEBUG_LOCKS ? System.nanoTime() : 0;
synchronized (mutex) {
++waitingReaders;
try {
@ -778,12 +781,15 @@ public class PDOM extends PlatformObject implements IPDOM {
db.setLocked(true);
if (sDEBUG_LOCKS) {
t = (System.nanoTime() - t) / 1000000;
if (t >= LONG_READ_LOCK_WAIT_REPORT_THRESHOLD) {
System.out.println("Acquired index read lock after " + t + " ms wait."); //$NON-NLS-1$//$NON-NLS-2$
}
incReadLock(fLockDebugging);
}
}
}
public void releaseReadLock() {
boolean clearCache= false;
synchronized (mutex) {
@ -884,6 +890,12 @@ public class PDOM extends PlatformObject implements IPDOM {
fireChange(event);
}
public boolean hasWaitingReaders() {
synchronized (mutex) {
return waitingReaders > 0;
}
}
public long getLastWriteAccess() {
return lastWriteAccess;
}
@ -957,45 +969,67 @@ public class PDOM extends PlatformObject implements IPDOM {
PDOMName name;
if ((options & FIND_DECLARATIONS) != 0) {
for (name= pdomBinding.getFirstDeclaration(); name != null; name= name.getNextInBinding()) {
if (isCommitted(name)) {
names.add(name);
}
}
}
if ((options & FIND_DEFINITIONS) != 0) {
for (name = pdomBinding.getFirstDefinition(); name != null; name= name.getNextInBinding()) {
if (isCommitted(name)) {
names.add(name);
}
}
}
if ((options & FIND_REFERENCES) != 0) {
for (name = pdomBinding.getFirstReference(); name != null; name= name.getNextInBinding()) {
if (isCommitted(name)) {
names.add(name);
}
}
}
}
private void findNamesForMyBinding(PDOMMacroContainer container, int options, ArrayList<IIndexFragmentName> names)
throws CoreException {
if ((options & FIND_DEFINITIONS) != 0) {
for (PDOMMacro macro= container.getFirstDefinition(); macro != null; macro= macro.getNextInContainer()) {
final IIndexFragmentName name = macro.getDefinition();
if (name != null) {
if (name != null && isCommitted(macro)) {
names.add(name);
}
}
}
if ((options & FIND_REFERENCES) != 0) {
for (PDOMMacroReferenceName name = container.getFirstReference(); name != null; name= name.getNextInContainer()) {
if (isCommitted(name)) {
names.add(name);
}
}
}
}
protected boolean isCommitted(PDOMName name) throws CoreException {
return true;
}
protected boolean isCommitted(PDOMMacro name) throws CoreException {
return true;
}
protected boolean isCommitted(PDOMMacroReferenceName name) throws CoreException {
return true;
}
public IIndexFragmentInclude[] findIncludedBy(IIndexFragmentFile file) throws CoreException {
PDOMFile pdomFile= adaptFile(file);
if (pdomFile != null) {
List<PDOMInclude> result = new ArrayList<PDOMInclude>();
for (PDOMInclude i= pdomFile.getFirstIncludedBy(); i != null; i= i.getNextInIncludedBy()) {
if (i.getIncludedBy().getTimestamp() > 0) {
result.add(i);
}
}
return result.toArray(new PDOMInclude[result.size()]);
}
return new PDOMInclude[0];
@ -1198,6 +1232,10 @@ public class PDOM extends PlatformObject implements IPDOM {
return new StringBuilder(name.length + 2).append((char) (record >> 16)).append((char) record).append(name).toString();
}
public boolean hasLastingDefinition(PDOMBinding binding) throws CoreException {
return binding.hasDefinition();
}
private PDOMBinding[] getCrossLanguageBindings(IBinding binding) throws CoreException {
switch(binding.getLinkage().getLinkageID()) {
case ILinkage.C_LINKAGE_ID:

View file

@ -7,6 +7,7 @@
*
* Contributors:
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
@ -187,6 +188,10 @@ public class PDOMProxy implements IPDOM {
}
}
public boolean hasWaitingReaders() {
return fDelegate != null && fDelegate.hasWaitingReaders();
}
public synchronized void resetCacheCounters() {
if (fDelegate != null)
fDelegate.resetCacheCounters();

View file

@ -8,6 +8,7 @@
* Contributors:
* Markus Schorn - initial API and implementation
* IBM Corporation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
@ -46,6 +47,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexInclude;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
@ -68,6 +70,9 @@ import org.eclipse.osgi.util.NLS;
* @since 4.0
*/
abstract public class PDOMWriter {
// TODO(sprigogin): Remove SEMI_TRANSACTIONAL_UPDATES and ALLOW_LOCK_YIELDING constants and simplify the code.
public static boolean SEMI_TRANSACTIONAL_UPDATES = true;
public static boolean ALLOW_LOCK_YIELDING = true;
public static int SKIP_ALL_REFERENCES= -1;
public static int SKIP_TYPE_REFERENCES= 1;
public static int SKIP_MACRO_REFERENCES= 2;
@ -200,11 +205,11 @@ abstract public class PDOMWriter {
if (fShowActivity) {
trace("Indexer: adding " + ifl.getURI()); //$NON-NLS-1$
}
index.acquireWriteLock(readlockCount);
long start= System.currentTimeMillis();
Throwable th= null;
YieldableIndexLock lock = new YieldableIndexLock(index, readlockCount, flushIndex);
lock.acquire();
try {
storeFileInIndex(index, ifl, symbolMap, linkageID, configHash, contextIncludes);
storeFileInIndex(index, ifl, symbolMap, linkageID, configHash, contextIncludes, lock);
} catch (RuntimeException e) {
th= e;
} catch (PDOMNotImplementedError e) {
@ -214,7 +219,7 @@ abstract public class PDOMWriter {
} catch (AssertionError e) {
th= e;
} finally {
index.releaseWriteLock(readlockCount, flushIndex);
lock.release();
}
if (th != null) {
stati.add(createStatus(NLS.bind(Messages.PDOMWriter_errorWhileParsing,
@ -223,7 +228,7 @@ abstract public class PDOMWriter {
if (i < ifls.length - 1) {
updateFileCount(0, 0, 1); // update header count
}
fStatistics.fAddToIndexTime += System.currentTimeMillis() - start;
fStatistics.fAddToIndexTime += lock.getCumulativeLockTime();
}
}
}
@ -448,16 +453,38 @@ abstract public class PDOMWriter {
private IIndexFragmentFile storeFileInIndex(IWritableIndex index, IIndexFileLocation location,
Map<IIndexFileLocation, Symbols> symbolMap, int linkageID, int configHash,
Set<IASTPreprocessorIncludeStatement> contextIncludes) throws CoreException {
Set<IASTPreprocessorIncludeStatement> contextIncludes, YieldableIndexLock lock)
throws CoreException, InterruptedException {
Set<IIndexFileLocation> clearedContexts= Collections.emptySet();
IIndexFragmentFile file= index.getWritableFile(linkageID, location);
IIndexFragmentFile file;
long timestamp = fResolver.getLastModified(location);
if (SEMI_TRANSACTIONAL_UPDATES) {
// In fine grained locking mode we create a temporary PDOMFile with zero timestamp,
// add names to it, then replace contents of the old file from the temporary one, then
// delete the temporary file. The write lock on the index is periodically yielded while
// adding names to the temporary file, if the process takes long time.
IIndexFragmentFile oldFile = index.getWritableFile(linkageID, location);
if (oldFile != null) {
IIndexInclude[] includedBy = index.findIncludedBy(oldFile);
if (includedBy.length > 0) {
clearedContexts= new HashSet<IIndexFileLocation>();
for (IIndexInclude include : includedBy) {
clearedContexts.add(include.getIncludedByLocation());
}
}
}
file= index.addUncommittedFile(linkageID, location);
} else {
file= index.getWritableFile(linkageID, location);
if (file != null) {
clearedContexts= new HashSet<IIndexFileLocation>();
index.clearFile(file, clearedContexts);
} else {
file= index.addFile(linkageID, location);
}
file.setTimestamp(fResolver.getLastModified(location));
file.setTimestamp(timestamp);
}
try {
file.setScannerConfigurationHashcode(configHash);
Symbols lists= symbolMap.get(location);
if (lists != null) {
@ -481,7 +508,15 @@ abstract public class PDOMWriter {
(contextIncludes.contains(include) || clearedContexts.contains(info.fLocation));
}
}
index.setFileContent(file, linkageID, includeInfos, macros, names, fResolver);
index.setFileContent(file, linkageID, includeInfos, macros, names, fResolver,
SEMI_TRANSACTIONAL_UPDATES && ALLOW_LOCK_YIELDING ? lock : null);
}
if (SEMI_TRANSACTIONAL_UPDATES) {
file.setTimestamp(timestamp);
file = index.commitUncommittedFile();
}
} finally {
index.clearUncommittedFile();
}
return file;
}

View file

@ -8,6 +8,7 @@
* Contributors:
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
@ -25,17 +26,26 @@ import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IIndexFragmentFile;
import org.eclipse.cdt.internal.core.index.IWritableIndexFragment;
import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation;
import org.eclipse.cdt.internal.core.pdom.db.BTree;
import org.eclipse.cdt.internal.core.pdom.db.ChunkCache;
import org.eclipse.cdt.internal.core.pdom.db.DBProperties;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMFile;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacro;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacroReferenceName;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.core.runtime.CoreException;
public class WritablePDOM extends PDOM implements IWritableIndexFragment {
private boolean fClearedBecauseOfVersionMismatch= false;
private boolean fCreatedFromScratch= false;
private ASTFilePathResolver fPathResolver;
private PDOMFile fileBeingUpdated;
private PDOMFile uncommittedFile;
private IIndexFileLocation uncommittedLocation;
public WritablePDOM(File dbPath, IIndexLocationConverter locationConverter,
Map<String, IPDOMLinkageFactory> linkageFactoryMappings) throws CoreException {
@ -53,11 +63,57 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment {
@Override
public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location) throws CoreException {
if (uncommittedLocation != null && uncommittedLocation.equals(location)) {
return uncommittedFile;
}
return super.addFile(linkageID, location);
}
public IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location) throws CoreException {
uncommittedLocation = location;
fileBeingUpdated = getFile(linkageID, uncommittedLocation);
PDOMLinkage linkage= createLinkage(linkageID);
uncommittedFile = new PDOMFile(linkage, location, linkageID);
return uncommittedFile;
}
public IIndexFragmentFile commitUncommittedFile() throws CoreException {
if (uncommittedFile == null)
return null;
IIndexFragmentFile file;
if (fileBeingUpdated == null) {
// New file.
BTree fileIndex = getFileIndex();
fileIndex.insert(uncommittedFile.getRecord());
file = uncommittedFile;
} else {
// Existing file.
fileBeingUpdated.replaceContentsFrom(uncommittedFile);
file = fileBeingUpdated;
fileBeingUpdated = null;
}
fEvent.fFilesWritten.add(uncommittedLocation);
uncommittedFile = null;
uncommittedLocation = null;
return file;
}
public void clearUncommittedFile() throws CoreException {
if (uncommittedFile != null) {
try {
uncommittedFile.clear(null);
uncommittedFile.delete();
} finally {
uncommittedFile = null;
uncommittedLocation = null;
fileBeingUpdated = null;
}
}
}
public void addFileContent(IIndexFragmentFile sourceFile, IncludeInformation[] includes,
IASTPreprocessorStatement[] macros, IASTName[][] names, ASTFilePathResolver pathResolver) throws CoreException {
IASTPreprocessorStatement[] macros, IASTName[][] names, ASTFilePathResolver pathResolver,
YieldableIndexLock lock) throws CoreException, InterruptedException {
assert sourceFile.getIndexFragment() == this;
PDOMFile pdomFile = (PDOMFile) sourceFile;
@ -66,15 +122,17 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment {
final ASTFilePathResolver origResolver= fPathResolver;
fPathResolver= pathResolver;
try {
pdomFile.addNames(names);
pdomFile.addNames(names, lock);
} finally {
fPathResolver= origResolver;
}
final IIndexFileLocation location = pdomFile.getLocation();
if (location != null) {
fEvent.fClearedFiles.remove(location);
fEvent.fFilesWritten.add(location);
}
}
public void clearFile(IIndexFragmentFile file, Collection<IIndexFileLocation> contextsRemoved)
throws CoreException {
@ -171,11 +229,47 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment {
public PDOMFile getFileForASTPath(int linkageID, String astPath) throws CoreException {
if (fPathResolver != null && astPath != null) {
return getFile(linkageID, fPathResolver.resolveASTPath(astPath));
IIndexFileLocation location = fPathResolver.resolveASTPath(astPath);
if (location.equals(uncommittedLocation))
return fileBeingUpdated != null ? fileBeingUpdated : uncommittedFile;
return getFile(linkageID, location);
}
return null;
}
@Override
public boolean hasLastingDefinition(PDOMBinding binding) throws CoreException {
if (fileBeingUpdated == null) {
return binding.hasDefinition();
}
// Definitions in fileBeingUpdated will soon go away, so look for a definition elsewhere.
for (PDOMName name = binding.getFirstDefinition(); name != null; name = name.getNextInBinding()) {
if (!fileBeingUpdated.getPDOM().equals(name.getPDOM()) ||
fileBeingUpdated.getRecord() != name.getFileRecord()) {
return true;
}
}
return false;
}
@Override
protected boolean isCommitted(PDOMName name) throws CoreException {
return uncommittedFile == null || !uncommittedFile.getPDOM().equals(name.getPDOM()) ||
uncommittedFile.getRecord() != name.getFileRecord();
}
@Override
protected boolean isCommitted(PDOMMacro name) throws CoreException {
return uncommittedFile == null || !uncommittedFile.getPDOM().equals(name.getPDOM()) ||
uncommittedFile.getRecord() != name.getFileRecord();
}
@Override
protected boolean isCommitted(PDOMMacroReferenceName name) throws CoreException {
return uncommittedFile == null || !uncommittedFile.getPDOM().equals(name.getPDOM()) ||
uncommittedFile.getRecord() != name.getFileRecord();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.index.IWritableIndexFragment#getDatabaseSizeBytes()
*/

View file

@ -0,0 +1,74 @@
/*******************************************************************************
* Copyright (c) 2010 Google, Inc 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:
* Sergey Prigogin (Google) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
import org.eclipse.cdt.internal.core.index.IWritableIndex;
/**
* Write lock on the index that can be yielded temporarily to unblock threads that need
* read access to the index.
* @since 5.2
*/
public class YieldableIndexLock {
private final IWritableIndex index;
private final int readlockCount;
private final boolean flushIndex;
private long lastLockTime;
private long cumulativeLockTime;
public YieldableIndexLock(IWritableIndex index, int readlockCount, boolean flushIndex) {
this.index = index;
this.readlockCount = readlockCount;
this.flushIndex = flushIndex;
}
/**
* Acquires the lock.
*
* @throws InterruptedException
*/
public void acquire() throws InterruptedException {
index.acquireWriteLock(readlockCount);
lastLockTime = System.currentTimeMillis();
}
/**
* Releases the lock.
*/
public void release() {
if (lastLockTime != 0) {
index.releaseWriteLock(readlockCount, flushIndex);
cumulativeLockTime += System.currentTimeMillis() - lastLockTime;
lastLockTime = 0;
}
}
/**
* Yields the lock temporarily if it was held for YIELD_INTERVAL or more, and somebody is waiting
* for a read lock.
* @throws InterruptedException
*/
public void yield() throws InterruptedException {
if (index.hasWaitingReaders()) {
index.releaseWriteLock(readlockCount, false);
cumulativeLockTime += System.currentTimeMillis() - lastLockTime;
lastLockTime = 0;
acquire();
}
}
/**
* @return Total time the lock was held in milliseconds.
*/
public long getCumulativeLockTime() {
return cumulativeLockTime;
}
}

View file

@ -9,6 +9,7 @@
* QNX - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;
@ -30,6 +31,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.ast.IParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexInclude;
import org.eclipse.cdt.core.index.IIndexLocationConverter;
@ -42,6 +44,7 @@ import org.eclipse.cdt.internal.core.index.IWritableIndexFragment;
import org.eclipse.cdt.internal.core.index.IndexFileLocation;
import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.YieldableIndexLock;
import org.eclipse.cdt.internal.core.pdom.db.BTree;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator;
@ -115,6 +118,10 @@ public class PDOMFile implements IIndexFragmentFile {
return record;
}
public PDOM getPDOM() {
return fLinkage.getPDOM();
}
@Override
public boolean equals(Object obj) {
if (obj == this)
@ -128,13 +135,116 @@ public class PDOMFile implements IIndexFragmentFile {
@Override
public final int hashCode() {
return System.identityHashCode(fLinkage.getPDOM()) + (int)(41*record);
return System.identityHashCode(fLinkage.getPDOM()) + (int) (41 * record);
}
/**
* Directly changes this record's internal location string. The format
* of this string is unspecified in general and is determined by the
* associated IIndexLocationConverter
* Transfers names, macros and includes from another file to this one and deletes the other file.
* @param sourceFile the file to transfer the local bindings from.
* @throws CoreException
*/
public void replaceContentsFrom(PDOMFile sourceFile) throws CoreException {
ICPPUsingDirective[] directives= getUsingDirectives();
for (ICPPUsingDirective ud : directives) {
if (ud instanceof IPDOMNode) {
((IPDOMNode) ud).delete(null);
}
}
setFirstUsingDirectiveRec(sourceFile.getLastUsingDirectiveRec());
// Replace the includes
PDOMInclude include = getFirstInclude();
while (include != null) {
PDOMInclude nextInclude = include.getNextInIncludes();
IIndexFile includedBy = include.getIncludedBy();
if (this.equals(includedBy)) {
include.delete();
}
include = nextInclude;
}
include = sourceFile.getFirstInclude();
setFirstInclude(include);
while (include != null) {
IIndexFile includedBy = include.getIncludedBy();
if (sourceFile.equals(includedBy)) {
include.setIncludedBy(this);
if (sourceFile.equals(include.getIncludes())) {
include.setIncludes(this);
}
}
include = include.getNextInIncludes();
}
// Replace all the macros in this file.
PDOMLinkage linkage= getLinkage();
PDOMMacro macro = getFirstMacro();
while (macro != null) {
PDOMMacro nextMacro = macro.getNextMacro();
macro.delete(linkage);
macro = nextMacro;
}
macro = sourceFile.getFirstMacro();
setFirstMacro(macro);
for (; macro != null; macro = macro.getNextMacro()) {
macro.setFile(this);
}
// Replace all macro references
ArrayList<PDOMMacroReferenceName> mrefs= new ArrayList<PDOMMacroReferenceName>();
PDOMMacroReferenceName mref = getFirstMacroReference();
while (mref != null) {
mrefs.add(mref);
mref= mref.getNextInFile();
}
for (PDOMMacroReferenceName m : mrefs) {
m.delete();
}
mref = sourceFile.getFirstMacroReference();
setFirstMacroReference(mref);
for (; mref != null; mref = mref.getNextInFile()) {
mref.setFile(this);
}
// Replace all the names in this file
ArrayList<PDOMName> names= new ArrayList<PDOMName>();
PDOMName name = getFirstName();
for (; name != null; name= name.getNextInFile()) {
names.add(name);
linkage.onDeleteName(name);
}
for (Iterator<PDOMName> iterator = names.iterator(); iterator.hasNext();) {
name = iterator.next();
name.delete();
}
name = sourceFile.getFirstName();
setFirstName(name);
for (; name != null; name= name.getNextInFile()) {
name.setFile(this);
}
setTimestamp(sourceFile.getTimestamp());
setScannerConfigurationHashcode(sourceFile.getScannerConfigurationHashcode());
sourceFile.delete();
}
/**
* This method should not be called on PDOMFile objects that are referenced by the file index.
* @param location a new location
* @throws CoreException
*/
public void setLocation(IIndexFileLocation location) throws CoreException {
String locationString = fLinkage.getPDOM().getLocationConverter().toInternalFormat(location);
if (locationString == null)
throw new CoreException(CCorePlugin.createStatus(Messages.getString("PDOMFile.toInternalProblem") + //$NON-NLS-1$
location.getURI()));
setInternalLocation(locationString);
}
/**
* Directly changes this record's internal location string. The format of this string is unspecified
* in general and is determined by the associated IIndexLocationConverter.
* This method should not be called on PDOMFile objects that are referenced by the file index.
* @param internalLocation
* @throws CoreException
*/
@ -256,7 +366,7 @@ public class PDOMFile implements IIndexFragmentFile {
return fLinkage;
}
public void addNames(IASTName[][] names) throws CoreException {
public void addNames(IASTName[][] names, YieldableIndexLock lock) throws CoreException, InterruptedException {
assert getFirstName() == null;
assert getFirstMacroReference() == null;
final PDOMLinkage linkage= getLinkage();
@ -265,6 +375,9 @@ public class PDOMFile implements IIndexFragmentFile {
PDOMMacroReferenceName lastMacroName= null;
for (IASTName[] name : names) {
if (name[0] != null) {
if (lock != null) {
lock.yield();
}
PDOMName caller= nameCache.get(name[1]);
IIndexFragmentName fname= createPDOMName(linkage, name[0], caller);
if (fname instanceof PDOMName) {
@ -340,7 +453,7 @@ public class PDOMFile implements IIndexFragmentFile {
include.delete();
include = nextInclude;
}
setFirstInclude(include);
setFirstInclude(null);
// Delete all the macros in this file
PDOMLinkage linkage= getLinkage();
@ -381,6 +494,15 @@ public class PDOMFile implements IIndexFragmentFile {
setTimestamp(-1);
}
/**
* Deletes this file from PDOM. Only uncommitted files can be safely deleted.
*
* @throws CoreException
*/
public void delete() throws CoreException {
fLinkage.getDB().free(record);
}
public void addIncludesTo(IncludeInformation[] includeInfos) throws CoreException {
assert getFirstInclude() == null;

View file

@ -141,6 +141,11 @@ public class PDOMInclude implements IIndexFragmentInclude {
return rec != 0 ? new PDOMFile(linkage, rec) : null;
}
void setIncludes(PDOMFile includedFile) throws CoreException {
long rec = includedFile != null ? includedFile.getRecord() : 0;
linkage.getDB().putRecPtr(record + INCLUDED_FILE, rec);
}
/**
* Checks if the name is the same as the end part of the path of the included file.
*/
@ -166,7 +171,7 @@ public class PDOMInclude implements IIndexFragmentInclude {
return rec != 0 ? new PDOMFile(linkage, rec) : null;
}
private void setIncludedBy(PDOMFile includedBy) throws CoreException {
void setIncludedBy(PDOMFile includedBy) throws CoreException {
long rec = includedBy != null ? includedBy.getRecord() : 0;
linkage.getDB().putRecPtr(record + INCLUDED_BY, rec);
}

View file

@ -9,6 +9,7 @@
* QNX - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;
@ -269,6 +270,14 @@ public class PDOMMacro implements IIndexMacro, IPDOMBinding, IASTFileLocation {
return filerec != 0 ? new PDOMFile(fLinkage, filerec) : null;
}
public long getFileRecord() throws CoreException {
return fLinkage.getDB().getRecPtr(fRecord + FILE);
}
void setFile(PDOMFile file) throws CoreException {
fLinkage.getDB().putRecPtr(fRecord + FILE, file != null ? file.getRecord() : 0);
}
public int getEndingLineNumber() {
return 0;
}

View file

@ -8,6 +8,7 @@
* Contributors:
* QNX - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;
@ -21,6 +22,7 @@ import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding;
import org.eclipse.cdt.internal.core.index.IIndexFragmentName;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
@ -67,6 +69,10 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil
return record;
}
public PDOM getPDOM() {
return linkage.getPDOM();
}
private long getRecField(int offset) throws CoreException {
return linkage.getDB().getRecPtr(record + offset);
}
@ -111,6 +117,14 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil
return filerec != 0 ? new PDOMFile(linkage, filerec) : null;
}
public long getFileRecord() throws CoreException {
return linkage.getDB().getRecPtr(record + FILE_REC_OFFSET);
}
void setFile(PDOMFile file) throws CoreException {
linkage.getDB().putRecPtr(record + FILE_REC_OFFSET, file != null ? file.getRecord() : 0);
}
PDOMMacroReferenceName getNextInFile() throws CoreException {
return getNameField(FILE_NEXT_OFFSET);
}

View file

@ -8,6 +8,7 @@
* Contributors:
* QNX - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;
@ -22,6 +23,7 @@ import org.eclipse.cdt.core.index.IndexLocationFactory;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IIndexFragmentName;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
@ -121,6 +123,10 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
linkage.getDB().putRecPtr(record + offset, fieldrec);
}
public PDOM getPDOM() {
return linkage.getPDOM();
}
public PDOMBinding getBinding() throws CoreException {
long bindingrec = getRecField(BINDING_REC_OFFSET);
return linkage.getBinding(bindingrec);
@ -162,6 +168,14 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
return filerec != 0 ? new PDOMFile(linkage, filerec) : null;
}
public long getFileRecord() throws CoreException {
return linkage.getDB().getRecPtr(record + FILE_REC_OFFSET);
}
void setFile(PDOMFile file) throws CoreException {
linkage.getDB().putRecPtr(record + FILE_REC_OFFSET, file != null ? file.getRecord() : 0);
}
public IIndexName getEnclosingDefinition() throws CoreException {
long namerec = getEnclosingDefinitionRecord();
return namerec != 0 ? new PDOMName(linkage, namerec) : null;

View file

@ -299,7 +299,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
if (fromName.isDefinition()) {
return true;
}
return !pdomBinding.hasDefinition();
return !getPDOM().hasLastingDefinition(pdomBinding);
}
return false;
}
@ -444,8 +444,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
if (!(method instanceof IProblemBinding)) {
PDOMBinding pdomBinding= adaptBinding(method);
if (pdomBinding == null) {
createBinding(type, method, fileLocalRec);
} else if (!pdomBinding.hasDefinition()) {
pdomBinding = createBinding(type, method, fileLocalRec);
} else if (!getPDOM().hasLastingDefinition(pdomBinding)) {
pdomBinding.update(this, method);
}
}