1 package org.apache.lucene.store.db; 2 3 /** 4 * Licensed to the Apache Software Foundation (ASF) under one or more 5 * contributor license agreements. See the NOTICE file distributed with 6 * this work for additional information regarding copyright ownership. 7 * The ASF licenses this file to You under the Apache License, Version 2.0 8 * (the "License"); you may not use this file except in compliance with 9 * the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 import java.io.IOException; 21 import java.io.ByteArrayInputStream; 22 import java.io.DataInputStream; 23 import java.util.Set; 24 import java.util.HashSet; 25 import java.util.List; 26 import java.util.ArrayList; 27 import java.util.Iterator; 28 import java.util.Collections; 29 30 import org.apache.lucene.store.Directory; 31 import org.apache.lucene.store.Lock; 32 import org.apache.lucene.store.IndexOutput; 33 import org.apache.lucene.store.IndexInput; 34 35 import com.sleepycat.db.internal.DbEnv; 36 import com.sleepycat.db.internal.Db; 37 import com.sleepycat.db.internal.DbConstants; 38 import com.sleepycat.db.DatabaseEntry; 39 import com.sleepycat.db.internal.Dbc; 40 import com.sleepycat.db.internal.DbTxn; 41 import com.sleepycat.db.DatabaseException; 42 43 import com.sleepycat.db.Database; 44 import com.sleepycat.db.Transaction; 45 import com.sleepycat.db.DbHandleExtractor; 46 47 /** 48 * A DbDirectory is a Berkeley DB 4.3 based implementation of 49 * {@link org.apache.lucene.store.Directory Directory}. It uses two 50 * {@link com.sleepycat.db.internal.Db Db} database handles, one for storing file 51 * records and another for storing file data blocks. 52 * 53 */ 54 55 public class DbDirectory extends Directory { 56 57 protected Set<DbIndexOutput> openFiles = Collections.synchronizedSet(new HashSet<DbIndexOutput>()); 58 protected Db files, blocks; 59 protected DbTxn txn; 60 protected int flags; 61 62 /** 63 * Instantiate a DbDirectory. The same threading rules that apply to 64 * Berkeley DB handles apply to instances of DbDirectory. 65 * 66 * @param txn a transaction handle that is going to be used for all db 67 * operations done by this instance. This parameter may be 68 * <code>null</code>. 69 * @param files a db handle to store file records. 70 * @param blocks a db handle to store file data blocks. 71 * @param flags flags used for db read operations. 72 */ 73 74 public DbDirectory(DbTxn txn, Db files, Db blocks, int flags) 75 { 76 super(); 77 78 this.txn = txn; 79 this.files = files; 80 this.blocks = blocks; 81 this.flags = flags; 82 } 83 84 public DbDirectory(Transaction txn, Database files, Database blocks, 85 int flags) 86 { 87 super(); 88 89 this.txn = txn != null ? DbHandleExtractor.getDbTxn(txn) : null; 90 this.files = DbHandleExtractor.getDb(files); 91 this.blocks = DbHandleExtractor.getDb(blocks); 92 this.flags = flags; 93 } 94 95 public DbDirectory(Transaction txn, Database files, Database blocks) 96 { 97 this(txn, files, blocks, 0); 98 } 99 100 @Override 101 public void close() 102 throws IOException 103 { 104 flush(); 105 } 106 107 /** 108 * Flush the currently open files. After they have been flushed it is 109 * safe to commit the transaction without closing this DbDirectory 110 * instance first. 111 * @see #setTransaction 112 */ 113 public void flush() 114 throws IOException 115 { 116 Iterator<DbIndexOutput> iterator = openFiles.iterator(); 117 118 while (iterator.hasNext()) 119 iterator.next().flush(); 120 } 121 122 @Override 123 public IndexOutput createOutput(String name) 124 throws IOException 125 { 126 return new DbIndexOutput(this, name, true); 127 } 128 129 @Override 130 public void deleteFile(String name) 131 throws IOException 132 { 133 new File(name).delete(this); 134 } 135 136 @Override 137 public boolean fileExists(String name) 138 throws IOException 139 { 140 return new File(name).exists(this); 141 } 142 143 @Override 144 public long fileLength(String name) 145 throws IOException 146 { 147 File file = new File(name); 148 149 if (file.exists(this)) 150 return file.getLength(); 151 152 throw new IOException("File does not exist: " + name); 153 } 154 155 @Override 156 public long fileModified(String name) 157 throws IOException 158 { 159 File file = new File(name); 160 161 if (file.exists(this)) 162 return file.getTimeModified(); 163 164 throw new IOException("File does not exist: " + name); 165 } 166 167 @Override 168 public String[] listAll() 169 throws IOException 170 { 171 Dbc cursor = null; 172 List<String> list = new ArrayList<String>(); 173 174 try { 175 try { 176 DatabaseEntry key = new DatabaseEntry(new byte[0]); 177 DatabaseEntry data = new DatabaseEntry((byte[]) null); 178 179 data.setPartial(true); 180 181 cursor = files.cursor(txn, flags); 182 183 if (cursor.get(key, data, 184 DbConstants.DB_SET_RANGE | flags) != DbConstants.DB_NOTFOUND) 185 { 186 ByteArrayInputStream buffer = 187 new ByteArrayInputStream(key.getData()); 188 DataInputStream in = new DataInputStream(buffer); 189 String name = in.readUTF(); 190 191 in.close(); 192 list.add(name); 193 194 while (cursor.get(key, data, 195 DbConstants.DB_NEXT | flags) != DbConstants.DB_NOTFOUND) { 196 buffer = new ByteArrayInputStream(key.getData()); 197 in = new DataInputStream(buffer); 198 name = in.readUTF(); 199 in.close(); 200 201 list.add(name); 202 } 203 } 204 } finally { 205 if (cursor != null) 206 cursor.close(); 207 } 208 } catch (DatabaseException e) { 209 throw new IOException(e.getMessage()); 210 } 211 212 return list.toArray(new String[list.size()]); 213 } 214 215 @Override 216 public IndexInput openInput(String name) 217 throws IOException 218 { 219 return new DbIndexInput(this, name); 220 } 221 222 @Override 223 public Lock makeLock(String name) 224 { 225 return new DbLock(); 226 } 227 228 @Override 229 public void touchFile(String name) 230 throws IOException 231 { 232 File file = new File(name); 233 long length = 0L; 234 235 if (file.exists(this)) 236 length = file.getLength(); 237 238 file.modify(this, length, System.currentTimeMillis()); 239 } 240 241 /** 242 * Once a transaction handle was committed it is no longer valid. In 243 * order to continue using this DbDirectory instance after a commit, the 244 * transaction handle has to be replaced. 245 * @param txn the new transaction handle to use 246 */ 247 public void setTransaction(Transaction txn) 248 { 249 setTransaction(txn != null ? DbHandleExtractor.getDbTxn(txn) : null); 250 } 251 252 /** 253 * Once a transaction handle was committed it is no longer valid. In 254 * order to continue using this DbDirectory instance after a commit, the 255 * transaction handle has to be replaced. 256 * @param txn the new transaction handle to use 257 */ 258 public void setTransaction(DbTxn txn) 259 { 260 this.txn = txn; 261 } 262 }