001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.repository.disk;
043:
044: import java.io.IOException;
045: import java.io.Serializable;
046: import java.util.Arrays;
047: import java.util.Collection;
048: import java.util.Collections;
049: import java.util.Comparator;
050: import java.util.Map;
051: import java.util.Map.Entry;
052: import java.util.Set;
053: import java.util.concurrent.ConcurrentHashMap;
054: import java.util.concurrent.locks.ReadWriteLock;
055: import java.util.concurrent.locks.ReentrantReadWriteLock;
056: import org.netbeans.modules.cnd.repository.api.Repository;
057: import org.netbeans.modules.cnd.repository.queue.RepositoryQueue;
058: import org.netbeans.modules.cnd.repository.queue.RepositoryThreadManager;
059: import org.netbeans.modules.cnd.repository.spi.Key;
060: import org.netbeans.modules.cnd.repository.spi.Persistent;
061: import org.netbeans.modules.cnd.repository.spi.RepositoryListener;
062: import org.netbeans.modules.cnd.repository.translator.RepositoryTranslatorImpl;
063: import org.netbeans.modules.cnd.repository.util.RepositoryExceptionImpl;
064: import org.netbeans.modules.cnd.repository.util.RepositoryListenersManager;
065:
066: /**
067: *
068: * @author Sergey Grinev
069: */
070: public final class DiskRepositoryManager extends AbstractDiskRepository
071: implements Repository {
072: private final Map<String, UnitDiskRepository> repositories;
073:
074: private static DiskRepositoryManager instance = new DiskRepositoryManager();
075: private final RepositoryQueue queue;
076: private final RepositoryThreadManager threadManager;
077: private final Persistent removedObject;
078: private final ReadWriteLock rwLock;
079:
080: public static DiskRepositoryManager getInstance() {
081: return instance;
082: }
083:
084: private DiskRepositoryManager() {
085: removedObject = new RemovedPersistent();
086: rwLock = new ReentrantReadWriteLock(true);
087: threadManager = new RepositoryThreadManager(this , rwLock);
088: queue = threadManager.startup();
089: repositories = new ConcurrentHashMap<String, UnitDiskRepository>();
090: }
091:
092: private AbstractDiskRepository getCreateRepository(Key key)
093: throws IOException {
094: assert key != null;
095:
096: final String unitName = key.getUnit().toString();
097: assert unitName != null;
098:
099: UnitDiskRepository repository = repositories.get(unitName);
100:
101: if (repository == null) {
102: synchronized (repositories) {
103: repository = repositories.get(unitName);
104: if (repository == null) {
105: if (RepositoryListenersManager.getInstance()
106: .fireUnitOpenedEvent(unitName)) {
107: RepositoryTranslatorImpl
108: .loadUnitIndex(unitName);
109: repository = new UnitDiskRepository(unitName);
110: repositories.put(unitName, repository);
111: }
112: }
113: }
114: }
115:
116: return repository;
117: }
118:
119: public void put(Key id, Persistent obj) {
120: queue.addLast(id, obj);
121: }
122:
123: public void write(Key key, Persistent object) {
124: try {
125: AbstractDiskRepository diskRep = getCreateRepository(key);
126:
127: if (diskRep == null)
128: return;
129:
130: if (object instanceof RemovedPersistent) {
131: diskRep.remove(key);
132: } else {
133: diskRep.write(key, object);
134: }
135: } catch (Throwable ex) {
136: RepositoryListenersManager.getInstance().fireAnException(
137: key.getUnit().toString(),
138: new RepositoryExceptionImpl(ex));
139: }
140: }
141:
142: public Persistent get(Key key) {
143: assert key != null;
144:
145: try {
146: AbstractDiskRepository diskRep = getCreateRepository(key);
147: if (diskRep != null) {
148: return diskRep.get(key);
149: }
150: } catch (Throwable ex) {
151: RepositoryListenersManager.getInstance().fireAnException(
152: key.getUnit().toString(),
153: new RepositoryExceptionImpl(ex));
154: }
155:
156: return null;
157: }
158:
159: public void remove(Key key) {
160: queue.addLast(key, removedObject);
161: }
162:
163: public void waitForQueue() throws InterruptedException {
164: if (queue != null) {
165: while (!queue.disposable()) {
166: Thread.sleep(50);
167: queue.onIdle();
168: }
169: }
170: }
171:
172: public void shutdown() {
173: if (threadManager != null) {
174: threadManager.shutdown();
175: }
176:
177: close();
178: }
179:
180: private void iterateWith(Visitor visitor) {
181: for (Entry<String, UnitDiskRepository> entry : repositories
182: .entrySet()) {
183: try {
184: visitor.visit(entry.getValue());
185: } catch (Throwable exc) {
186: RepositoryListenersManager.getInstance()
187: .fireAnException(entry.getKey(),
188: new RepositoryExceptionImpl(exc));
189: }
190: }
191: }
192:
193: public boolean maintenance(long timeout) {
194: if (repositories.size() == 0) {
195: return false;
196: }
197:
198: Collection<UnitDiskRepository> values = repositories.values();
199: UnitDiskRepository[] sfs = (UnitDiskRepository[]) values
200: .toArray(new UnitDiskRepository[values.size()]);
201: Arrays.sort(sfs, new FragmentationComparator());
202: boolean needMoreTime = false;
203: long start = System.currentTimeMillis();
204: for (int i = 0; i < sfs.length; i++) {
205: if (timeout <= 0) {
206: needMoreTime = true;
207: break;
208: }
209:
210: if (sfs[i].maintenance(timeout)) {
211: needMoreTime = true;
212: }
213: timeout -= (System.currentTimeMillis() - start);
214: }
215: return needMoreTime;
216: }
217:
218: public void openUnit(String unitName) {
219: }
220:
221: public void closeUnit(final String unitName,
222: final boolean cleanRepository, Set<String> requiredUnits) {
223:
224: try {
225: rwLock.writeLock().lock();
226:
227: Collection<RepositoryQueue.Entry> removedEntries = queue
228: .clearQueue(new UnitFilter(unitName));
229: if (!cleanRepository) {
230: for (RepositoryQueue.Entry entry : removedEntries) {
231: write(entry.getKey(), entry.getValue());
232: }
233: }
234:
235: AbstractDiskRepository repository = repositories
236: .remove(unitName);
237:
238: if (repository != null) {
239: try {
240: repository.close();
241: } catch (Throwable exc) {
242: RepositoryListenersManager.getInstance()
243: .fireAnException(unitName,
244: new RepositoryExceptionImpl(exc));
245: }
246: }
247:
248: } finally {
249: rwLock.writeLock().unlock();
250: }
251:
252: //clean the repository cach files here if it is necessary
253: //
254: StorageAllocator allocator = StorageAllocator.getInstance();
255: if (cleanRepository) {
256: allocator.deleteUnitFiles(unitName, true);
257: }
258: allocator.closeUnit(unitName);
259: }
260:
261: public void removeUnit(String unitName) {
262: closeUnit(unitName, true, Collections.<String> emptySet());
263: }
264:
265: public void close() {
266: boolean saveAll = true;
267: try {
268: rwLock.writeLock().lock();
269: cleanAndWriteQueue();
270: iterateWith(new CloseVisitor());
271: repositories.clear();
272: } finally {
273: rwLock.writeLock().unlock();
274: }
275:
276: }
277:
278: public int getFragmentationPercentage() throws IOException {
279: return 0;
280: }
281:
282: public void hang(Key key, Persistent obj) {
283: }
284:
285: public void debugClear() {
286: try {
287: rwLock.writeLock().lock();
288: cleanAndWriteQueue();
289: } finally {
290: rwLock.writeLock().unlock();
291: }
292: }
293:
294: private void cleanAndWriteQueue() {
295: Collection<RepositoryQueue.Entry> removedEntries = queue
296: .clearQueue(new AllFilter());
297: for (RepositoryQueue.Entry entry : removedEntries) {
298: write(entry.getKey(), entry.getValue());
299: }
300: }
301:
302: public void cleanCaches() {
303: StorageAllocator.getInstance().cleanRepositoryCaches();
304: }
305:
306: public void registerRepositoryListener(
307: final RepositoryListener aListener) {
308: }
309:
310: public void unregisterRepositoryListener(
311: final RepositoryListener aListener) {
312: }
313:
314: public void startup(int persistMechanismVersion) {
315: }
316:
317: static private class RemovedPersistent implements Persistent {
318:
319: }
320:
321: private interface Visitor {
322: void visit(AbstractDiskRepository repository)
323: throws IOException;
324: }
325:
326: private static class UnitFilter implements RepositoryQueue.Filter {
327:
328: private String unitName;
329:
330: public UnitFilter(String unitName) {
331: this .unitName = unitName;
332: }
333:
334: public boolean accept(Key key, Persistent value) {
335: return key.getUnit().equals(unitName);
336: }
337: }
338:
339: private class AllFilter implements RepositoryQueue.Filter {
340: public boolean accept(Key key, Persistent value) {
341: return true;
342: }
343: }
344:
345: static private class CloseVisitor implements Visitor {
346:
347: public CloseVisitor() {
348: super ();
349: }
350:
351: public void visit(AbstractDiskRepository repository)
352: throws IOException {
353: repository.close();
354: }
355: }
356:
357: private static class FragmentationComparator implements
358: Comparator<UnitDiskRepository>, Serializable {
359: private static final long serialVersionUID = 7249069246763182397L;
360:
361: public int compare(UnitDiskRepository o1, UnitDiskRepository o2) {
362: return o2.getFragmentationPercentage()
363: - o1.getFragmentationPercentage();
364: }
365: }
366: }
|