001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.kahadb.journal; 018 019 import java.io.IOException; 020 import java.util.ArrayList; 021 import java.util.HashMap; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 026 /** 027 * Used to pool DataFileAccessors. 028 * 029 * @author chirino 030 */ 031 public class DataFileAccessorPool { 032 033 private final Journal journal; 034 private final Map<Integer, Pool> pools = new HashMap<Integer, Pool>(); 035 private boolean closed; 036 private int maxOpenReadersPerFile = 5; 037 038 class Pool { 039 040 private final DataFile file; 041 private final List<DataFileAccessor> pool = new ArrayList<DataFileAccessor>(); 042 private boolean used; 043 private int openCounter; 044 private boolean disposed; 045 046 public Pool(DataFile file) { 047 this.file = file; 048 } 049 050 public DataFileAccessor openDataFileReader() throws IOException { 051 DataFileAccessor rc = null; 052 if (pool.isEmpty()) { 053 rc = new DataFileAccessor(journal, file); 054 } else { 055 rc = pool.remove(pool.size() - 1); 056 } 057 used = true; 058 openCounter++; 059 return rc; 060 } 061 062 public synchronized void closeDataFileReader(DataFileAccessor reader) { 063 openCounter--; 064 if (pool.size() >= maxOpenReadersPerFile || disposed) { 065 reader.dispose(); 066 } else { 067 pool.add(reader); 068 } 069 } 070 071 public synchronized void clearUsedMark() { 072 used = false; 073 } 074 075 public synchronized boolean isUsed() { 076 return used; 077 } 078 079 public synchronized void dispose() { 080 for (DataFileAccessor reader : pool) { 081 reader.dispose(); 082 } 083 pool.clear(); 084 disposed = true; 085 } 086 087 public synchronized int getOpenCounter() { 088 return openCounter; 089 } 090 091 } 092 093 public DataFileAccessorPool(Journal dataManager) { 094 this.journal = dataManager; 095 } 096 097 synchronized void clearUsedMark() { 098 for (Iterator<Pool> iter = pools.values().iterator(); iter.hasNext();) { 099 Pool pool = iter.next(); 100 pool.clearUsedMark(); 101 } 102 } 103 104 synchronized void disposeUnused() { 105 for (Iterator<Pool> iter = pools.values().iterator(); iter.hasNext();) { 106 Pool pool = iter.next(); 107 if (!pool.isUsed()) { 108 pool.dispose(); 109 iter.remove(); 110 } 111 } 112 } 113 114 synchronized void disposeDataFileAccessors(DataFile dataFile) { 115 if (closed) { 116 throw new IllegalStateException("Closed."); 117 } 118 Pool pool = pools.get(dataFile.getDataFileId()); 119 if (pool != null) { 120 if (pool.getOpenCounter() == 0) { 121 pool.dispose(); 122 pools.remove(dataFile.getDataFileId()); 123 } else { 124 throw new IllegalStateException("The data file is still in use: " + dataFile + ", use count: " + pool.getOpenCounter()); 125 } 126 } 127 } 128 129 synchronized DataFileAccessor openDataFileAccessor(DataFile dataFile) throws IOException { 130 if (closed) { 131 throw new IOException("Closed."); 132 } 133 134 Pool pool = pools.get(dataFile.getDataFileId()); 135 if (pool == null) { 136 pool = new Pool(dataFile); 137 pools.put(dataFile.getDataFileId(), pool); 138 } 139 return pool.openDataFileReader(); 140 } 141 142 synchronized void closeDataFileAccessor(DataFileAccessor reader) { 143 Pool pool = pools.get(reader.getDataFile().getDataFileId()); 144 if (pool == null || closed) { 145 reader.dispose(); 146 } else { 147 pool.closeDataFileReader(reader); 148 } 149 } 150 151 public synchronized void close() { 152 if (closed) { 153 return; 154 } 155 closed = true; 156 for (Iterator<Pool> iter = pools.values().iterator(); iter.hasNext();) { 157 Pool pool = iter.next(); 158 pool.dispose(); 159 } 160 pools.clear(); 161 } 162 163 }