001: /*
002: Copyright (C) 2007 Mobixess Inc. http://www.java-objects-database.com
003:
004: This file is part of the JODB (Java Objects Database) open source project.
005:
006: JODB is free software; you can redistribute it and/or modify it under
007: the terms of version 2 of the GNU General Public License as published
008: by the Free Software Foundation.
009:
010: JODB is distributed in the hope that it will be useful, but WITHOUT ANY
011: WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
013: for more details.
014:
015: You should have received a copy of the GNU General Public License along
016: with this program; if not, write to the Free Software Foundation, Inc.,
017: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: */
019: package com.mobixess.jodb.core.index;
020:
021: import java.io.IOException;
022: import java.lang.reflect.Field;
023: import java.nio.ByteBuffer;
024: import java.util.Arrays;
025: import java.util.Vector;
026:
027: import com.mobixess.jodb.core.IllegalClassTypeException;
028: import com.mobixess.jodb.core.JodbIOException;
029: import com.mobixess.jodb.core.agent.JODBAgent;
030: import com.mobixess.jodb.core.io.IOBase;
031: import com.mobixess.jodb.core.io.JODBOperationContext;
032: import com.mobixess.jodb.core.io.ObjectDataContainer;
033: import com.mobixess.jodb.core.io.ObjectDataContainer.FIELD_CATEGORIES;
034: import com.mobixess.jodb.core.io.ObjectDataContainer.FieldRecord;
035: import com.mobixess.jodb.core.io.ObjectDataContainer.FieldsIterator;
036: import com.mobixess.jodb.core.transaction.TransactionContainer;
037: import com.mobixess.jodb.core.transaction.TransactionUtils;
038: import com.mobixess.jodb.core.transaction.TransactionUtils.DataContainersCache;
039: import com.mobixess.jodb.util.PrimitiveJavaTypesUtil;
040:
041: public class JODBIndexingRootAgent extends JODBAgent {
042:
043: private final static int DEFAULT_CAPACITY = 30;
044: private final static int DEFAULT_INCREMENT = 30;
045:
046: private JODBIndexingAgent[] _agents;
047:
048: private short _totalAgents;
049: private int _capacityIncrement;
050:
051: public JODBIndexingRootAgent() {
052: this (DEFAULT_CAPACITY, DEFAULT_INCREMENT);
053: }
054:
055: public JODBIndexingRootAgent(int initialCapacity,
056: int capacityIncrement) {
057: _agents = new JODBIndexingAgent[initialCapacity];
058: _capacityIncrement = capacityIncrement;
059: }
060:
061: public synchronized JODBIndexingAgent enableIndex(Field field,
062: JODBOperationContext context) throws IOException {
063: TransactionContainer transactionContainer = context
064: .getTransactionContainer();
065: transactionContainer.enableAgentMode();
066: try {
067: JODBIndexingAgent agent = addAgent(field, context);
068: IOBase base = context.getBase();
069: int classId = base.getOrSetClassTypeSubstitutionID(field
070: .getDeclaringClass());
071: int fieldId = base.getOrSetFieldSubstitutionID(field);
072: long[] allOffsets = base.getForAllObjects(context
073: .getIoTicket());
074: DataContainersCache dataContainersCache = TransactionUtils
075: .getObjectDataContainerCache();
076: ObjectDataContainer dataContainer = dataContainersCache
077: .pullObjectDataContainer();
078: try {
079: for (int i = 0; i < allOffsets.length; i++) {
080: processIndexForObjectId(allOffsets[i], classId,
081: fieldId, field.getType(), dataContainer,
082: agent, context);
083: dataContainer.reset();
084: }
085: try {
086: transactionContainer.set(agent, Integer.MAX_VALUE);
087: } catch (IllegalClassTypeException e) {
088: e.printStackTrace();
089: }
090: } finally {
091: dataContainersCache
092: .pushObjectDataContainer(dataContainer);
093: }
094:
095: return agent;
096: } finally {
097: transactionContainer.disableAgentMode();
098: }
099: }
100:
101: private void processIndexForObjectId(long objectOffset,
102: int classId, int fieldId, Class fieldType,
103: ObjectDataContainer dataContainer, JODBIndexingAgent agent,
104: JODBOperationContext context) throws IOException {
105: FieldsIterator fieldsIterator = dataContainer.readObject(
106: context, objectOffset, true);
107: if (fieldsIterator != null) {
108: if (dataContainer.getOriginalClassType() != classId) {
109: return;
110: }
111: if (dataContainer.getOriginalClassType() != dataContainer
112: .getTranslatedClassType()) {
113: throw new IllegalArgumentException(
114: "No indexing for translated classes");
115: }
116: FieldRecord fieldRecord = dataContainer.getRecordCache();
117: IOBase base = context.getBase();
118: while (fieldsIterator.hasNext()) {
119: fieldsIterator.next(fieldRecord, base, false);
120: if (fieldRecord._category != FIELD_CATEGORIES.PRIMITIVE) {//TODO optimize to skip none primitive fields
121: continue;
122: }
123: if (fieldRecord._fieldID == fieldId) {
124: agent.insertIndex(objectOffset,
125: fieldRecord._primitiveRawDataBuffer,
126: context);
127: return;
128: }
129: }
130: //add field as having default value
131: ByteBuffer defaultValue = PrimitiveJavaTypesUtil
132: .getDefaultValueAsByteBuffer(fieldType);
133: agent.insertIndex(objectOffset, defaultValue, context);
134: }
135: }
136:
137: public synchronized void getAgentsForClassId(
138: Vector<IndexingRecord> agentsBuffer, int classTypeId) {
139: for (int i = 0; i < _totalAgents; i++) {
140: if (_agents[i].getClassId() == classTypeId) {
141: IndexingRecord indexingRecord = TransactionUtils
142: .getObjectDataContainerCache()
143: .pullIndexRecord();
144: indexingRecord.setIndexingAgent(_agents[i]);
145: agentsBuffer.add(indexingRecord);
146: }
147: }
148: }
149:
150: private synchronized JODBIndexingAgent addAgent(Field field,
151: JODBOperationContext context) throws IOException {
152: TransactionContainer transactionContainer = context
153: .getTransactionContainer();
154: transactionContainer.enableAgentMode();
155: try {
156: int fieldId = context.getBase()
157: .getOrSetFieldSubstitutionID(field);
158: for (int i = 0; i < _totalAgents; i++) {
159: if (_agents[i].getFieldId() == fieldId) {
160: return _agents[i];
161: }
162: }
163: _totalAgents++;
164: _agents = ensurePersistentArrayCapacity(_agents,
165: _totalAgents, transactionContainer,
166: _capacityIncrement);
167: _agents[_totalAgents - 1] = new JODBIndexingAgent(field,
168: context);
169: try {
170: transactionContainer.set(this , Integer.MAX_VALUE);
171: } catch (IllegalClassTypeException e) {
172: // TODO log
173: e.printStackTrace();
174: }
175: return _agents[_totalAgents - 1];
176: } finally {
177: transactionContainer.disableAgentMode();
178: }
179: }
180:
181: public JODBIndexingAgent getIndexingAgent(Field field, IOBase base) {
182: int fieldId = base.getFieldSubstitutionID(field);
183: return getIndexingAgent(fieldId, base);
184: }
185:
186: public JODBIndexingAgent getIndexingAgent(int fieldId, IOBase base) {
187: for (int i = 0; i < _totalAgents; i++) {
188: if (_agents[i].getFieldId() == fieldId) {
189: return _agents[i];
190: }
191: }
192: return null;
193: }
194:
195: public synchronized void removeAgent(Field field,
196: JODBOperationContext context) {
197: int fieldId = context.getBase().getOrSetFieldSubstitutionID(
198: field);
199: for (int i = 0; i < _totalAgents; i++) {
200: if (_agents[i].getFieldId() == fieldId) {
201: TransactionContainer transactionContainer = context
202: .getTransactionContainer();
203: try {
204: transactionContainer.delete(_agents[i],
205: Integer.MAX_VALUE);
206: } catch (IllegalClassTypeException e) {
207: // TODO log
208: e.printStackTrace();
209: }
210: if (i < _totalAgents - 1) {
211: System.arraycopy(_agents, i + 1, _agents, i,
212: _totalAgents - i);
213: _agents[_totalAgents - 1] = null;
214: }
215: _totalAgents--;
216: try {
217: transactionContainer.enableAgentMode();
218: transactionContainer.set(_agents, 1);
219: } catch (IllegalClassTypeException e) {
220: // TODO log
221: e.printStackTrace();
222: } finally {
223: transactionContainer.disableAgentMode();
224: }
225: break;
226: }
227: }
228: }
229:
230: public static <T> T[] ensurePersistentArrayCapacity(
231: T[] initialArray, int size, TransactionContainer container,
232: int capacityIncrement) {
233: if (size >= initialArray.length) {
234: @SuppressWarnings("unchecked")
235: T[] newAgentsArray = (T[]) java.lang.reflect.Array
236: .newInstance(initialArray.getClass()
237: .getComponentType(), size
238: + capacityIncrement);
239: System.arraycopy(initialArray, 0, newAgentsArray, 0,
240: initialArray.length);
241: Arrays.fill(initialArray, null);
242: try {
243: container.delete(initialArray, 1);
244: } catch (IllegalClassTypeException e) {
245: //TODO log
246: e.printStackTrace();
247: }
248: initialArray = newAgentsArray;
249: }
250: return initialArray;
251: }
252: }
|