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.*;
024: import com.db4o.foundation.*;
025: import com.db4o.internal.*;
026: import com.db4o.internal.slots.*;
027:
028: public class RamFreespaceManager extends AbstractFreespaceManager {
029:
030: private final TreeIntObject _finder = new TreeIntObject(0);
031:
032: private Tree _freeByAddress;
033:
034: private Tree _freeBySize;
035:
036: public RamFreespaceManager(LocalObjectContainer file) {
037: super (file);
038: }
039:
040: private void addFreeSlotNodes(int address, int length) {
041: FreeSlotNode addressNode = new FreeSlotNode(address);
042: addressNode.createPeer(length);
043: _freeByAddress = Tree.add(_freeByAddress, addressNode);
044: _freeBySize = Tree.add(_freeBySize, addressNode._peer);
045: }
046:
047: public Slot allocateTransactionLogSlot(int length) {
048: FreeSlotNode sizeNode = (FreeSlotNode) Tree.last(_freeBySize);
049: if (sizeNode == null || sizeNode._key < length) {
050: return null;
051: }
052:
053: // We can just be appending to the end of the file, using one
054: // really big contigous slot that keeps growing. Let's limit.
055: int limit = length + 100;
056: if (sizeNode._key > limit) {
057: return getSlot(limit);
058: }
059:
060: removeFromBothTrees(sizeNode);
061: return new Slot(sizeNode._peer._key, sizeNode._key);
062: }
063:
064: public void freeTransactionLogSlot(Slot slot) {
065: free(slot);
066: }
067:
068: public void beginCommit() {
069: // do nothing
070: }
071:
072: public void commit() {
073: // do nothing
074: }
075:
076: public void endCommit() {
077: // do nothing
078: }
079:
080: public void free(final Slot slot) {
081:
082: int address = slot.address();
083: int length = slot.length();
084:
085: if (address <= 0) {
086: throw new IllegalArgumentException();
087: }
088:
089: if (DTrace.enabled) {
090: DTrace.FREE_RAM.logLength(address, length);
091: }
092:
093: _finder._key = address;
094: FreeSlotNode sizeNode;
095: FreeSlotNode addressnode = (FreeSlotNode) Tree.findSmaller(
096: _freeByAddress, _finder);
097: if ((addressnode != null)
098: && ((addressnode._key + addressnode._peer._key) == address)) {
099: sizeNode = addressnode._peer;
100: _freeBySize = _freeBySize.removeNode(sizeNode);
101: sizeNode._key += length;
102: FreeSlotNode secondAddressNode = (FreeSlotNode) Tree
103: .findGreaterOrEqual(_freeByAddress, _finder);
104: if ((secondAddressNode != null)
105: && (address + length == secondAddressNode._key)) {
106: sizeNode._key += secondAddressNode._peer._key;
107: removeFromBothTrees(secondAddressNode._peer);
108: }
109: sizeNode.removeChildren();
110: _freeBySize = Tree.add(_freeBySize, sizeNode);
111: } else {
112: addressnode = (FreeSlotNode) Tree.findGreaterOrEqual(
113: _freeByAddress, _finder);
114: if ((addressnode != null)
115: && (address + length == addressnode._key)) {
116: sizeNode = addressnode._peer;
117: removeFromBothTrees(sizeNode);
118: sizeNode._key += length;
119: addressnode._key = address;
120: addressnode.removeChildren();
121: sizeNode.removeChildren();
122: _freeByAddress = Tree.add(_freeByAddress, addressnode);
123: _freeBySize = Tree.add(_freeBySize, sizeNode);
124: } else {
125: if (canDiscard(length)) {
126: return;
127: }
128: addFreeSlotNodes(address, length);
129: }
130: }
131: _file.overwriteDeletedBlockedSlot(slot);
132: }
133:
134: public void freeSelf() {
135: // Do nothing.
136: // The RAM manager frees itself on reading.
137: }
138:
139: private void freeReader(StatefulBuffer reader) {
140: if (!Debug.freespace) {
141: _file.free(reader.getAddress(), reader.length());
142: }
143: }
144:
145: public Slot getSlot(int length) {
146:
147: _finder._key = length;
148: _finder._object = null;
149: _freeBySize = FreeSlotNode.removeGreaterOrEqual(
150: (FreeSlotNode) _freeBySize, _finder);
151:
152: if (_finder._object == null) {
153: return null;
154: }
155:
156: FreeSlotNode node = (FreeSlotNode) _finder._object;
157: int blocksFound = node._key;
158: int address = node._peer._key;
159: _freeByAddress = _freeByAddress.removeNode(node._peer);
160: int remainingBlocks = blocksFound - length;
161: if (canDiscard(remainingBlocks)) {
162: length = blocksFound;
163: } else {
164: addFreeSlotNodes(address + length, remainingBlocks);
165: }
166:
167: if (DTrace.enabled) {
168: DTrace.GET_FREESPACE.logLength(address, length);
169: }
170:
171: return new Slot(address, length);
172: }
173:
174: int marshalledLength() {
175: return TreeInt.marshalledLength((TreeInt) _freeBySize);
176: }
177:
178: public int onNew(LocalObjectContainer file) {
179: // do nothing
180: return 0;
181: }
182:
183: public void read(int freeSlotsID) {
184: readById(freeSlotsID);
185: }
186:
187: private void read(StatefulBuffer reader) {
188: FreeSlotNode.sizeLimit = blockedDiscardLimit();
189: _freeBySize = new TreeReader(reader, new FreeSlotNode(0), true)
190: .read();
191: final Tree.ByRef addressTree = new Tree.ByRef();
192: if (_freeBySize != null) {
193: _freeBySize.traverse(new Visitor4() {
194: public void visit(Object a_object) {
195: FreeSlotNode node = ((FreeSlotNode) a_object)._peer;
196: addressTree.value = Tree.add(addressTree.value,
197: node);
198: }
199: });
200: }
201: _freeByAddress = addressTree.value;
202: }
203:
204: void read(Slot slot) {
205: if (slot.address() == 0) {
206: return;
207: }
208: StatefulBuffer reader = _file.readWriterByAddress(
209: transaction(), slot.address(), slot.length());
210: if (reader == null) {
211: return;
212: }
213: read(reader);
214: freeReader(reader);
215: }
216:
217: private void readById(int freeSlotsID) {
218: if (freeSlotsID <= 0) {
219: return;
220: }
221: if (discardLimit() == Integer.MAX_VALUE) {
222: return;
223: }
224: StatefulBuffer reader = _file.readWriterByID(transaction(),
225: freeSlotsID);
226: if (reader == null) {
227: return;
228: }
229:
230: read(reader);
231:
232: if (!Debug.freespace) {
233: _file.free(freeSlotsID, Const4.POINTER_LENGTH);
234: freeReader(reader);
235: }
236: }
237:
238: private void removeFromBothTrees(FreeSlotNode sizeNode) {
239: _freeBySize = _freeBySize.removeNode(sizeNode);
240: _freeByAddress = _freeByAddress.removeNode(sizeNode._peer);
241: }
242:
243: public int slotCount() {
244: return Tree.size(_freeByAddress);
245: }
246:
247: public void start(int slotAddress) {
248: // this is done in read(), nothing to do here
249: }
250:
251: public byte systemType() {
252: return FM_RAM;
253: }
254:
255: public String toString() {
256: final StringBuffer sb = new StringBuffer();
257: sb.append("RAM FreespaceManager\n");
258: sb.append("Address Index\n");
259: _freeByAddress.traverse(new Visitor4() {
260: public void visit(Object obj) {
261: sb.append(obj);
262: sb.append("\n");
263: }
264:
265: });
266: sb.append("Length Index\n");
267: _freeBySize.traverse(new Visitor4() {
268: public void visit(Object obj) {
269: sb.append(obj);
270: sb.append("\n");
271: }
272: });
273: return sb.toString();
274: }
275:
276: public void traverse(final Visitor4 visitor) {
277: if (_freeByAddress == null) {
278: return;
279: }
280: _freeByAddress.traverse(new Visitor4() {
281: public void visit(Object a_object) {
282: FreeSlotNode fsn = (FreeSlotNode) a_object;
283: int address = fsn._key;
284: int length = fsn._peer._key;
285: visitor.visit(new Slot(address, length));
286: }
287: });
288: }
289:
290: public int write() {
291: Pointer4 pointer = _file.newSlot(marshalledLength());
292: write(pointer);
293: return pointer._id;
294: }
295:
296: void write(Pointer4 pointer) {
297: StatefulBuffer buffer = new StatefulBuffer(transaction(),
298: pointer);
299: TreeInt.write(buffer, (TreeInt) _freeBySize);
300: buffer.writeEncrypt();
301: transaction().flushFile();
302: transaction().writePointer(pointer);
303: }
304:
305: }
|