001: // kelondroRAMIndex.java
002: // (C) 2008 by Michael Peter Christen; mc@yacy.net, Frankfurt a. M., Germany
003: // first published 07.01.2008 on http://yacy.net
004: //
005: // $LastChangedDate: 2006-04-02 22:40:07 +0200 (So, 02 Apr 2006) $
006: // $LastChangedRevision: 1986 $
007: // $LastChangedBy: orbiter $
008: //
009: // LICENSE
010: //
011: // This program is free software; you can redistribute it and/or modify
012: // it under the terms of the GNU General Public License as published by
013: // the Free Software Foundation; either version 2 of the License, or
014: // (at your option) any later version.
015: //
016: // This program is distributed in the hope that it will be useful,
017: // but WITHOUT ANY WARRANTY; without even the implied warranty of
018: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
019: // GNU General Public License for more details.
020: //
021: // You should have received a copy of the GNU General Public License
022: // along with this program; if not, write to the Free Software
023: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: package de.anomic.kelondro;
026:
027: import java.util.ArrayList;
028: import java.util.Date;
029: import java.util.Iterator;
030: import java.util.List;
031:
032: import de.anomic.kelondro.kelondroRow.Entry;
033:
034: public class kelondroRAMIndex implements kelondroIndex {
035:
036: private kelondroRow rowdef;
037: private kelondroRowSet index0, index1;
038: private kelondroRow.EntryComparator entryComparator;
039:
040: public kelondroRAMIndex(kelondroRow rowdef, int initialspace) {
041: this .rowdef = rowdef;
042: this .entryComparator = new kelondroRow.EntryComparator(
043: rowdef.objectOrder);
044: reset(initialspace);
045: }
046:
047: public void reset() {
048: reset(0);
049: }
050:
051: public void reset(int initialspace) {
052: this .index0 = null; // first flush RAM to make room
053: this .index0 = new kelondroRowSet(rowdef, initialspace);
054: this .index1 = null; // to show that this is the initialization phase
055: }
056:
057: public kelondroRow row() {
058: return index0.row();
059: }
060:
061: private final void finishInitialization() {
062: if (index1 == null) {
063: // finish initialization phase
064: index0.sort();
065: index0.uniq();
066: index1 = new kelondroRowSet(rowdef, 0);
067: }
068: }
069:
070: public synchronized kelondroRow.Entry get(byte[] key) {
071: assert (key != null);
072: finishInitialization();
073: kelondroRow.Entry indexentry = index0.get(key);
074: if (indexentry != null)
075: return indexentry;
076: return index1.get(key);
077: }
078:
079: public boolean has(byte[] key) {
080: assert (key != null);
081: finishInitialization();
082: if (index0.has(key))
083: return true;
084: return index1.has(key);
085: }
086:
087: public synchronized kelondroRow.Entry put(kelondroRow.Entry entry) {
088: assert (entry != null);
089: finishInitialization();
090: // if the new entry is within the initialization part, just overwrite it
091: kelondroRow.Entry indexentry = index0.get(entry
092: .getPrimaryKeyBytes());
093: if (indexentry != null) {
094: index0.put(entry);
095: return indexentry;
096: }
097: // else place it in the index1
098: return index1.put(entry);
099: }
100:
101: public Entry put(Entry row, Date entryDate) {
102: return put(row);
103: }
104:
105: public void putMultiple(List<Entry> rows) {
106: Iterator<Entry> i = rows.iterator();
107: while (i.hasNext()) {
108: put(i.next());
109: }
110: }
111:
112: public synchronized void addUnique(kelondroRow.Entry entry) {
113: assert (entry != null);
114: if (index1 == null) {
115: // we are in the initialization phase
116: index0.addUnique(entry);
117: } else {
118: // initialization is over, add to secondary index
119: index1.addUnique(entry);
120: }
121: }
122:
123: public void addUniqueMultiple(List<Entry> rows) {
124: Iterator<Entry> i = rows.iterator();
125: while (i.hasNext()) {
126: addUnique(i.next());
127: }
128: }
129:
130: public synchronized ArrayList<kelondroRowSet> removeDoubles() {
131: // finish initialization phase explicitely
132: if (index1 == null)
133: index1 = new kelondroRowSet(rowdef, 0);
134: return index0.removeDoubles();
135: }
136:
137: public synchronized kelondroRow.Entry remove(byte[] key,
138: boolean keepOrder) {
139: assert keepOrder == true; // if this is false, the index must be re-ordered so many times which will cause a major CPU usage
140: finishInitialization();
141: // if the new entry is within the initialization part, just delete it
142: kelondroRow.Entry indexentry = index0.remove(key, keepOrder);
143: if (indexentry != null) {
144: assert index0.remove(key, true) == null; // check if remove worked
145: return indexentry;
146: }
147: // else remove it from the index1
148: return index1.remove(key, keepOrder);
149: }
150:
151: public synchronized kelondroRow.Entry removeOne() {
152: if ((index1 != null) && (index1.size() != 0)) {
153: return index1.removeOne();
154: }
155: if ((index0 != null) && (index0.size() != 0)) {
156: return index0.removeOne();
157: }
158: return null;
159: }
160:
161: public synchronized int size() {
162: if ((index0 != null) && (index1 == null)) {
163: return index0.size();
164: }
165: if ((index0 == null) && (index1 != null)) {
166: return index1.size();
167: }
168: assert ((index0 != null) && (index1 != null));
169: return index0.size() + index1.size();
170: }
171:
172: public synchronized kelondroCloneableIterator<byte[]> keys(
173: boolean up, byte[] firstKey) {
174: // returns the key-iterator of the underlying kelondroIndex
175: if (index1 == null) {
176: // finish initialization phase
177: index0.sort();
178: index0.uniq();
179: index1 = new kelondroRowSet(rowdef, 0);
180: return index0.keys(up, firstKey);
181: }
182: assert (index1 != null);
183: if (index0 == null) {
184: //assert consistencyAnalysis0() : "consistency problem: " + consistencyAnalysis();
185: return index1.keys(up, firstKey);
186: }
187: // index0 should be sorted
188: // sort index1 to enable working of the merge iterator
189: index1.sort();
190: //assert consistencyAnalysis0() : "consistency problem: " + consistencyAnalysis();
191: return new kelondroMergeIterator<byte[]>(index0.keys(up,
192: firstKey), index1.keys(up, firstKey),
193: rowdef.objectOrder, kelondroMergeIterator.simpleMerge,
194: true);
195: }
196:
197: public synchronized kelondroCloneableIterator<kelondroRow.Entry> rows(
198: boolean up, byte[] firstKey) {
199: // returns the row-iterator of the underlying kelondroIndex
200: if (index1 == null) {
201: // finish initialization phase
202: index0.sort();
203: index0.uniq();
204: index1 = new kelondroRowSet(rowdef, 0);
205: return index0.rows(up, firstKey);
206: }
207: assert (index1 != null);
208: if (index0 == null) {
209: //assert consistencyAnalysis0() : "consistency problem: " + consistencyAnalysis();
210: return index1.rows(up, firstKey);
211: }
212: // index0 should be sorted
213: // sort index1 to enable working of the merge iterator
214: index1.sort();
215: //assert consistencyAnalysis0() : "consistency problem: " + consistencyAnalysis();
216: return new kelondroMergeIterator<kelondroRow.Entry>(index0
217: .rows(up, firstKey), index1.rows(up, firstKey),
218: entryComparator, kelondroMergeIterator.simpleMerge,
219: true);
220: }
221:
222: public kelondroProfile profile() {
223: if (index0 == null)
224: return index1.profile();
225: if (index1 == null)
226: return index0.profile();
227: return kelondroProfile.consolidate(index0.profile(), index1
228: .profile());
229: }
230:
231: public synchronized void close() {
232: if (index0 != null)
233: index0.close();
234: if (index1 != null)
235: index1.close();
236: }
237:
238: public String filename() {
239: return null; // this does not have a file name
240: }
241:
242: }
|