Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 262178
Collapse All | Expand All

(-)model/org/eclipse/dltk/internal/core/BufferManager.java (-7 / +50 lines)
Lines 15-20 Link Here
15
import org.eclipse.core.resources.IFile;
15
import org.eclipse.core.resources.IFile;
16
import org.eclipse.core.resources.IResource;
16
import org.eclipse.core.resources.IResource;
17
import org.eclipse.dltk.core.IBuffer;
17
import org.eclipse.dltk.core.IBuffer;
18
import org.eclipse.dltk.core.IBufferFactory;
18
import org.eclipse.dltk.core.IModelElement;
19
import org.eclipse.dltk.core.IModelElement;
19
import org.eclipse.dltk.core.IOpenable;
20
import org.eclipse.dltk.core.IOpenable;
20
21
Lines 31-37 Link Here
31
	 * LRU cache of buffers. The key and value for an entry in the table is the
32
	 * LRU cache of buffers. The key and value for an entry in the table is the
32
	 * identical buffer.
33
	 * identical buffer.
33
	 */
34
	 */
34
	protected OverflowingLRUCache openBuffers = new BufferCache(60);
35
	private BufferCache openBuffers = new BufferCache(60);
36
37
	/**
38
	 * @deprecated
39
	 */
40
	protected IBufferFactory defaultBufferFactory = new IBufferFactory() {
41
		/**
42
		 * @deprecated
43
		 */
44
		public IBuffer createBuffer(IOpenable owner) {
45
			return BufferManager.createBuffer(owner);
46
		}
47
	};
35
48
36
	/**
49
	/**
37
	 * Adds a buffer to the table of open buffers.
50
	 * Adds a buffer to the table of open buffers.
Lines 42-48 Link Here
42
					.toStringWithAncestors();
55
					.toStringWithAncestors();
43
			System.out.println("Adding buffer for " + owner); //$NON-NLS-1$
56
			System.out.println("Adding buffer for " + owner); //$NON-NLS-1$
44
		}
57
		}
58
		synchronized (this.openBuffers) {
45
		this.openBuffers.put(buffer.getOwner(), buffer);
59
		this.openBuffers.put(buffer.getOwner(), buffer);
60
	}
61
		// close buffers that were removed from the cache if space was needed
62
		this.openBuffers.closeBuffers();
46
		if (VERBOSE) {
63
		if (VERBOSE) {
47
			System.out
64
			System.out
48
					.println("-> Buffer cache filling ratio = " + NumberFormat.getInstance().format(this.openBuffers.fillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
65
					.println("-> Buffer cache filling ratio = " + NumberFormat.getInstance().format(this.openBuffers.fillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
Lines 50-68 Link Here
50
	}
67
	}
51
68
52
	public static IBuffer createBuffer(IOpenable owner) {
69
	public static IBuffer createBuffer(IOpenable owner) {
53
		IModelElement element = owner;
70
		IModelElement element = (IModelElement) owner;
54
		IResource resource = element.getResource();
71
		IResource resource = element.getResource();
55
		return new Buffer(resource instanceof IFile ? (IFile) resource : null,
72
		return new Buffer(resource instanceof IFile ? (IFile) resource : null,
56
				owner, element.isReadOnly());
73
				owner, element.isReadOnly());
57
	}
74
	}
58
75
76
	public static IBuffer createNullBuffer(IOpenable owner) {
77
		IModelElement element = (IModelElement) owner;
78
		IResource resource = element.getResource();
79
		return new NullBuffer(resource instanceof IFile ? (IFile) resource
80
				: null, owner, element.isReadOnly());
81
	}
82
59
	/**
83
	/**
60
	 * Returns the open buffer associated with the given owner, or
84
	 * Returns the open buffer associated with the given owner, or
61
	 * <code>null</code> if the owner does not have an open buffer associated
85
	 * <code>null</code> if the owner does not have an open buffer associated
62
	 * with it.
86
	 * with it.
63
	 */
87
	 */
