001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.internal;
022:
023: import com.db4o.foundation.*;
024: import com.db4o.internal.marshall.*;
025: import com.db4o.marshall.*;
026:
027: /**
028: * @exclude
029: */
030: public class MarshallingBuffer implements WriteBuffer {
031:
032: private static final int SIZE_NEEDED = Const4.LONG_LENGTH;
033:
034: private static final int NO_PARENT = -Integer.MAX_VALUE;
035:
036: private Buffer _delegate;
037:
038: private int _lastOffSet;
039:
040: private int _addressInParent = NO_PARENT;
041:
042: private List4 _children;
043:
044: private FieldMetadata _indexedField;
045:
046: public int length() {
047: return offset();
048: }
049:
050: public int offset() {
051: if (_delegate == null) {
052: return 0;
053: }
054: return _delegate.offset();
055: }
056:
057: public void writeByte(byte b) {
058: prepareWrite();
059: _delegate.writeByte(b);
060: }
061:
062: public void writeBytes(byte[] bytes) {
063: prepareWrite(bytes.length);
064: _delegate.writeBytes(bytes);
065: }
066:
067: public void writeInt(int i) {
068: prepareWrite();
069: _delegate.writeInt(i);
070: }
071:
072: public void writeLong(long l) {
073: prepareWrite();
074: _delegate.writeLong(l);
075: }
076:
077: private void prepareWrite() {
078: prepareWrite(SIZE_NEEDED);
079: }
080:
081: private void prepareWrite(int sizeNeeded) {
082: if (_delegate == null) {
083: _delegate = new Buffer(sizeNeeded);
084: }
085: _lastOffSet = _delegate.offset();
086: if (remainingSize() < sizeNeeded) {
087: resize(sizeNeeded);
088: }
089: }
090:
091: private int remainingSize() {
092: return _delegate.length() - _delegate.offset();
093: }
094:
095: private void resize(int sizeNeeded) {
096: int newSize = _delegate.length() * 2;
097: if (newSize - _lastOffSet < sizeNeeded) {
098: newSize += sizeNeeded;
099: }
100: Buffer temp = new Buffer(newSize);
101: temp.offset(_lastOffSet);
102: _delegate.copyTo(temp, 0, 0, _delegate.length());
103: _delegate = temp;
104: }
105:
106: public void transferLastWriteTo(MarshallingBuffer other,
107: boolean storeLengthInLink) {
108: other.addressInParent(_lastOffSet, storeLengthInLink);
109: int length = _delegate.offset() - _lastOffSet;
110: other.prepareWrite(length);
111: int otherOffset = other._delegate.offset();
112: System.arraycopy(_delegate._buffer, _lastOffSet,
113: other._delegate._buffer, otherOffset, length);
114: _delegate.offset(_lastOffSet);
115: other._delegate.offset(otherOffset + length);
116: other._lastOffSet = otherOffset;
117: }
118:
119: private void addressInParent(int offset, boolean storeLengthInLink) {
120: _addressInParent = storeLengthInLink ? offset : -offset;
121: }
122:
123: public void transferContentTo(Buffer buffer) {
124: transferContentTo(buffer, length());
125: }
126:
127: public void transferContentTo(Buffer buffer, int length) {
128: System.arraycopy(_delegate._buffer, 0, buffer._buffer,
129: buffer._offset, length);
130: buffer._offset += length;
131: }
132:
133: public Buffer testDelegate() {
134: return _delegate;
135: }
136:
137: public MarshallingBuffer addChild() {
138: return addChild(true, false);
139: }
140:
141: public MarshallingBuffer addChild(boolean reserveLinkSpace,
142: boolean storeLengthInLink) {
143: MarshallingBuffer child = new MarshallingBuffer();
144: child.addressInParent(offset(), storeLengthInLink);
145: _children = new List4(_children, child);
146: if (reserveLinkSpace) {
147: reserveChildLinkSpace(storeLengthInLink);
148: }
149: return child;
150: }
151:
152: public void reserveChildLinkSpace(boolean storeLengthInLink) {
153: int length = storeLengthInLink ? Const4.INT_LENGTH * 2
154: : Const4.INT_LENGTH;
155: prepareWrite(length);
156: _delegate.incrementOffset(length);
157: }
158:
159: public void mergeChildren(MarshallingContext context,
160: int masterAddress, int linkOffset) {
161: mergeChildren(context, masterAddress, this , this , linkOffset);
162: }
163:
164: private static void mergeChildren(MarshallingContext context,
165: int masterAddress, MarshallingBuffer writeBuffer,
166: MarshallingBuffer parentBuffer, int linkOffset) {
167: if (parentBuffer._children == null) {
168: return;
169: }
170: Iterator4 i = new Iterator4Impl(parentBuffer._children);
171: while (i.moveNext()) {
172: merge(context, masterAddress, writeBuffer, parentBuffer,
173: (MarshallingBuffer) i.current(), linkOffset);
174: }
175: }
176:
177: private static void merge(MarshallingContext context,
178: int masterAddress, MarshallingBuffer writeBuffer,
179: MarshallingBuffer parentBuffer,
180: MarshallingBuffer childBuffer, int linkOffset) {
181:
182: int childPosition = writeBuffer.offset();
183:
184: writeBuffer.reserve(childBuffer.blockedLength());
185:
186: mergeChildren(context, masterAddress, writeBuffer, childBuffer,
187: linkOffset);
188:
189: int savedWriteBufferOffset = writeBuffer.offset();
190: writeBuffer.seek(childPosition);
191: childBuffer.transferContentTo(writeBuffer._delegate);
192: writeBuffer.seek(savedWriteBufferOffset);
193:
194: parentBuffer.writeLink(childBuffer, childPosition + linkOffset,
195: childBuffer.unblockedLength());
196:
197: childBuffer.writeIndex(context, masterAddress, childPosition
198: + linkOffset);
199:
200: }
201:
202: public void seek(int offset) {
203: _delegate.offset(offset);
204: }
205:
206: private void reserve(int length) {
207: prepareWrite(length);
208: _delegate.offset(_delegate.offset() + length);
209: }
210:
211: private void writeLink(MarshallingBuffer child, int position,
212: int length) {
213: int offset = offset();
214: _delegate.offset(child.addressInParent());
215: _delegate.writeInt(position);
216: if (child.storeLengthInLink()) {
217: _delegate.writeInt(length);
218: }
219: _delegate.offset(offset);
220: }
221:
222: private void writeIndex(MarshallingContext context,
223: int masterAddress, int position) {
224: if (_indexedField != null) {
225:
226: // for now this is a String index only, it takes the entire slot.
227:
228: StatefulBuffer buffer = new StatefulBuffer(context
229: .transaction(), unblockedLength());
230:
231: int blockedPosition = context.container().bytesToBlocks(
232: position);
233:
234: int indexID = masterAddress + blockedPosition;
235:
236: buffer.setID(indexID);
237: buffer.address(indexID);
238:
239: transferContentTo(buffer, unblockedLength());
240:
241: _indexedField.addIndexEntry(context.transaction(), context
242: .objectID(), buffer);
243: }
244: }
245:
246: private int addressInParent() {
247: if (!hasParent()) {
248: throw new IllegalStateException();
249: }
250: if (_addressInParent < 0) {
251: return -_addressInParent;
252: }
253: return _addressInParent;
254: }
255:
256: public void debugDecrementLastOffset(int count) {
257: _lastOffSet -= count;
258: }
259:
260: public boolean hasParent() {
261: return _addressInParent != NO_PARENT;
262: }
263:
264: private boolean storeLengthInLink() {
265: return _addressInParent > 0;
266: }
267:
268: public void requestIndexEntry(FieldMetadata fieldMetadata) {
269: _indexedField = fieldMetadata;
270: }
271:
272: public MarshallingBuffer checkBlockAlignment(
273: MarshallingContext context,
274: MarshallingBuffer precedingBuffer, IntByRef precedingLength) {
275:
276: _lastOffSet = offset();
277:
278: if (doBlockAlign()) {
279: precedingBuffer.blockAlign(context, precedingLength.value);
280: }
281: if (precedingBuffer != null) {
282: precedingLength.value += precedingBuffer.length();
283: }
284: precedingBuffer = this ;
285: if (_children != null) {
286: Iterator4 i = new Iterator4Impl(_children);
287: while (i.moveNext()) {
288: precedingBuffer = ((MarshallingBuffer) i.current())
289: .checkBlockAlignment(context, precedingBuffer,
290: precedingLength);
291: }
292: }
293: return precedingBuffer;
294: }
295:
296: private void blockAlign(MarshallingContext context,
297: int precedingLength) {
298: int totalLength = context.container().blockAlignedBytes(
299: precedingLength + length());
300: int newLength = totalLength - precedingLength;
301: blockAlign(newLength);
302: }
303:
304: public int marshalledLength() {
305: int length = length();
306: if (_children != null) {
307: Iterator4 i = new Iterator4Impl(_children);
308: while (i.moveNext()) {
309: length += ((MarshallingBuffer) i.current())
310: .marshalledLength();
311: }
312: }
313: return length;
314: }
315:
316: private void blockAlign(int length) {
317: if (length > _delegate.length()) {
318: int sizeNeeded = length - _delegate.offset();
319: prepareWrite(sizeNeeded);
320: }
321: _delegate.offset(length);
322: }
323:
324: private boolean doBlockAlign() {
325: return hasParent(); // For now we block align every linked entry. Indexes could be created late.
326: }
327:
328: private int blockedLength() {
329: return length();
330: }
331:
332: private int unblockedLength() {
333: // This is only valid after checkBlockAlignMent has been called.
334: return _lastOffSet;
335: }
336:
337: }
|