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.ix.IxTree;
027: import com.db4o.internal.slots.Slot;
028:
029: public class FreespaceManagerIx extends AbstractFreespaceManager {
030:
031: private int _slotAddress;
032:
033: private FreespaceIxAddress _addressIx;
034: private FreespaceIxLength _lengthIx;
035:
036: private boolean _started;
037:
038: private Collection4 _xBytes;
039:
040: private final boolean _overwriteDeletedSlots;
041:
042: public FreespaceManagerIx(LocalObjectContainer file) {
043: super (file);
044: _overwriteDeletedSlots = Debug.xbytes
045: || file.config().freespaceFiller() != null;
046: }
047:
048: private void add(int address, int length) {
049: _addressIx.add(address, length);
050: _lengthIx.add(address, length);
051: }
052:
053: public Slot allocateTransactionLogSlot(int length) {
054: return getSlot(length);
055: }
056:
057: public void freeTransactionLogSlot(Slot slot) {
058: free(slot);
059: }
060:
061: public void beginCommit() {
062: if (!started()) {
063: return;
064: }
065: slotEntryToZeroes(_file, _slotAddress);
066: }
067:
068: public void endCommit() {
069: if (!started()) {
070: return;
071: }
072: if (_overwriteDeletedSlots) {
073: _xBytes = new Collection4();
074: }
075:
076: _addressIx._index.commitFreeSpace(_lengthIx._index);
077:
078: StatefulBuffer writer = new StatefulBuffer(_file
079: .systemTransaction(), _slotAddress, slotLength());
080: _addressIx._index._metaIndex.write(writer);
081: _lengthIx._index._metaIndex.write(writer);
082: if (_overwriteDeletedSlots) {
083: writer.setID(Const4.IGNORE_ID); // no XBytes check
084: }
085: if (_file.configImpl().flushFileBuffers()) {
086: _file.syncFiles();
087: }
088: writer.writeEncrypt();
089:
090: if (_overwriteDeletedSlots) {
091: Iterator4 i = _xBytes.iterator();
092: _xBytes = null;
093: while (i.moveNext()) {
094: Slot slot = (Slot) i.current();
095: overwriteDeletedSlot(slot);
096: }
097: }
098: }
099:
100: public int slotCount() {
101: return _addressIx.entryCount();
102: }
103:
104: public void free(Slot slot) {
105:
106: int address = slot.address();
107: int length = slot.length();
108:
109: if (!started()) {
110: return;
111: }
112:
113: if (address <= 0) {
114: return;
115: }
116:
117: if (canDiscard(length)) {
118: return;
119: }
120:
121: if (DTrace.enabled) {
122: DTrace.FREE.logLength(address, length);
123: }
124:
125: int freedAddress = address;
126: int freedLength = length;
127:
128: _addressIx.find(address);
129:
130: if (_addressIx.preceding()) {
131: if (_addressIx.address() + _addressIx.length() == address) {
132: remove(_addressIx.address(), _addressIx.length());
133: address = _addressIx.address();
134: length += _addressIx.length();
135: _addressIx.find(freedAddress);
136: }
137: }
138:
139: if (_addressIx.subsequent()) {
140: if (freedAddress + freedLength == _addressIx.address()) {
141: remove(_addressIx.address(), _addressIx.length());
142: length += _addressIx.length();
143: }
144: }
145:
146: add(address, length);
147:
148: if (_overwriteDeletedSlots) {
149: overwriteDeletedSlot(new Slot(freedAddress, freedLength));
150: }
151: }
152:
153: public void freeSelf() {
154: if (!started()) {
155: return;
156: }
157: _addressIx._index._metaIndex.free(_file);
158: _lengthIx._index._metaIndex.free(_file);
159: }
160:
161: public Slot getSlot(int length) {
162:
163: if (!started()) {
164: return null;
165: }
166:
167: int address = 0;
168:
169: _lengthIx.find(length);
170:
171: if (_lengthIx.match()) {
172: remove(_lengthIx.address(), _lengthIx.length());
173: address = _lengthIx.address();
174: } else if (_lengthIx.subsequent()) {
175: int lengthRemainder = _lengthIx.length() - length;
176: int addressRemainder = _lengthIx.address() + length;
177: remove(_lengthIx.address(), _lengthIx.length());
178: add(addressRemainder, lengthRemainder);
179: address = _lengthIx.address();
180: }
181:
182: if (address == 0) {
183: return null;
184: }
185:
186: if (DTrace.enabled) {
187: DTrace.GET_FREESPACE.logLength(address, length);
188: }
189: return new Slot(address, length);
190: }
191:
192: public void migrateTo(FreespaceManager fm) {
193: if (!started()) {
194: return;
195: }
196: super .migrateTo(fm);
197: }
198:
199: public void traverse(final Visitor4 visitor) {
200: if (!started()) {
201: return;
202: }
203: final IntObjectVisitor dispatcher = new IntObjectVisitor() {
204: public void visit(int length, Object address) {
205: visitor.visit(new Slot(((Integer) address).intValue(),
206: length));
207: }
208: };
209: Tree.traverse(_addressIx._indexTrans.getRoot(), new Visitor4() {
210: public void visit(Object a_object) {
211: IxTree ixTree = (IxTree) a_object;
212: ixTree.visitAll(dispatcher);
213: }
214: });
215: }
216:
217: public int onNew(LocalObjectContainer file) {
218: return file.ensureFreespaceSlot();
219: }
220:
221: public void read(int freespaceID) {
222: // this is done in start(), nothing to do here
223: }
224:
225: private void remove(int address, int length) {
226: _addressIx.remove(address, length);
227: _lengthIx.remove(address, length);
228: }
229:
230: public void start(int slotAddress) {
231:
232: if (started()) {
233: return;
234: }
235:
236: _slotAddress = slotAddress;
237:
238: MetaIndex miAddress = new MetaIndex();
239: MetaIndex miLength = new MetaIndex();
240:
241: Buffer reader = new Buffer(slotLength());
242: reader.read(_file, slotAddress, 0);
243: miAddress.read(reader);
244: miLength.read(reader);
245:
246: _addressIx = new FreespaceIxAddress(_file, miAddress);
247: _lengthIx = new FreespaceIxLength(_file, miLength);
248:
249: _started = true;
250: }
251:
252: private boolean started() {
253: return _started;
254: }
255:
256: public byte systemType() {
257: return FM_IX;
258: }
259:
260: public int write() {
261: return 0; // no special ID, FreespaceIX information is stored in fileheader variable part
262: }
263:
264: private void overwriteDeletedSlot(Slot slot) {
265: if (_overwriteDeletedSlots) {
266: if (_xBytes == null) {
267: _file.overwriteDeletedBlockedSlot(slot);
268: } else {
269: _xBytes.add(slot);
270: }
271: }
272: }
273:
274: public String toString() {
275: String str = "FreespaceManagerIx\n" + _lengthIx.toString();
276: return str;
277: }
278:
279: public void commit() {
280: // do nothing
281: }
282:
283: }
|