64
	public IBuffer getBuffer(IOpenable owner) {
88
	public IBuffer getBuffer(IOpenable owner) {
65
		return (IBuffer) this.openBuffers.get(owner);
89
		synchronized (this.openBuffers) {
90
			return (IBuffer) this.openBuffers.get(owner);
91
	}
66
	}
92
	}
67
93
68
	/**
94
	/**
Lines 71-81 Link Here
71
	public synchronized static BufferManager getDefaultBufferManager() {
97
	public synchronized static BufferManager getDefaultBufferManager() {
72
		if (DEFAULT_BUFFER_MANAGER == null) {
98
		if (DEFAULT_BUFFER_MANAGER == null) {
73
			DEFAULT_BUFFER_MANAGER = new BufferManager();
99
			DEFAULT_BUFFER_MANAGER = new BufferManager();
74
		}
100
	}
75
		return DEFAULT_BUFFER_MANAGER;
101
		return DEFAULT_BUFFER_MANAGER;
76
	}
102
	}
77
103
78
	/**
104
	/**
105
	 * Returns the default buffer factory.
106
	 * 
107
	 * @deprecated
108
	 */
109
	public IBufferFactory getDefaultBufferFactory() {
110
		return this.defaultBufferFactory;
111
	}
112
113
	/**
79
	 * Returns an enumeration of all open buffers.
114
	 * Returns an enumeration of all open buffers.
80
	 * <p>
115
	 * <p>
81
	 * The <code>Enumeration</code> answered is thread safe.
116
	 * The <code>Enumeration</code> answered is thread safe.
Lines 84-93 Link Here
84
	 * @return Enumeration of IBuffer
119
	 * @return Enumeration of IBuffer
85
	 */
120
	 */
86
	public Enumeration getOpenBuffers() {
121
	public Enumeration getOpenBuffers() {
122
		Enumeration result;
87
		synchronized (this.openBuffers) {
123
		synchronized (this.openBuffers) {
88
			this.openBuffers.shrink();
124
			this.openBuffers.shrink();
89
			return this.openBuffers.elements();
125
			result = this.openBuffers.elements();
90
		}
126
	}
127
		// close buffers that were removed from the cache if space was needed
128
		this.openBuffers.closeBuffers();
129
		return result;
91
	}
130
	}
92
131
93
	/**
132
	/**
Lines 98-105 Link Here
98
			String owner = ((Openable) buffer.getOwner())
137
			String owner = ((Openable) buffer.getOwner())
99
					.toStringWithAncestors();
138
					.toStringWithAncestors();
100
			System.out.println("Removing buffer for " + owner); //$NON-NLS-1$
139
			System.out.println("Removing buffer for " + owner); //$NON-NLS-1$
101
		}
140
	}
141
		synchronized (this.openBuffers) {
102
		this.openBuffers.remove(buffer.getOwner());
142
		this.openBuffers.remove(buffer.getOwner());
143
	}
144
		// close buffers that were removed from the cache (should be only one)
145
		this.openBuffers.closeBuffers();
103
		if (VERBOSE) {
146
		if (VERBOSE) {
104
			System.out
147
			System.out
105
					.println("-> Buffer cache filling ratio = " + NumberFormat.getInstance().format(this.openBuffers.fillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
148
					.println("-> Buffer cache filling ratio = " + NumberFormat.getInstance().format(this.openBuffers.fillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
(-)model/org/eclipse/dltk/internal/core/BufferCache.java (-4 / +23 lines)
Lines 9-14 Link Here
9
 *******************************************************************************/
9
 *******************************************************************************/
10
package org.eclipse.dltk.internal.core;
10
package org.eclipse.dltk.internal.core;
11
11
12
import java.util.ArrayList;
13
12
import org.eclipse.dltk.core.IBuffer;
14
import org.eclipse.dltk.core.IBuffer;
13
import org.eclipse.dltk.internal.core.util.LRUCache;
15
import org.eclipse.dltk.internal.core.util.LRUCache;
14
16
Lines 16-21 Link Here
16
 * An LRU cache of <code>IBuffers</code>.
