KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > lucene > store > MMapDirectory


1 package org.apache.lucene.store;
2
3 /**
4  * Copyright 2004 The Apache Software Foundation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18  
19 import java.io.IOException JavaDoc;
20 import java.io.File JavaDoc;
21 import java.io.RandomAccessFile JavaDoc;
22 import java.nio.ByteBuffer JavaDoc;
23 import java.nio.channels.FileChannel JavaDoc;
24 import java.nio.channels.FileChannel.MapMode;
25
26 /** File-based {@link Directory} implementation that uses mmap for input.
27  *
28  * <p>To use this, invoke Java with the System property
29  * org.apache.lucene.FSDirectory.class set to
30  * org.apache.lucene.store.MMapDirectory. This will cause {@link
31  * FSDirectory#getDirectory(File,boolean)} to return instances of this class.
32  */

33 public class MMapDirectory extends FSDirectory {
34
35   private static class MMapIndexInput extends IndexInput {
36
37     private ByteBuffer JavaDoc buffer;
38     private final long length;
39
40     private MMapIndexInput(RandomAccessFile JavaDoc raf) throws IOException JavaDoc {
41         this.length = raf.length();
42         this.buffer = raf.getChannel().map(MapMode.READ_ONLY, 0, length);
43     }
44
45     public byte readByte() throws IOException JavaDoc {
46       return buffer.get();
47     }
48
49     public void readBytes(byte[] b, int offset, int len)
50       throws IOException JavaDoc {
51       buffer.get(b, offset, len);
52     }
53
54     public long getFilePointer() {
55       return buffer.position();
56     }
57
58     public void seek(long pos) throws IOException JavaDoc {
59       buffer.position((int)pos);
60     }
61
62     public long length() {
63       return length;
64     }
65
66     public Object JavaDoc clone() {
67       MMapIndexInput clone = (MMapIndexInput)super.clone();
68       clone.buffer = buffer.duplicate();
69       return clone;
70     }
71
72     public void close() throws IOException JavaDoc {}
73   }
74
75   /* Added class MultiMMapIndexInput, Paul Elschot.
76    * Slightly adapted constructor of MMapIndexInput.
77    * Licensed under the Apache License, Version 2.0.
78    */

79   private static class MultiMMapIndexInput extends IndexInput {
80   
81     private ByteBuffer JavaDoc[] buffers;
82     private int[] bufSizes; // keep here, ByteBuffer.size() method is optional
83

84     private final long length;
85   
86     private int curBufIndex;
87     private final int maxBufSize;
88   
89     private ByteBuffer JavaDoc curBuf; // redundant for speed: buffers[curBufIndex]
90
private int curAvail; // redundant for speed: (bufSizes[curBufIndex] - curBuf.position())
91

92     
93     public MultiMMapIndexInput(RandomAccessFile JavaDoc raf, int maxBufSize)
94       throws IOException JavaDoc {
95       this.length = raf.length();
96       this.maxBufSize = maxBufSize;
97       
98       if (maxBufSize <= 0)
99         throw new IllegalArgumentException JavaDoc("Non positive maxBufSize: "
100                                            + maxBufSize);
101       
102       if ((length / maxBufSize) > Integer.MAX_VALUE)
103         throw new IllegalArgumentException JavaDoc
104           ("RandomAccessFile too big for maximum buffer size: "
105            + raf.toString());
106       
107       int nrBuffers = (int) (length / maxBufSize);
108       if ((nrBuffers * maxBufSize) < length) nrBuffers++;
109       
110       this.buffers = new ByteBuffer JavaDoc[nrBuffers];
111       this.bufSizes = new int[nrBuffers];
112       
113       long bufferStart = 0;
114       FileChannel JavaDoc rafc = raf.getChannel();
115       for (int bufNr = 0; bufNr < nrBuffers; bufNr++) {
116         int bufSize = (length > (bufferStart + maxBufSize))
117           ? maxBufSize
118           : (int) (length - bufferStart);
119         this.buffers[bufNr] = rafc.map(MapMode.READ_ONLY,bufferStart,bufSize);
120         this.bufSizes[bufNr] = bufSize;
121         bufferStart += bufSize;
122       }
123       seek(0L);
124     }
125   
126     public byte readByte() throws IOException JavaDoc {
127       // Performance might be improved by reading ahead into an array of
128
// eg. 128 bytes and readByte() from there.
129
if (curAvail == 0) {
130         curBufIndex++;
131         curBuf = buffers[curBufIndex]; // index out of bounds when too many bytes requested
132
curBuf.position(0);
133         curAvail = bufSizes[curBufIndex];
134       }
135       curAvail--;
136       return curBuf.get();
137     }
138   
139     public void readBytes(byte[] b, int offset, int len) throws IOException JavaDoc {
140       while (len > curAvail) {
141         curBuf.get(b, offset, curAvail);
142         len -= curAvail;
143         offset += curAvail;
144         curBufIndex++;
145         curBuf = buffers[curBufIndex]; // index out of bounds when too many bytes requested
146
curBuf.position(0);
147         curAvail = bufSizes[curBufIndex];
148       }
149       curBuf.get(b, offset, len);
150       curAvail -= len;
151     }
152   
153     public long getFilePointer() {
154       return (curBufIndex * (long) maxBufSize) + curBuf.position();
155     }
156   
157     public void seek(long pos) throws IOException JavaDoc {
158       curBufIndex = (int) (pos / maxBufSize);
159       curBuf = buffers[curBufIndex];
160       int bufOffset = (int) (pos - (curBufIndex * maxBufSize));
161       curBuf.position(bufOffset);
162       curAvail = bufSizes[curBufIndex] - bufOffset;
163     }
164   
165     public long length() {
166       return length;
167     }
168   
169     public Object JavaDoc clone() {
170       MultiMMapIndexInput clone = (MultiMMapIndexInput)super.clone();
171       clone.buffers = new ByteBuffer JavaDoc[buffers.length];
172       // No need to clone bufSizes.
173
// Since most clones will use only one buffer, duplicate() could also be
174
// done lazy in clones, eg. when adapting curBuf.
175
for (int bufNr = 0; bufNr < buffers.length; bufNr++) {
176         clone.buffers[bufNr] = buffers[bufNr].duplicate();
177       }
178       try {
179         clone.seek(getFilePointer());
180       } catch(IOException JavaDoc ioe) {
181         throw new RuntimeException JavaDoc(ioe);
182       };
183       return clone;
184     }
185   
186     public void close() throws IOException JavaDoc {}
187   }
188   
189   private final int MAX_BBUF = Integer.MAX_VALUE;
190
191   public IndexInput openInput(String JavaDoc name) throws IOException JavaDoc {
192     File JavaDoc f = new File JavaDoc(getFile(), name);
193     RandomAccessFile JavaDoc raf = new RandomAccessFile JavaDoc(f, "r");
194     try {
195       return (raf.length() <= MAX_BBUF)
196              ? (IndexInput) new MMapIndexInput(raf)
197              : (IndexInput) new MultiMMapIndexInput(raf, MAX_BBUF);
198     } finally {
199       raf.close();
200     }
201   }
202 }
203
Popular Tags