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.*;
024: import com.db4o.foundation.*;
025: import com.db4o.internal.slots.*;
026:
027: /**
028: * public for .NET conversion reasons
029: *
030: * TODO: Split this class for individual usecases. Only use the member
031: * variables needed for the respective usecase.
032: *
033: * @exclude
034: */
035: public final class StatefulBuffer extends Buffer {
036:
037: private int i_address;
038: private int _addressOffset;
039:
040: private int i_cascadeDelete;
041:
042: private int i_id;
043:
044: // carries instantiation depth through the reading process
045: private int i_instantionDepth;
046: private int i_length;
047:
048: Transaction i_trans;
049:
050: // carries updatedepth depth through the update process
051: // and carries instantiation information through the reading process
052: private int i_updateDepth = 1;
053:
054: public int _payloadOffset;
055:
056: public StatefulBuffer(Transaction a_trans, int a_initialBufferSize) {
057: i_trans = a_trans;
058: i_length = a_initialBufferSize;
059: _buffer = new byte[i_length];
060: }
061:
062: public StatefulBuffer(Transaction a_trans, int address, int length) {
063: this (a_trans, length);
064: i_address = address;
065: }
066:
067: public StatefulBuffer(Transaction trans, Slot slot) {
068: this (trans, slot.address(), slot.length());
069: }
070:
071: public StatefulBuffer(Transaction trans, Pointer4 pointer) {
072: this (trans, pointer._slot);
073: i_id = pointer._id;
074: }
075:
076: public int cascadeDeletes() {
077: return i_cascadeDelete;
078: }
079:
080: public void debugCheckBytes() {
081: if (Debug.xbytes) {
082: if (_offset != i_length) {
083: // Db4o.log("!!! YapBytes.debugCheckBytes not all bytes used");
084: // This is normal for writing The FreeSlotArray, becauce one
085: // slot is possibly reserved by it's own pointer.
086: }
087: }
088: }
089:
090: public int getAddress() {
091: return i_address;
092: }
093:
094: public int addressOffset() {
095: return _addressOffset;
096: }
097:
098: public int getID() {
099: return i_id;
100: }
101:
102: public int getInstantiationDepth() {
103: return i_instantionDepth;
104: }
105:
106: public int length() {
107: return i_length;
108: }
109:
110: public ObjectContainerBase getStream() {
111: return i_trans.container();
112: }
113:
114: public ObjectContainerBase stream() {
115: return i_trans.container();
116: }
117:
118: public LocalObjectContainer file() {
119: return ((LocalTransaction) i_trans).file();
120: }
121:
122: public Transaction getTransaction() {
123: return i_trans;
124: }
125:
126: public int getUpdateDepth() {
127: return i_updateDepth;
128: }
129:
130: public byte[] getWrittenBytes() {
131: byte[] bytes = new byte[_offset];
132: System.arraycopy(_buffer, 0, bytes, 0, _offset);
133: return bytes;
134: }
135:
136: public int preparePayloadRead() {
137: int newPayLoadOffset = readInt();
138: int length = readInt();
139: int linkOffSet = _offset;
140: _offset = newPayLoadOffset;
141: _payloadOffset += length;
142: return linkOffSet;
143: }
144:
145: public void read() throws Db4oIOException {
146: stream()
147: .readBytes(_buffer, i_address, _addressOffset, i_length);
148: }
149:
150: public final StatefulBuffer readEmbeddedObject()
151: throws Db4oIOException {
152: int id = readInt();
153: int length = readInt();
154: if (id == 0) {
155: return null;
156: }
157: StatefulBuffer bytes = null;
158: bytes = stream().readWriterByAddress(i_trans, id, length);
159: if (bytes != null) {
160: bytes.setID(id);
161: }
162: if (bytes != null) {
163: bytes.setUpdateDepth(getUpdateDepth());
164: bytes.setInstantiationDepth(getInstantiationDepth());
165: }
166: return bytes;
167: }
168:
169: public final StatefulBuffer readYapBytes() {
170: int length = readInt();
171: if (length == 0) {
172: return null;
173: }
174: StatefulBuffer yb = new StatefulBuffer(i_trans, length);
175: System.arraycopy(_buffer, _offset, yb._buffer, 0, length);
176: _offset += length;
177: return yb;
178: }
179:
180: public void removeFirstBytes(int aLength) {
181: i_length -= aLength;
182: byte[] temp = new byte[i_length];
183: System.arraycopy(_buffer, aLength, temp, 0, i_length);
184: _buffer = temp;
185: _offset -= aLength;
186: if (_offset < 0) {
187: _offset = 0;
188: }
189: }
190:
191: public void address(int a_address) {
192: i_address = a_address;
193: }
194:
195: public void setCascadeDeletes(int depth) {
196: i_cascadeDelete = depth;
197: }
198:
199: public void setID(int a_id) {
200: i_id = a_id;
201: }
202:
203: public void setInstantiationDepth(int a_depth) {
204: i_instantionDepth = a_depth;
205: }
206:
207: public void setTransaction(Transaction aTrans) {
208: i_trans = aTrans;
209: }
210:
211: public void setUpdateDepth(int a_depth) {
212: i_updateDepth = a_depth;
213: }
214:
215: public void slotDelete() {
216: i_trans.slotDelete(i_id, slot());
217: }
218:
219: public void trim4(int a_offset, int a_length) {
220: byte[] temp = new byte[a_length];
221: System.arraycopy(_buffer, a_offset, temp, 0, a_length);
222: _buffer = temp;
223: i_length = a_length;
224: }
225:
226: public void useSlot(int a_adress) {
227: i_address = a_adress;
228: _offset = 0;
229: }
230:
231: // FIXME: FB remove
232: public void useSlot(int address, int length) {
233: useSlot(new Slot(address, length));
234: }
235:
236: public void useSlot(Slot slot) {
237: i_address = slot.address();
238: _offset = 0;
239: if (slot.length() > _buffer.length) {
240: _buffer = new byte[slot.length()];
241: }
242: i_length = slot.length();
243: }
244:
245: // FIXME: FB remove
246: public void useSlot(int a_id, int a_adress, int a_length) {
247: i_id = a_id;
248: useSlot(a_adress, a_length);
249: }
250:
251: public void write() {
252: if (Debug.xbytes) {
253: debugCheckBytes();
254: }
255: file().writeBytes(this , i_address, _addressOffset);
256: }
257:
258: public void writeEmbeddedNull() {
259: writeInt(0);
260: writeInt(0);
261: }
262:
263: public void writeEncrypt() {
264: if (Deploy.debug) {
265: debugCheckBytes();
266: }
267: file().writeEncrypt(this , i_address, _addressOffset);
268: }
269:
270: /* Only used for Strings, topLevel therefore means aligning blocksize, so
271: * index will be possible.
272: */
273: public void writePayload(StatefulBuffer payLoad, boolean topLevel) {
274: checkMinimumPayLoadOffsetAndWritePointerAndLength(payLoad
275: .length(), topLevel);
276: System.arraycopy(payLoad._buffer, 0, _buffer, _payloadOffset,
277: payLoad._buffer.length);
278: transferPayLoadAddress(payLoad, _payloadOffset);
279: _payloadOffset += payLoad._buffer.length;
280: }
281:
282: private void checkMinimumPayLoadOffsetAndWritePointerAndLength(
283: int length, boolean alignToBlockSize) {
284: if (_payloadOffset <= _offset + (Const4.INT_LENGTH * 2)) {
285: _payloadOffset = _offset + (Const4.INT_LENGTH * 2);
286: }
287: if (alignToBlockSize) {
288: _payloadOffset = stream().blockAlignedBytes(_payloadOffset);
289: }
290: writeInt(_payloadOffset);
291:
292: // TODO: This length is here for historical reasons.
293: // It's actually never really needed during reading.
294: // It's only necessary because array and string used
295: // to consist of a double pointer in marshaller family 0
296: // and it was not considered a good idea to change
297: // their linkLength() values for compatibility reasons
298: // with marshaller family 0.
299: writeInt(length);
300: }
301:
302: public int reserveAndPointToPayLoadSlot(int length) {
303: checkMinimumPayLoadOffsetAndWritePointerAndLength(length, false);
304: int linkOffset = _offset;
305: _offset = _payloadOffset;
306: _payloadOffset += length;
307: return linkOffset;
308: }
309:
310: public Buffer readPayloadWriter(int offset, int length) {
311: StatefulBuffer payLoad = new StatefulBuffer(i_trans, 0, length);
312: System.arraycopy(_buffer, offset, payLoad._buffer, 0, length);
313: transferPayLoadAddress(payLoad, offset);
314: return payLoad;
315: }
316:
317: private void transferPayLoadAddress(StatefulBuffer toWriter,
318: int offset) {
319: int blockedOffset = offset / stream().blockSize();
320: toWriter.i_address = i_address + blockedOffset;
321: toWriter.i_id = toWriter.i_address;
322: toWriter._addressOffset = _addressOffset;
323: }
324:
325: void writeShortString(String a_string) {
326: writeShortString(i_trans, a_string);
327: }
328:
329: public void moveForward(int length) {
330: _addressOffset += length;
331: }
332:
333: public void writeForward() {
334: write();
335: _addressOffset += i_length;
336: _offset = 0;
337: }
338:
339: public String toString() {
340: if (!Debug4.prettyToStrings) {
341: return super .toString();
342: }
343: return "id " + i_id + " adr " + i_address + " len " + i_length;
344: }
345:
346: public void noXByteCheck() {
347: if (Debug.xbytes && Deploy.overwrite) {
348: setID(Const4.IGNORE_ID);
349: }
350: }
351:
352: public void writeIDs(IntIterator4 idIterator, int maxCount) {
353: int savedOffset = _offset;
354: writeInt(0);
355: int actualCount = 0;
356: while (idIterator.moveNext()) {
357: writeInt(idIterator.currentInt());
358: actualCount++;
359: if (actualCount >= maxCount) {
360: break;
361: }
362: }
363: int secondSavedOffset = _offset;
364: _offset = savedOffset;
365: writeInt(actualCount);
366: _offset = secondSavedOffset;
367: }
368:
369: public Slot slot() {
370: return new Slot(i_address, i_length);
371: }
372:
373: public Pointer4 pointer() {
374: return new Pointer4(i_id, slot());
375: }
376:
377: }
|