001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb.persist;
032:
033: import org.hsqldb.lib.DoubleIntIndex;
034:
035: /**
036: * Maintains a list of free file blocks with fixed capacity.<p>
037: *
038: * @author fredt@users
039: * @version 1.8.0
040: * @since 1.8.0
041: */
042: public class DataFileBlockManager {
043:
044: private DoubleIntIndex lookup;
045: private final int capacity;
046: private int midSize;
047: private final int scale;
048: private long releaseCount;
049: private long requestCount;
050: private long requestSize;
051:
052: // reporting vars
053: long lostFreeBlockSize;
054: boolean isModified;
055:
056: /**
057: *
058: */
059: public DataFileBlockManager(int capacity, int scale, long lostSize) {
060:
061: lookup = new DoubleIntIndex(capacity, true);
062:
063: lookup.setValuesSearchTarget();
064:
065: this .capacity = capacity;
066: this .scale = scale;
067: this .lostFreeBlockSize = lostSize;
068: this .midSize = 128; // arbitrary initial value
069: }
070:
071: /**
072: */
073: void add(int pos, int rowSize) {
074:
075: isModified = true;
076:
077: if (capacity == 0) {
078: lostFreeBlockSize += rowSize;
079:
080: return;
081: }
082:
083: releaseCount++;
084:
085: //
086: if (lookup.size() == capacity) {
087: resetList();
088: }
089:
090: lookup.add(pos, rowSize);
091: }
092:
093: /**
094: * Returns the position of a free block or 0.
095: */
096: int get(int rowSize) {
097:
098: if (lookup.size() == 0) {
099: return -1;
100: }
101:
102: int index = lookup.findFirstGreaterEqualKeyIndex(rowSize);
103:
104: if (index == -1) {
105: return -1;
106: }
107:
108: // statistics for successful requests only - to be used later for midSize
109: requestCount++;
110:
111: requestSize += rowSize;
112:
113: int length = lookup.getValue(index);
114: int difference = length - rowSize;
115: int key = lookup.getKey(index);
116:
117: lookup.remove(index);
118:
119: if (difference >= midSize) {
120: int pos = key + (rowSize / scale);
121:
122: lookup.add(pos, difference);
123: } else {
124: lostFreeBlockSize += difference;
125: }
126:
127: return key;
128: }
129:
130: int size() {
131: return lookup.size();
132: }
133:
134: long getLostBlocksSize() {
135: return lostFreeBlockSize;
136: }
137:
138: boolean isModified() {
139: return isModified;
140: }
141:
142: void clear() {
143: removeBlocks(lookup.size());
144: }
145:
146: private void resetList() {
147:
148: if (requestCount != 0) {
149: midSize = (int) (requestSize / requestCount);
150: }
151:
152: int first = lookup.findFirstGreaterEqualSlotIndex(midSize);
153:
154: if (first < lookup.size() / 4) {
155: first = lookup.size() / 4;
156: }
157:
158: removeBlocks(first);
159: }
160:
161: private void removeBlocks(int blocks) {
162:
163: for (int i = 0; i < blocks; i++) {
164: lostFreeBlockSize += lookup.getValue(i);
165: }
166:
167: lookup.removeRange(0, blocks);
168: }
169:
170: private void checkIntegrity() throws NullPointerException {
171: }
172: }
|