PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/trunk/core/src/main/java/com/orientechnologies/orient/core/index/OIndexOneValue.java

http://orient.googlecode.com/
Java | 486 lines | 346 code | 116 blank | 24 comment | 92 complexity | ae9812a916a97917d7795e8b3b48f26a MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0
  1. /*
  2. * Copyright 2010-2012 Luca Garulli (l.garulli--at--orientechnologies.com)
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.orientechnologies.orient.core.index;
  17. import java.util.ArrayList;
  18. import java.util.Collection;
  19. import java.util.Collections;
  20. import java.util.HashSet;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.Map.Entry;
  24. import java.util.Set;
  25. import com.orientechnologies.common.collection.OMVRBTree;
  26. import com.orientechnologies.common.collection.OMVRBTreeEntry;
  27. import com.orientechnologies.common.comparator.ODefaultComparator;
  28. import com.orientechnologies.common.listener.OProgressListener;
  29. import com.orientechnologies.common.log.OLogManager;
  30. import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
  31. import com.orientechnologies.orient.core.db.record.ODatabaseRecord;
  32. import com.orientechnologies.orient.core.db.record.OIdentifiable;
  33. import com.orientechnologies.orient.core.record.impl.ODocument;
  34. import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerRID;
  35. import com.orientechnologies.orient.core.tx.OTransactionIndexChanges;
  36. import com.orientechnologies.orient.core.tx.OTransactionIndexChanges.OPERATION;
  37. import com.orientechnologies.orient.core.tx.OTransactionIndexChangesPerKey;
  38. import com.orientechnologies.orient.core.tx.OTransactionIndexChangesPerKey.OTransactionIndexEntry;
  39. /**
  40. * Abstract Index implementation that allows only one value for a key.
  41. *
  42. * @author Luca Garulli
  43. *
  44. */
  45. public abstract class OIndexOneValue extends OIndexMVRBTreeAbstract<OIdentifiable> {
  46. public OIndexOneValue(final String iType) {
  47. super(iType);
  48. }
  49. public OIdentifiable get(final Object iKey) {
  50. acquireExclusiveLock();
  51. try {
  52. return map.get(iKey);
  53. } finally {
  54. releaseExclusiveLock();
  55. }
  56. }
  57. public long count(final Object iKey) {
  58. acquireExclusiveLock();
  59. try {
  60. return map.containsKey(iKey) ? 1 : 0;
  61. } finally {
  62. releaseExclusiveLock();
  63. }
  64. }
  65. public int remove(final OIdentifiable iRecord) {
  66. modificationLock.requestModificationLock();
  67. try {
  68. acquireExclusiveLock();
  69. try {
  70. int tot = 0;
  71. for (final Entry<Object, OIdentifiable> entries : map.entrySet()) {
  72. if (entries.getValue().equals(iRecord)) {
  73. remove(entries.getKey(), iRecord);
  74. ++tot;
  75. }
  76. }
  77. return tot;
  78. } finally {
  79. releaseExclusiveLock();
  80. }
  81. } finally {
  82. modificationLock.releaseModificationLock();
  83. }
  84. }
  85. public int count(final OIdentifiable iRecord) {
  86. acquireExclusiveLock();
  87. try {
  88. int tot = 0;
  89. for (final Entry<Object, OIdentifiable> entries : map.entrySet()) {
  90. if (entries.getValue().equals((iRecord)))
  91. ++tot;
  92. }
  93. return tot;
  94. } finally {
  95. releaseExclusiveLock();
  96. }
  97. }
  98. @Override
  99. public void checkEntry(final OIdentifiable iRecord, final Object iKey) {
  100. // CHECK IF ALREADY EXIST
  101. final OIdentifiable indexedRID = get(iKey);
  102. if (indexedRID != null && !indexedRID.getIdentity().equals(iRecord.getIdentity())) {
  103. // CHECK IF IN THE SAME TX THE ENTRY WAS DELETED
  104. final OTransactionIndexChanges indexChanges = ODatabaseRecordThreadLocal.INSTANCE.get().getTransaction()
  105. .getIndexChanges(getName());
  106. if (indexChanges != null) {
  107. final OTransactionIndexChangesPerKey keyChanges = indexChanges.getChangesPerKey(iKey);
  108. if (keyChanges != null) {
  109. for (OTransactionIndexEntry entry : keyChanges.entries) {
  110. if (entry.operation == OPERATION.REMOVE)
  111. // WAS DELETED, OK!
  112. return;
  113. }
  114. }
  115. }
  116. OLogManager.instance().exception("Found duplicated key '%s' previously assigned to the record %s", null,
  117. OIndexException.class, iKey, indexedRID);
  118. }
  119. }
  120. public OIndexOneValue create(final String iName, final OIndexDefinition iIndexDefinition, final ODatabaseRecord iDatabase,
  121. final String iClusterIndexName, final int[] iClusterIdsToIndex, final OProgressListener iProgressListener) {
  122. return (OIndexOneValue) super.create(iName, iIndexDefinition, iDatabase, iClusterIndexName, iClusterIdsToIndex,
  123. iProgressListener, OStreamSerializerRID.INSTANCE);
  124. }
  125. public Collection<OIdentifiable> getValuesBetween(final Object iRangeFrom, final boolean iFromInclusive, final Object iRangeTo,
  126. final boolean iToInclusive, final int maxValuesToFetch) {
  127. if (iRangeFrom.getClass() != iRangeTo.getClass())
  128. throw new IllegalArgumentException("Range from-to parameters are of different types");
  129. acquireExclusiveLock();
  130. try {
  131. final OMVRBTreeEntry<Object, OIdentifiable> firstEntry;
  132. if (iFromInclusive)
  133. firstEntry = map.getCeilingEntry(iRangeFrom, OMVRBTree.PartialSearchMode.LOWEST_BOUNDARY);
  134. else
  135. firstEntry = map.getHigherEntry(iRangeFrom);
  136. if (firstEntry == null)
  137. return Collections.emptySet();
  138. final int firstEntryIndex = map.getPageIndex();
  139. final OMVRBTreeEntry<Object, OIdentifiable> lastEntry;
  140. if (iToInclusive)
  141. lastEntry = map.getHigherEntry(iRangeTo);
  142. else
  143. lastEntry = map.getCeilingEntry(iRangeTo, OMVRBTree.PartialSearchMode.LOWEST_BOUNDARY);
  144. final int lastEntryIndex;
  145. if (lastEntry != null)
  146. lastEntryIndex = map.getPageIndex();
  147. else
  148. lastEntryIndex = -1;
  149. OMVRBTreeEntry<Object, OIdentifiable> entry = firstEntry;
  150. map.setPageIndex(firstEntryIndex);
  151. final Set<OIdentifiable> result = new HashSet<OIdentifiable>();
  152. while (entry != null && !(entry == lastEntry && map.getPageIndex() == lastEntryIndex)
  153. && !(maxValuesToFetch > -1 && result.size() == maxValuesToFetch)) {
  154. result.add(entry.getValue());
  155. entry = OMVRBTree.next(entry);
  156. }
  157. return result;
  158. } finally {
  159. releaseExclusiveLock();
  160. }
  161. }
  162. public Collection<OIdentifiable> getValuesMajor(final Object fromKey, final boolean isInclusive, final int maxValuesToFetch) {
  163. acquireExclusiveLock();
  164. try {
  165. final OMVRBTreeEntry<Object, OIdentifiable> firstEntry;
  166. if (isInclusive)
  167. firstEntry = map.getCeilingEntry(fromKey, OMVRBTree.PartialSearchMode.LOWEST_BOUNDARY);
  168. else
  169. firstEntry = map.getHigherEntry(fromKey);
  170. if (firstEntry == null)
  171. return Collections.emptySet();
  172. OMVRBTreeEntry<Object, OIdentifiable> entry = firstEntry;
  173. final HashSet<OIdentifiable> result = new HashSet<OIdentifiable>();
  174. while (entry != null && !(maxValuesToFetch > -1 && result.size() == maxValuesToFetch)) {
  175. result.add(entry.getValue());
  176. entry = OMVRBTree.next(entry);
  177. }
  178. return result;
  179. } finally {
  180. releaseExclusiveLock();
  181. }
  182. }
  183. public Collection<OIdentifiable> getValuesMinor(final Object toKey, final boolean isInclusive, final int maxValuesToFetch) {
  184. acquireExclusiveLock();
  185. try {
  186. final OMVRBTreeEntry<Object, OIdentifiable> lastEntry;
  187. if (isInclusive)
  188. lastEntry = map.getFloorEntry(toKey, OMVRBTree.PartialSearchMode.HIGHEST_BOUNDARY);
  189. else
  190. lastEntry = map.getLowerEntry(toKey);
  191. if (lastEntry == null)
  192. return Collections.emptySet();
  193. OMVRBTreeEntry<Object, OIdentifiable> entry = lastEntry;
  194. final Set<OIdentifiable> result = new HashSet<OIdentifiable>();
  195. while (entry != null && !(maxValuesToFetch > -1 && result.size() == maxValuesToFetch)) {
  196. result.add(entry.getValue());
  197. entry = OMVRBTree.previous(entry);
  198. }
  199. return result;
  200. } finally {
  201. releaseExclusiveLock();
  202. }
  203. }
  204. public Collection<OIdentifiable> getValues(final Collection<?> iKeys, final int maxValuesToSearch) {
  205. final List<Object> sortedKeys = new ArrayList<Object>(iKeys);
  206. Collections.sort(sortedKeys, ODefaultComparator.INSTANCE);
  207. acquireExclusiveLock();
  208. final Set<OIdentifiable> result = new HashSet<OIdentifiable>();
  209. try {
  210. for (final Object key : sortedKeys) {
  211. if (maxValuesToSearch > -1 && result.size() == maxValuesToSearch)
  212. return result;
  213. final OIdentifiable val = map.get(key);
  214. if (val != null) {
  215. result.add(val);
  216. }
  217. }
  218. return result;
  219. } finally {
  220. releaseExclusiveLock();
  221. }
  222. }
  223. public Collection<ODocument> getEntriesMajor(final Object fromKey, final boolean isInclusive, final int maxEntriesToFetch) {
  224. acquireExclusiveLock();
  225. try {
  226. final OMVRBTreeEntry<Object, OIdentifiable> firstEntry;
  227. if (isInclusive)
  228. firstEntry = map.getCeilingEntry(fromKey, OMVRBTree.PartialSearchMode.LOWEST_BOUNDARY);
  229. else
  230. firstEntry = map.getHigherEntry(fromKey);
  231. if (firstEntry == null)
  232. return Collections.emptySet();
  233. OMVRBTreeEntry<Object, OIdentifiable> entry = firstEntry;
  234. final Set<ODocument> result = new ODocumentFieldsHashSet();
  235. while (entry != null && !(maxEntriesToFetch > -1 && result.size() == maxEntriesToFetch)) {
  236. final ODocument document = new ODocument();
  237. document.field("key", entry.getKey());
  238. document.field("rid", entry.getValue().getIdentity());
  239. document.unsetDirty();
  240. result.add(document);
  241. entry = OMVRBTree.next(entry);
  242. }
  243. return result;
  244. } finally {
  245. releaseExclusiveLock();
  246. }
  247. }
  248. public Collection<ODocument> getEntriesMinor(final Object toKey, final boolean isInclusive, final int maxEntriesToFetch) {
  249. acquireExclusiveLock();
  250. try {
  251. final OMVRBTreeEntry<Object, OIdentifiable> lastEntry;
  252. if (isInclusive)
  253. lastEntry = map.getFloorEntry(toKey, OMVRBTree.PartialSearchMode.HIGHEST_BOUNDARY);
  254. else
  255. lastEntry = map.getLowerEntry(toKey);
  256. if (lastEntry == null)
  257. return Collections.emptySet();
  258. OMVRBTreeEntry<Object, OIdentifiable> entry = lastEntry;
  259. final Set<ODocument> result = new ODocumentFieldsHashSet();
  260. while (entry != null && !(maxEntriesToFetch > -1 && result.size() == maxEntriesToFetch)) {
  261. final ODocument document = new ODocument();
  262. document.field("key", entry.getKey());
  263. document.field("rid", entry.getValue().getIdentity());
  264. document.unsetDirty();
  265. result.add(document);
  266. entry = OMVRBTree.previous(entry);
  267. }
  268. return result;
  269. } finally {
  270. releaseExclusiveLock();
  271. }
  272. }
  273. public Collection<ODocument> getEntriesBetween(final Object iRangeFrom, final Object iRangeTo, final boolean iInclusive,
  274. final int maxEntriesToFetch) {
  275. if (iRangeFrom.getClass() != iRangeTo.getClass())
  276. throw new IllegalArgumentException("Range from-to parameters are of different types");
  277. acquireExclusiveLock();
  278. try {
  279. final OMVRBTreeEntry<Object, OIdentifiable> firstEntry;
  280. if (iInclusive)
  281. firstEntry = map.getCeilingEntry(iRangeFrom, OMVRBTree.PartialSearchMode.LOWEST_BOUNDARY);
  282. else
  283. firstEntry = map.getHigherEntry(iRangeFrom);
  284. if (firstEntry == null)
  285. return Collections.emptySet();
  286. final int firstEntryIndex = map.getPageIndex();
  287. final OMVRBTreeEntry<Object, OIdentifiable> lastEntry;
  288. if (iInclusive)
  289. lastEntry = map.getHigherEntry(iRangeTo);
  290. else
  291. lastEntry = map.getCeilingEntry(iRangeTo, OMVRBTree.PartialSearchMode.LOWEST_BOUNDARY);
  292. final int lastEntryIndex;
  293. if (lastEntry != null)
  294. lastEntryIndex = map.getPageIndex();
  295. else
  296. lastEntryIndex = -1;
  297. OMVRBTreeEntry<Object, OIdentifiable> entry = firstEntry;
  298. map.setPageIndex(firstEntryIndex);
  299. final Set<ODocument> result = new ODocumentFieldsHashSet();
  300. while (entry != null && !(entry == lastEntry && map.getPageIndex() == lastEntryIndex)
  301. && !(maxEntriesToFetch > -1 && result.size() == maxEntriesToFetch)) {
  302. final ODocument document = new ODocument();
  303. document.field("key", entry.getKey());
  304. document.field("rid", entry.getValue().getIdentity());
  305. document.unsetDirty();
  306. result.add(document);
  307. entry = OMVRBTree.next(entry);
  308. }
  309. return result;
  310. } finally {
  311. releaseExclusiveLock();
  312. }
  313. }
  314. public Collection<ODocument> getEntries(final Collection<?> iKeys, final int maxEntriesToFetch) {
  315. final List<Object> sortedKeys = new ArrayList<Object>(iKeys);
  316. Collections.sort(sortedKeys, ODefaultComparator.INSTANCE);
  317. acquireExclusiveLock();
  318. final Set<ODocument> result = new ODocumentFieldsHashSet();
  319. try {
  320. for (final Object key : sortedKeys) {
  321. if (maxEntriesToFetch > -1 && result.size() == maxEntriesToFetch)
  322. return result;
  323. final OIdentifiable val = map.get(key);
  324. if (val != null) {
  325. final ODocument document = new ODocument();
  326. document.field("key", key);
  327. document.field("rid", val.getIdentity());
  328. document.unsetDirty();
  329. result.add(document);
  330. }
  331. }
  332. return result;
  333. } finally {
  334. releaseExclusiveLock();
  335. }
  336. }
  337. public long getSize() {
  338. acquireSharedLock();
  339. try {
  340. return map.size();
  341. } finally {
  342. releaseSharedLock();
  343. }
  344. }
  345. public long getKeySize() {
  346. acquireSharedLock();
  347. try {
  348. return map.size();
  349. } finally {
  350. releaseSharedLock();
  351. }
  352. }
  353. public Iterator<OIdentifiable> valuesIterator() {
  354. acquireExclusiveLock();
  355. try {
  356. return map.values().iterator();
  357. } finally {
  358. releaseExclusiveLock();
  359. }
  360. }
  361. @SuppressWarnings({ "unchecked", "rawtypes" })
  362. public Iterator<OIdentifiable> valuesInverseIterator() {
  363. acquireExclusiveLock();
  364. try {
  365. return ((OMVRBTree.Values) map.values()).inverseIterator();
  366. } finally {
  367. releaseExclusiveLock();
  368. }
  369. }
  370. }