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.freespace;
022:
023: import com.db4o.DTrace;
024: import com.db4o.foundation.Visitor4;
025: import com.db4o.internal.*;
026: import com.db4o.internal.btree.*;
027: import com.db4o.internal.slots.*;
028:
029: /**
030: * @exclude
031: */
032: public class BTreeFreespaceManager extends AbstractFreespaceManager {
033:
034: private RamFreespaceManager _delegate;
035:
036: private FreespaceBTree _slotsByAddress;
037:
038: private FreespaceBTree _slotsByLength;
039:
040: private PersistentIntegerArray _idArray;
041:
042: private int _delegateIndirectionID;
043:
044: private int _delegationRequests;
045:
046: public BTreeFreespaceManager(LocalObjectContainer file) {
047: super (file);
048: _delegate = new RamFreespaceManager(file);
049: }
050:
051: private void addSlot(Slot slot) {
052: _slotsByLength.add(transaction(), slot);
053: _slotsByAddress.add(transaction(), slot);
054: }
055:
056: public Slot allocateTransactionLogSlot(int length) {
057: return _delegate.allocateTransactionLogSlot(length);
058: }
059:
060: public void beginCommit() {
061: // TODO: FB remove
062: }
063:
064: private void beginDelegation() {
065: _delegationRequests++;
066: }
067:
068: public void commit() {
069: beginDelegation();
070: _slotsByAddress.commit(transaction());
071: _slotsByLength.commit(transaction());
072: }
073:
074: private void createBTrees(int addressID, int lengthID) {
075: _slotsByAddress = new FreespaceBTree(transaction(), addressID,
076: new AddressKeySlotHandler());
077: _slotsByLength = new FreespaceBTree(transaction(), lengthID,
078: new LengthKeySlotHandler());
079: }
080:
081: public void endCommit() {
082: endDelegation();
083: }
084:
085: private void endDelegation() {
086: _delegationRequests--;
087: }
088:
089: public void free(Slot slot) {
090: if (!started()) {
091: return;
092: }
093: if (isDelegating()) {
094: _delegate.free(slot);
095: return;
096: }
097: try {
098: beginDelegation();
099: if (DTrace.enabled) {
100: DTrace.FREE.logLength(slot.address(), slot.length());
101: }
102: Slot remove[] = new Slot[2];
103: Slot newFreeSlot = slot;
104: BTreePointer pointer = searchBTree(_slotsByAddress, slot,
105: SearchTarget.LOWEST);
106: BTreePointer previousPointer = pointer != null ? pointer
107: .previous() : _slotsByAddress
108: .lastPointer(transaction());
109: if (previousPointer != null) {
110: Slot previousSlot = (Slot) previousPointer.key();
111: if (previousSlot.isDirectlyPreceding(newFreeSlot)) {
112: remove[0] = previousSlot;
113: newFreeSlot = previousSlot.append(newFreeSlot);
114: }
115: }
116: if (pointer != null) {
117: Slot nextSlot = (Slot) pointer.key();
118: if (newFreeSlot.isDirectlyPreceding(nextSlot)) {
119: remove[1] = nextSlot;
120: newFreeSlot = newFreeSlot.append(nextSlot);
121: }
122: }
123: for (int i = 0; i < remove.length; i++) {
124: if (remove[i] != null) {
125: removeSlot(remove[i]);
126: }
127: }
128: if (!canDiscard(newFreeSlot.length())) {
129: addSlot(newFreeSlot);
130: }
131: _file.overwriteDeletedBlockedSlot(slot);
132: } finally {
133: endDelegation();
134: }
135: }
136:
137: public void freeSelf() {
138: _slotsByAddress.free(transaction());
139: _slotsByLength.free(transaction());
140: }
141:
142: public void freeTransactionLogSlot(Slot slot) {
143: _delegate.freeTransactionLogSlot(slot);
144: }
145:
146: public Slot getSlot(int length) {
147: if (!started()) {
148: return null;
149: }
150: if (isDelegating()) {
151: return _delegate.getSlot(length);
152: }
153: try {
154: beginDelegation();
155: BTreePointer pointer = searchBTree(_slotsByLength,
156: new Slot(0, length), SearchTarget.HIGHEST);
157: if (pointer == null) {
158: return null;
159: }
160: Slot slot = (Slot) pointer.key();
161: removeSlot(slot);
162: int remainingLength = slot.length() - length;
163: if (!canDiscard(remainingLength)) {
164: addSlot(slot.subSlot(length));
165: slot = slot.truncate(length);
166: }
167: if (DTrace.enabled) {
168: DTrace.GET_FREESPACE.logLength(slot.address(), slot
169: .length());
170: }
171: return slot;
172: } finally {
173: endDelegation();
174: }
175: }
176:
177: private void initializeExisting(int slotAddress) {
178: _idArray = new PersistentIntegerArray(slotAddress);
179: _idArray.read(transaction());
180: int[] ids = _idArray.array();
181: int addressId = ids[0];
182: int lengthID = ids[1];
183: _delegateIndirectionID = ids[2];
184: createBTrees(addressId, lengthID);
185: _slotsByAddress.read(transaction());
186: _slotsByLength.read(transaction());
187: Pointer4 delegatePointer = transaction().readPointer(
188: _delegateIndirectionID);
189: transaction().writeZeroPointer(_delegateIndirectionID);
190: transaction().flushFile();
191: _delegate.read(delegatePointer._slot);
192: }
193:
194: private void initializeNew() {
195: createBTrees(0, 0);
196: _slotsByAddress.write(transaction());
197: _slotsByLength.write(transaction());
198: _delegateIndirectionID = _file.getPointerSlot();
199: int[] ids = new int[] { _slotsByAddress.getID(),
200: _slotsByLength.getID(), _delegateIndirectionID };
201: _idArray = new PersistentIntegerArray(ids);
202: _idArray.write(transaction());
203: _file.systemData().freespaceAddress(_idArray.getID());
204: }
205:
206: private boolean isDelegating() {
207: return _delegationRequests > 0;
208: }
209:
210: public int onNew(LocalObjectContainer file) {
211: return 0;
212: }
213:
214: public void read(int freeSpaceID) {
215: // do nothing
216: }
217:
218: private void removeSlot(Slot slot) {
219: _slotsByLength.remove(transaction(), slot);
220: _slotsByAddress.remove(transaction(), slot);
221: }
222:
223: private BTreePointer searchBTree(BTree bTree, Slot slot,
224: SearchTarget target) {
225: BTreeNodeSearchResult searchResult = bTree.searchLeaf(
226: transaction(), slot, target);
227: return searchResult.firstValidPointer();
228: }
229:
230: public int slotCount() {
231: return _slotsByAddress.size(transaction())
232: + _delegate.slotCount();
233: }
234:
235: public void start(int slotAddress) {
236: try {
237: beginDelegation();
238: if (slotAddress == 0) {
239: initializeNew();
240: } else {
241: initializeExisting(slotAddress);
242: }
243: } finally {
244: endDelegation();
245: }
246: }
247:
248: private boolean started() {
249: return _idArray != null;
250: }
251:
252: public byte systemType() {
253: return FM_BTREE;
254: }
255:
256: public String toString() {
257: return _slotsByLength.toString();
258: }
259:
260: public int totalFreespace() {
261: return super .totalFreespace() + _delegate.totalFreespace();
262: }
263:
264: public void traverse(final Visitor4 visitor) {
265: _slotsByAddress.traverseKeys(transaction(), visitor);
266: }
267:
268: public int write() {
269: try {
270: beginDelegation();
271: Slot slot = _file.getSlot(_delegate.marshalledLength());
272: Pointer4 pointer = new Pointer4(_delegateIndirectionID,
273: slot);
274: _delegate.write(pointer);
275: return _idArray.getID();
276: } finally {
277: endDelegation();
278: }
279: }
280:
281: }
|