18
 * An LRU cache of <code>IBuffers</code>.
17
 */
19
 */
18
public class BufferCache extends OverflowingLRUCache {
20
public class BufferCache extends OverflowingLRUCache {
21
22
	private ThreadLocal buffersToClose = new ThreadLocal();
19
/**
23
/**
20
 * Constructs a new buffer cache of the given size.
24
 * Constructs a new buffer cache of the given size.
21
 */
25
 */
Lines 37-56 Link Here
37
 */
41
 */
38
protected boolean close(LRUCacheEntry entry) {
42
protected boolean close(LRUCacheEntry entry) {
39
	IBuffer buffer= (IBuffer) entry._fValue;
43
	IBuffer buffer= (IBuffer) entry._fValue;
40
	
44
41
	// prevent buffer that have unsaved changes or working copy buffer to be removed
45
	// prevent buffer that have unsaved changes or working copy buffer to be removed
42
	// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=39311
46
	// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=39311
43
	if (!((Openable)buffer.getOwner()).canBufferBeRemovedFromCache(buffer)) {
47
	if (!((Openable)buffer.getOwner()).canBufferBeRemovedFromCache(buffer)) {
44
		return false;
48
		return false;
45
	} else {
49
	} else {
46
		buffer.close();
50
			ArrayList buffers = (ArrayList) this.buffersToClose.get();
51
			if (buffers == null) {
52
				buffers = new ArrayList();
53
				this.buffersToClose.set(buffers);
54
			}
55
			buffers.add(buffer);
47
		return true;
56
		return true;
48
	}
57
	}
49
}
58
}
59
60
	void closeBuffers() {
61
		ArrayList buffers = (ArrayList) this.buffersToClose.get();
62
		if (buffers == null)
63
			return;
64
		this.buffersToClose.set(null);
65
		for (int i = 0, length = buffers.size(); i < length; i++) {
66
			((IBuffer) buffers.get(i)).close();
67
		}
68
	}
50
	/**
69
	/**
51
	 * Returns a new instance of the reciever.
70
	 * Returns a new instance of the reciever.
52
	 */
71
	 */
53
	protected LRUCache newInstance(int size, int overflow) {
72
	protected LRUCache newInstance(int size, int newOverflow) {
54
		return new BufferCache(size, overflow);
73
		return new BufferCache(size, newOverflow);
55
	}
74
	}
56
}
75
}
(-)model/org/eclipse/dltk/internal/core/AbstractSourceModule.java (-33 / +37 lines)
Lines 618-680 Link Here
618
	protected IBuffer openBuffer(IProgressMonitor pm, Object info)
618
	protected IBuffer openBuffer(IProgressMonitor pm, Object info)
