001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.needle.gigaspaces.store;
018:
019: import java.io.IOException;
020:
021: import net.jini.core.lease.Lease;
022: import org.apache.lucene.store.IndexOutput;
023:
024: /**
025: * Only use buckets to write the file to the index. Writes a header file and one
026: * or more buckets that hold the file content.
027: *
028: * <p>Allows only seeking to the first bucket, which is what Lucene does with typical
029: * bucket size.
030: *
031: * @author kimchy
032: */
033: class GigaSpaceMemIndexOutput extends IndexOutput {
034:
035: private GigaSpaceDirectory dir;
036:
037: private String fileName;
038:
039: private FileBucketEntry firstBucketEntry;
040:
041: private byte[] buffer;
042:
043: private int bufferPosition;
044:
045: private int currentBucketIndex;
046:
047: private long length;
048:
049: private long position;
050:
051: private boolean open;
052:
053: // seek occured, we only allow to work on the first bucket
054: private boolean seekOccured;
055:
056: public GigaSpaceMemIndexOutput(GigaSpaceDirectory dir,
057: String fileName) throws IOException {
058: this .dir = dir;
059: this .fileName = fileName;
060: open = true;
061: buffer = new byte[dir.getBucketSize()];
062: // this file is overridden by Lucene, so delete it first
063: if (fileName.equals("segments.gen")) {
064: dir.deleteFile(fileName);
065: }
066: }
067:
068: public void writeByte(byte b) throws IOException {
069: if (bufferPosition == dir.getBucketSize()) {
070: if (seekOccured) {
071: throw new GigaSpaceDirectoryException(dir
072: .getIndexName(), fileName,
073: "Seek occured and overflowed first bucket");
074: }
075: flushBucket();
076: }
077: buffer[bufferPosition++] = b;
078: if (!seekOccured) {
079: length++;
080: position++;
081: }
082: }
083:
084: public void writeBytes(byte[] b, int offset, int len)
085: throws IOException {
086: if (!seekOccured) {
087: position += len;
088: length += len;
089: }
090: while (len > 0) {
091: if (bufferPosition == dir.getBucketSize()) {
092: if (seekOccured) {
093: throw new GigaSpaceDirectoryException(dir
094: .getIndexName(), fileName,
095: "Seek occured and overflowed first bucket");
096: }
097: flushBucket();
098: }
099:
100: int remainInBuffer = dir.getBucketSize() - bufferPosition;
101: int bytesToCopy = len < remainInBuffer ? len
102: : remainInBuffer;
103: System.arraycopy(b, offset, buffer, bufferPosition,
104: bytesToCopy);
105: offset += bytesToCopy;
106: len -= bytesToCopy;
107: bufferPosition += bytesToCopy;
108: }
109: }
110:
111: public void flush() throws IOException {
112: // do nothing here
113: }
114:
115: public void close() throws IOException {
116: if (!open) {
117: return;
118: }
119: open = false;
120: // flush any bucket we might have
121: flushBucket();
122: try {
123: dir.getSpace().write(firstBucketEntry, null, Lease.FOREVER);
124: } catch (Exception e) {
125: throw new GigaSpaceDirectoryException(dir.getIndexName(),
126: fileName, "Failed to write bucket [0]", e);
127: }
128: try {
129: dir.getSpace()
130: .write(
131: new FileEntry(dir.getIndexName(), fileName,
132: length), null, Lease.FOREVER);
133: } catch (Exception e) {
134: throw new GigaSpaceDirectoryException(dir.getIndexName(),
135: fileName, "Failed to write file entry", e);
136: }
137: buffer = null;
138: firstBucketEntry = null;
139: }
140:
141: public long getFilePointer() {
142: return this .position;
143: }
144:
145: public void seek(long pos) throws IOException {
146: if (pos >= dir.getBucketSize()) {
147: throw new GigaSpaceDirectoryException(dir.getIndexName(),
148: fileName,
149: "seek called outside of first bucket boundries");
150: }
151: // create the first bucket if still not created
152: if (firstBucketEntry == null) {
153: firstBucketEntry = new FileBucketEntry(dir.getIndexName(),
154: fileName, 0, new byte[bufferPosition]);
155: System.arraycopy(buffer, 0, firstBucketEntry.data, 0,
156: bufferPosition);
157: } else {
158: // flush the current buffer. We only seek into the first bucket
159: // so no need to keep it around
160: if (!seekOccured) {
161: flushBucket(currentBucketIndex, buffer, bufferPosition);
162: }
163: }
164: position = pos;
165: currentBucketIndex = 0;
166: bufferPosition = (int) pos;
167: buffer = firstBucketEntry.data;
168: seekOccured = true;
169: }
170:
171: public long length() throws IOException {
172: return length;
173: }
174:
175: private void flushBucket() throws IOException {
176: if (currentBucketIndex == 0) {
177: if (firstBucketEntry == null) {
178: firstBucketEntry = new FileBucketEntry(dir
179: .getIndexName(), fileName, 0,
180: new byte[bufferPosition]);
181: System.arraycopy(buffer, 0, firstBucketEntry.data, 0,
182: bufferPosition);
183: } else {
184: // do nothing, we are writing directly into the first buffer
185: }
186: } else {
187: if (bufferPosition > 0) {
188: flushBucket(currentBucketIndex, buffer, bufferPosition);
189: }
190: }
191: currentBucketIndex++;
192: bufferPosition = 0;
193: }
194:
195: private void flushBucket(long bucketIndex, byte[] buffer, int length)
196: throws IOException {
197: FileBucketEntry fileBucketEntry = new FileBucketEntry(dir
198: .getIndexName(), fileName, bucketIndex, null);
199: fileBucketEntry.data = new byte[length];
200: System.arraycopy(buffer, 0, fileBucketEntry.data, 0, length);
201: try {
202: dir.getSpace().write(fileBucketEntry, null, Lease.FOREVER);
203: } catch (Exception e) {
204: throw new GigaSpaceDirectoryException(dir.getIndexName(),
205: fileName, "Failed to write bucket [" + bucketIndex
206: + "]", e);
207: }
208: }
209: }
|