619
			throws ModelException {
619
			throws ModelException {
620
		// create buffer
620
		// create buffer
621
		final BufferManager bufManager = getBufferManager();
621
		BufferManager bufManager = getBufferManager();
622
		final boolean isWorkingCopy = isWorkingCopy();
622
		boolean isWorkingCopy = isWorkingCopy();
623
		IBuffer buffer = isWorkingCopy ? this.owner.createBuffer(this)
623
		IBuffer buffer = isWorkingCopy ? this.owner.createBuffer(this)
624
				: BufferManager.createBuffer(this);
624
				: BufferManager.createBuffer(this);
625
		if (buffer == null) {
625
		if (buffer == null)
626
			return null;
626
			return null;
627
628
		ISourceModule original = null;
629
		boolean mustSetToOriginalContent = false;
630
		if (isWorkingCopy) {
631
			// ensure that isOpen() is called outside the bufManager
632
			// synchronized block
633
			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=237772
634
			mustSetToOriginalContent = !isPrimary()
635
					&& (original = new SourceModule((ModelElement) getParent(),
636
							getElementName(), DefaultWorkingCopyOwner.PRIMARY))
637
							.isOpen();
627
		}
638
		}
628
639
629
		/*
640
		// synchronize to ensure that 2 threads are not putting 2 different
630
		 * synchronize to ensure that 2 threads are not putting 2 different
641
		// buffers at the same time
631
		 * buffers at the same time see
642
		// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146331
632
		 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=146331
633
		 */
634
		synchronized (bufManager) {
643
		synchronized (bufManager) {
635
			final IBuffer existingBuffer = bufManager.getBuffer(this);
644
			IBuffer existingBuffer = bufManager.getBuffer(this);
636
			if (existingBuffer != null)
645
			if (existingBuffer != null)
637
				return existingBuffer;
646
				return existingBuffer;
647
638
			// set the buffer source
648
			// set the buffer source
639
			char[] chars = buffer.getCharacters();
649
			if (buffer.getCharacters() == null) {
640
			if ((chars == null) || (chars.length == 0)) {
641
				if (isWorkingCopy) {
650
				if (isWorkingCopy) {
642
					ISourceModule original;
651
					if (mustSetToOriginalContent) {
643
					if (!isPrimary()
644
							&& (original = getOriginalSourceModule()).isOpen()) {
645
						buffer.setContents(original.getSource());
652
						buffer.setContents(original.getSource());
646
					} else {
653
					} else {
647
						char[] content;
654
						IFile file = (IFile) getResource();
648
						try {
655
						if (file == null || !file.exists()) {
649
							content = getBufferContent();
656
							// initialize buffer with empty contents
650
						} catch (ModelException e) {
657
							buffer.setContents(CharOperation.NO_CHAR);
651
							if (e.getStatus().getCode() == IModelStatusConstants.ELEMENT_DOES_NOT_EXIST) {
658
						} else {
652
								content = CharOperation.NO_CHAR;
659
							buffer.setContents(Util
653
							} else {
660
									.getResourceContentsAsCharArray(file));
654
								throw e;
655
							}
656
						}
661
						}
657
						buffer.setContents(content);
658
					}
662
					}
659
				} else {
663
				} else {
660
					char[] content = getBufferContent();
664
					IFile file = (IFile) getResource();
661
					buffer.setContents(content);
665
					if (file == null || !file.exists())
666
						throw newNotPresentException();
667
					buffer.setContents(Util
668
							.getResourceContentsAsCharArray(file));
662
				}
669
				}
663
			}
670
			}
664
671
665
			// add buffer to buffer cache
672
			// add buffer to buffer cache
666
			/*
673
			// note this may cause existing buffers to be removed from the
667
			 * note this may cause existing buffers to be removed from the
674
			// buffer cache, but only primary compilation unit's buffer
668
			 * buffer cache, but only primary compilation unit's buffer can be
675
			// can be closed, thus no call to a client's IBuffer#close() can be
669
			 * closed, thus no call to a client's IBuffer#close() can be done in
676
			// done in this synchronized block.
670
			 * this synchronized block.
671
			 */
672
			bufManager.addBuffer(buffer);
677
			bufManager.addBuffer(buffer);
673
678
674
			// listen to buffer changes
679
			// listen to buffer changes
675
			buffer.addBufferChangedListener(this);
680
			buffer.addBufferChangedListener(this);
676
		}
681
		}
677
678
		return buffer;
682
		return buffer;
679
	}
683
	}
680
684
(-)model/org/eclipse/dltk/internal/core/NullBuffer.java (+26 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 
9
 *******************************************************************************/
10
package org.eclipse.dltk.internal.core;
11
12
import org.eclipse.core.resources.IFile;
13
import org.eclipse.dltk.core.IOpenable;
14
15
/**
16
 * This class represents a null buffer. This buffer is used to represent a buffer for a class file
17
 * that has no source attached.
18
 */
19
public class NullBuffer extends Buffer {
20
	/**
21
	 * Creates a new null buffer on an underlying resource.
22
	 */
23
	public NullBuffer(IFile file, IOpenable owner, boolean readOnly) {
24
		super(file, owner, readOnly);
25
	}
26
}

Return to bug 262178