diff --git a/_base/base-build.xml b/_base/base-build.xml index 099d5b53b3c..7a32fd85738 100644 --- a/_base/base-build.xml +++ b/_base/base-build.xml @@ -13,6 +13,9 @@ + + + diff --git a/build.xml b/build.xml index ffbd5549158..b79149bb5b4 100644 --- a/build.xml +++ b/build.xml @@ -5,7 +5,7 @@ - + diff --git a/client/pom.xml b/client/pom.xml index 3ca216179c7..fecbaf876fc 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 ../ @@ -35,7 +35,6 @@ * com.orientechnologies.orient.client.* - com.orientechnologies.orientdb-core @@ -46,5 +45,4 @@ - diff --git a/client/src/main/java/com/orientechnologies/orient/client/remote/OStorageRemote.java b/client/src/main/java/com/orientechnologies/orient/client/remote/OStorageRemote.java index 08f3d619fc6..bd8e1debde0 100755 --- a/client/src/main/java/com/orientechnologies/orient/client/remote/OStorageRemote.java +++ b/client/src/main/java/com/orientechnologies/orient/client/remote/OStorageRemote.java @@ -1809,13 +1809,15 @@ private void removeDeadConnections() { // FREE DEAD CONNECTIONS int removedDeadConnections = 0; for (OChannelBinaryAsynchClient n : new ArrayList(networkPool)) { - if (n != null && !n.isConnected()) + if (n != null && !n.isConnected()) //Fixed issue with removing of network connections though connection is active. + { try { n.close(); } catch (Exception e) { } networkPool.remove(n); removedDeadConnections++; + } } OLogManager.instance().debug(this, "Found and removed %d dead connections from the network pool", removedDeadConnections); diff --git a/commons/pom.xml b/commons/pom.xml index 5a59215c284..cc7544565c4 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 ../ @@ -35,7 +35,6 @@ com.orientechnologies.common.* javax.imageio.spi.*,sun.misc.*;resolution:=optional - com.orientechnologies.orientdb-core diff --git a/commons/src/main/java/com/orientechnologies/common/comparator/OCaseInsentiveComparator.java b/commons/src/main/java/com/orientechnologies/common/comparator/OCaseInsentiveComparator.java index 0011959b41a..91980311037 100644 --- a/commons/src/main/java/com/orientechnologies/common/comparator/OCaseInsentiveComparator.java +++ b/commons/src/main/java/com/orientechnologies/common/comparator/OCaseInsentiveComparator.java @@ -7,6 +7,6 @@ */ public class OCaseInsentiveComparator implements Comparator { public int compare(final String stringOne, final String stringTwo) { - return stringOne.toLowerCase().compareTo(stringTwo.toLowerCase()); + return stringOne.compareToIgnoreCase(stringTwo); } } diff --git a/commons/src/main/java/com/orientechnologies/common/console/OCommandStream.java b/commons/src/main/java/com/orientechnologies/common/console/OCommandStream.java new file mode 100755 index 00000000000..7d4cead2488 --- /dev/null +++ b/commons/src/main/java/com/orientechnologies/common/console/OCommandStream.java @@ -0,0 +1,11 @@ +package com.orientechnologies.common.console; + +import com.orientechnologies.common.concur.resource.OCloseable; + +/** + * @author Artem Orobets + */ +public interface OCommandStream extends OCloseable { + boolean hasNext(); + String nextCommand(); +} diff --git a/commons/src/main/java/com/orientechnologies/common/console/OConsoleApplication.java b/commons/src/main/java/com/orientechnologies/common/console/OConsoleApplication.java old mode 100644 new mode 100755 index 3f0d8735dd2..874eac0458e --- a/commons/src/main/java/com/orientechnologies/common/console/OConsoleApplication.java +++ b/commons/src/main/java/com/orientechnologies/common/console/OConsoleApplication.java @@ -22,8 +22,14 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; import java.util.Map.Entry; +import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -85,7 +91,7 @@ public int run() { if (consoleInput == null || consoleInput.length() == 0) continue; - if (!executeCommands(new Scanner(consoleInput), false)) + if (!executeCommands(new ODFACommandStream(consoleInput), false)) break; } } else { @@ -105,28 +111,22 @@ protected boolean isInteractiveMode(String[] args) { protected boolean executeBatch(final String commandLine) { final File commandFile = new File(commandLine); - Scanner scanner = null; - + OCommandStream scanner; try { - scanner = new Scanner(commandFile); + scanner = new ODFACommandStream(commandFile); } catch (FileNotFoundException e) { - scanner = new Scanner(commandLine); + scanner = new ODFACommandStream(commandLine); } return executeCommands(scanner, true); } - protected boolean executeCommands(final Scanner iScanner, final boolean iExitOnException) { + protected boolean executeCommands(final OCommandStream commandStream, final boolean iExitOnException) { final StringBuilder commandBuffer = new StringBuilder(); try { - String commandLine = null; - - iScanner.useDelimiter(";(?=([^\"]*\"[^\"]*\")*[^\"]*$)(?=([^']*'[^']*')*[^']*$)|\n"); - - while (iScanner.hasNext()) { - - commandLine = iScanner.next().trim(); + while (commandStream.hasNext()) { + String commandLine = commandStream.nextCommand(); if (commandLine.isEmpty()) // EMPTY LINE @@ -167,7 +167,7 @@ protected boolean executeCommands(final Scanner iScanner, final boolean iExitOnE return false; } } finally { - iScanner.close(); + commandStream.close(); } return true; } @@ -349,7 +349,7 @@ protected void syntaxError(String iCommand, Method m) { /** * Returns a map of all console method and the object they can be called on. * - * @return Map + * @return Map<Method,Object> */ protected Map getConsoleMethods() { diff --git a/commons/src/main/java/com/orientechnologies/common/console/ODFACommandStream.java b/commons/src/main/java/com/orientechnologies/common/console/ODFACommandStream.java new file mode 100755 index 00000000000..321a14e3eef --- /dev/null +++ b/commons/src/main/java/com/orientechnologies/common/console/ODFACommandStream.java @@ -0,0 +1,257 @@ +package com.orientechnologies.common.console; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Artem Orobets + */ +public class ODFACommandStream implements OCommandStream { + public static final int BUFFER_SIZE = 1024; + + private Reader reader; + private CharBuffer buffer; + private final Set separators = new HashSet(Arrays.asList(';', '\n')); + private int position; + private int start; + private int end; + private StringBuilder partialResult; + private State state; + + public ODFACommandStream(String commands) { + reader = new StringReader(commands); + init(); + } + + public ODFACommandStream(File file) throws FileNotFoundException { + reader = new BufferedReader(new FileReader(file)); + init(); + } + + private void init() { + buffer = CharBuffer.allocate(BUFFER_SIZE); + buffer.flip(); + } + + @Override + public boolean hasNext() { + try { + fillBuffer(); + + return buffer.hasRemaining(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void fillBuffer() throws IOException { + if (!buffer.hasRemaining()) { + buffer.clear(); + reader.read(buffer); + buffer.flip(); + } + } + + @Override + public String nextCommand() { + try { + fillBuffer(); + + partialResult = new StringBuilder(); + state = State.S; + start = 0; + end = -1; + position = 0; + Symbol s = null; + while (state != State.E) { + s = nextSymbol(); + + final State newState = transition(state, s); + + if (state == State.S && newState != State.S) + start = position; + + if (newState == State.A) + end = position; + + if (newState == State.F) + throw new IllegalStateException("Unexpected end of file"); + + state = newState; + position++; + } + + if (s == Symbol.EOF) { + position--; + if (end == -1) { + start = 0; + end = 0; + } + } + + final String result; + if (partialResult.length() > 0) { + if (end > 0) { + result = partialResult.append(buffer.subSequence(start, end + 1).toString()).toString(); + } else { + partialResult.setLength(partialResult.length() + end + 1); + result = partialResult.toString(); + } + } else { + result = buffer.subSequence(start, end + 1).toString(); + } + + buffer.position(buffer.position() + position); + return result; + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Symbol nextSymbol() throws IOException { + Symbol s; + if (buffer.position() + position < buffer.limit()) { + s = symbol(buffer.charAt(position)); + } else { + buffer.compact(); + int read = reader.read(buffer); + buffer.flip(); + + if (read == 0) { + // There is something in source, but buffer is full + + if (state != State.S) + partialResult.append(buffer.subSequence(start, position).toString()); + start = 0; + end = end - position; + buffer.clear(); + read = reader.read(buffer); + buffer.flip(); + position = 0; + } + + if (read == -1) { + s = Symbol.EOF; + } else { + s = symbol(buffer.charAt(position)); + } + } + return s; + } + + private State transition(State s, Symbol c) { + switch (s) { + case S: + switch (c) { + case LATTER: + return State.A; + case WS: + return State.S; + case AP: + return State.B; + case QT: + return State.C; + case SEP: + return State.S; + case EOF: + return State.E; + } + break; + case A: + case D: + switch (c) { + case LATTER: + return State.A; + case WS: + return State.D; + case AP: + return State.B; + case QT: + return State.C; + case SEP: + return State.E; + case EOF: + return State.E; + } + break; + case B: + switch (c) { + case LATTER: + return State.B; + case WS: + return State.B; + case AP: + return State.A; + case QT: + return State.B; + case SEP: + return State.B; + case EOF: + return State.F; + } + break; + case C: + switch (c) { + case LATTER: + return State.C; + case WS: + return State.C; + case AP: + return State.C; + case QT: + return State.A; + case SEP: + return State.C; + case EOF: + return State.F; + } + break; + case E: + return State.E; + case F: + return State.F; + } + + throw new IllegalStateException(); + } + + @Override + public void close() { + try { + reader.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Symbol symbol(Character c) { + if (c.equals('\'')) + return Symbol.AP; + if (c.equals('"')) + return Symbol.QT; + if (separators.contains(c)) + return Symbol.SEP; + if (Character.isWhitespace(c)) + return Symbol.WS; + + return Symbol.LATTER; + } + + private enum State { + S, A, B, C, D, E, F + } + + private enum Symbol { + LATTER, WS, QT, AP, SEP, EOF + } +} diff --git a/commons/src/main/java/com/orientechnologies/common/console/OScannerCommandStream.java b/commons/src/main/java/com/orientechnologies/common/console/OScannerCommandStream.java new file mode 100755 index 00000000000..c729f5ec9c5 --- /dev/null +++ b/commons/src/main/java/com/orientechnologies/common/console/OScannerCommandStream.java @@ -0,0 +1,41 @@ +package com.orientechnologies.common.console; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +/** + * @author Artem Orobets + */ +public class OScannerCommandStream implements OCommandStream { + private Scanner scanner; + + public OScannerCommandStream(String commands) { + scanner = new Scanner(commands); + init(); + } + + public OScannerCommandStream(File file) throws FileNotFoundException { + scanner = new Scanner(file); + init(); + } + + private void init() { + scanner.useDelimiter(";(?=([^\"]*\"[^\"]*\")*[^\"]*$)(?=([^']*'[^']*')*[^']*$)|\n"); + } + + @Override + public boolean hasNext() { + return scanner.hasNext(); + } + + @Override + public String nextCommand() { + return scanner.next().trim(); + } + + @Override + public void close() { + scanner.close(); + } +} diff --git a/commons/src/main/java/com/orientechnologies/common/profiler/OProfiler.java b/commons/src/main/java/com/orientechnologies/common/profiler/OProfiler.java index dde561fd1ea..394c164dbbe 100644 --- a/commons/src/main/java/com/orientechnologies/common/profiler/OProfiler.java +++ b/commons/src/main/java/com/orientechnologies/common/profiler/OProfiler.java @@ -36,7 +36,7 @@ public class OProfiler extends OAbstractProfiler { public OProfiler() { } - public OProfiler(final OProfiler profiler) { + public OProfiler(final OAbstractProfiler profiler) { super(profiler); } diff --git a/commons/src/test/java/com/orientechnologies/common/console/ODFACommandStreamTest.java b/commons/src/test/java/com/orientechnologies/common/console/ODFACommandStreamTest.java new file mode 100755 index 00000000000..739d330dee5 --- /dev/null +++ b/commons/src/test/java/com/orientechnologies/common/console/ODFACommandStreamTest.java @@ -0,0 +1,45 @@ +package com.orientechnologies.common.console; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Artem Orobets + */ +public class ODFACommandStreamTest { + @Test + public void testNextCommand() throws Exception { + test("one;two", "one", "two"); + } + + @Test + public void testNextCommandQuotes() throws Exception { + test("Select 'one;'; Select \"t;w;o\"", "Select 'one;'", "Select \"t;w;o\""); + } + + @Test + public void testNextCommandSeparatorAtTheEnd() throws Exception { + test("one;two;", "one", "two"); + } + + @Test + public void testNextCommandWhitespaces() throws Exception { + test("\tone ; two ", "one", "two"); + } + + private void test(String source, String... expectedResults) { + final ODFACommandStream stream = new ODFACommandStream(source); + + for (String expectedResult : expectedResults) { + Assert.assertTrue(stream.hasNext()); + + String result = stream.nextCommand(); + Assert.assertEquals(result, expectedResult); + } + + Assert.assertFalse(stream.hasNext()); + } +} diff --git a/core/pom.xml b/core/pom.xml index 55b276d1c24..88eaad9f0d8 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -17,7 +17,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 ../ @@ -34,6 +34,7 @@ org.iq80.snappy;resolution:=optional, javax.imageio.spi,sun.misc;resolution:=optional, com.orientechnologies.nio;resolution:=optional, + com.orientechnologies.orient.client.remote;resolution:=optional, * com.orientechnologies.orient.core.* diff --git a/core/src/main/java/com/orientechnologies/orient/core/OConstants.java b/core/src/main/java/com/orientechnologies/orient/core/OConstants.java index 95e6fc21768..756c09cf2bd 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/OConstants.java +++ b/core/src/main/java/com/orientechnologies/orient/core/OConstants.java @@ -16,7 +16,7 @@ package com.orientechnologies.orient.core; public class OConstants { - public static final String ORIENT_VERSION = "1.6.1"; + public static final String ORIENT_VERSION = "1.6.2"; public static final String ORIENT_URL = "www.orientechnologies.com"; public static String getVersion() { diff --git a/core/src/main/java/com/orientechnologies/orient/core/collate/OCaseInsensitiveCollate.java b/core/src/main/java/com/orientechnologies/orient/core/collate/OCaseInsensitiveCollate.java new file mode 100644 index 00000000000..974e482c43f --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/collate/OCaseInsensitiveCollate.java @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2013 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.core.collate; + +import com.orientechnologies.common.comparator.ODefaultComparator; + +/** + * Case insensitive collate. + * + * @author Luca Garulli (l.garulli--at--orientechnologies.com) + * + */ +public class OCaseInsensitiveCollate extends ODefaultComparator implements OCollate { + public String getName() { + return "ci"; + } + + public Object transform(final Object obj) { + if (obj instanceof String) + return ((String) obj).toLowerCase(); + return obj; + } +} diff --git a/core/src/main/java/com/orientechnologies/orient/core/collate/OCollate.java b/core/src/main/java/com/orientechnologies/orient/core/collate/OCollate.java new file mode 100644 index 00000000000..31682af8503 --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/collate/OCollate.java @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2013 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.core.collate; + +import java.util.Comparator; + +/** + * Specify the Collating strategy when comparison in SQL statement is required. + * + * @author Luca Garulli (l.garulli--at--orientechnologies.com) + * + */ +public interface OCollate extends Comparator { + public String getName(); + + public Object transform(Object obj); +} diff --git a/core/src/main/java/com/orientechnologies/orient/core/collate/OCollateFactory.java b/core/src/main/java/com/orientechnologies/orient/core/collate/OCollateFactory.java new file mode 100644 index 00000000000..49661943f4b --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/collate/OCollateFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2013 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.core.collate; + +import java.util.Set; + +/** + * the Collating strategy when comparison in SQL statement is required. + * + * @author Luca Garulli (l.garulli--at--orientechnologies.com) + * + */ +public interface OCollateFactory { + + /** + * @return Set of supported collate names of this factory + */ + Set getNames(); + + /** + * Returns the requested collate + * + * @param name + */ + OCollate getCollate(String name); + +} \ No newline at end of file diff --git a/core/src/main/java/com/orientechnologies/orient/core/collate/ODefaultCollate.java b/core/src/main/java/com/orientechnologies/orient/core/collate/ODefaultCollate.java new file mode 100644 index 00000000000..f10d93de7d5 --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/collate/ODefaultCollate.java @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2013 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.core.collate; + +import com.orientechnologies.common.comparator.ODefaultComparator; + +/** + * Default collate, does not apply conversions. + * + * @author Luca Garulli (l.garulli--at--orientechnologies.com) + * + */ +public class ODefaultCollate extends ODefaultComparator implements OCollate { + public static final String NAME = "default"; + + public String getName() { + return NAME; + } + + public Object transform(final Object obj) { + return obj; + } +} diff --git a/core/src/main/java/com/orientechnologies/orient/core/collate/ODefaultCollateFactory.java b/core/src/main/java/com/orientechnologies/orient/core/collate/ODefaultCollateFactory.java new file mode 100644 index 00000000000..c2fb0c82e7c --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/collate/ODefaultCollateFactory.java @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2013 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.core.collate; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * the Collating strategy when comparison in SQL statement is required. + * + * @author Luca Garulli (l.garulli--at--orientechnologies.com) + * + */ +public class ODefaultCollateFactory implements OCollateFactory { + + private static final Map COLLATES = new HashMap(2); + + static { + register(new ODefaultCollate()); + register(new OCaseInsensitiveCollate()); + } + + /** + * @return Set of supported collate names of this factory + */ + @Override + public Set getNames() { + return COLLATES.keySet(); + } + + /** + * Returns the requested collate + * + * @param name + */ + @Override + public OCollate getCollate(final String name) { + return COLLATES.get(name); + } + + private static void register(final OCollate iCollate) { + COLLATES.put(iCollate.getName(), iCollate); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/orientechnologies/orient/core/config/OGlobalConfiguration.java b/core/src/main/java/com/orientechnologies/orient/core/config/OGlobalConfiguration.java index 15ffdc9fb26..99c8b3518b4 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/config/OGlobalConfiguration.java +++ b/core/src/main/java/com/orientechnologies/orient/core/config/OGlobalConfiguration.java @@ -81,9 +81,9 @@ public enum OGlobalConfiguration { "Maximum size of WAL cache (in amount of WAL pages, each page is 64k) <= 0 means that caching will be switched off.", Integer.class, 3000), - WAL_MAX_SEGMENT_SIZE("storage.wal.maxSegmentSize", "Maximum size of single WAL segment in megabytes.", Integer.class, 64), + WAL_MAX_SEGMENT_SIZE("storage.wal.maxSegmentSize", "Maximum size of single WAL segment in megabytes.", Integer.class, 256), - WAL_MAX_SIZE("storage.wal.maxSize", "Maximum size of WAL on disk in megabytes.", Integer.class, 150 * 1024), + WAL_MAX_SIZE("storage.wal.maxSize", "Maximum size of WAL on disk in megabytes.", Integer.class, 4 * 1024), WAL_COMMIT_TIMEOUT("storage.wal.commitTimeout", "Maximum interval between WAL commits (in ms.)", Integer.class, 1000), diff --git a/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OIndexRIDContainer.java b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OIndexRIDContainer.java new file mode 100644 index 00000000000..22b77fad909 --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OIndexRIDContainer.java @@ -0,0 +1,182 @@ +/* + * Copyright 2010-2012 Luca Garulli (l.garulli(at)orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.orientechnologies.orient.core.db.record.ridset.sbtree; + +import java.io.IOException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; +import com.orientechnologies.orient.core.db.record.OIdentifiable; +import com.orientechnologies.orient.core.index.sbtree.local.OSBTreeException; +import com.orientechnologies.orient.core.storage.impl.local.OStorageLocalAbstract; + +/** + * Persistent Set implementation that uses the SBTree to handle entries in persistent way. + * + * @author Artem Orobets + */ +public class OIndexRIDContainer implements Set { + public static final String INDEX_FILE_EXTENSION = ".irs"; + + private final long fileId; + private Set underlying; + private boolean isEmbedded; + private int topThreshold = 80; + private int bottomThreshold = 60; + + public OIndexRIDContainer(String name) { + final OStorageLocalAbstract storage = (OStorageLocalAbstract) ODatabaseRecordThreadLocal.INSTANCE.get().getStorage() + .getUnderlying(); + try { + fileId = storage.getDiskCache().openFile(name + INDEX_FILE_EXTENSION); + } catch (IOException e) { + throw new OSBTreeException("Error creation of sbtree with name" + name, e); + } + underlying = new HashSet(); + isEmbedded = true; + } + + public OIndexRIDContainer(long fileId, Set underlying) { + this.fileId = fileId; + this.underlying = underlying; + isEmbedded = !(underlying instanceof OIndexRIDContainerSBTree); + } + + public long getFileId() { + return fileId; + } + + @Override + public int size() { + return underlying.size(); + } + + @Override + public boolean isEmpty() { + return underlying.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return underlying.contains(o); + } + + @Override + public Iterator iterator() { + return underlying.iterator(); + } + + @Override + public Object[] toArray() { + return underlying.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return underlying.toArray(a); + } + + @Override + public boolean add(OIdentifiable oIdentifiable) { + final boolean res = underlying.add(oIdentifiable); + checkTopThreshold(); + return res; + } + + @Override + public boolean remove(Object o) { + final boolean res = underlying.remove(o); + checkBottomThreshold(); + return res; + } + + @Override + public boolean containsAll(Collection c) { + return underlying.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + final boolean res = underlying.addAll(c); + checkTopThreshold(); + return res; + } + + @Override + public boolean retainAll(Collection c) { + return underlying.retainAll(c); + } + + @Override + public boolean removeAll(Collection c) { + final boolean res = underlying.removeAll(c); + checkBottomThreshold(); + return res; + } + + @Override + public void clear() { + if (isEmbedded) + underlying.clear(); + else { + final OIndexRIDContainerSBTree tree = (OIndexRIDContainerSBTree) underlying; + tree.delete(); + underlying = new HashSet(); + isEmbedded = true; + } + } + + public boolean isEmbedded() { + return isEmbedded; + } + + public Set getUnderlying() { + return underlying; + } + + private void checkTopThreshold() { + if (isEmbedded && topThreshold < underlying.size()) + convertToSbTree(); + } + + private void checkBottomThreshold() { + if (!isEmbedded && bottomThreshold > underlying.size()) + convertToEmbedded(); + } + + private void convertToEmbedded() { + final OIndexRIDContainerSBTree tree = (OIndexRIDContainerSBTree) underlying; + + final Set set = new HashSet(tree); + + tree.delete(); + underlying = set; + isEmbedded = true; + } + + private void convertToSbTree() { + final OIndexRIDContainerSBTree tree = new OIndexRIDContainerSBTree(fileId); + + tree.addAll(underlying); + + underlying = tree; + isEmbedded = false; + } +} diff --git a/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeIndexRIDContainer.java b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OIndexRIDContainerSBTree.java similarity index 67% rename from core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeIndexRIDContainer.java rename to core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OIndexRIDContainerSBTree.java index 7b4a679b234..c093559e25b 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeIndexRIDContainer.java +++ b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OIndexRIDContainerSBTree.java @@ -16,6 +16,7 @@ package com.orientechnologies.orient.core.db.record.ridset.sbtree; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -26,15 +27,12 @@ import com.orientechnologies.orient.core.Orient; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.OIdentifiable; -import com.orientechnologies.orient.core.exception.OSerializationException; import com.orientechnologies.orient.core.index.sbtree.OSBTreeMapEntryIterator; import com.orientechnologies.orient.core.index.sbtree.OTreeInternal; +import com.orientechnologies.orient.core.index.sbtree.local.OSBTreeException; import com.orientechnologies.orient.core.index.sbtreebonsai.local.OBonsaiBucketPointer; import com.orientechnologies.orient.core.index.sbtreebonsai.local.OSBTreeBonsai; -import com.orientechnologies.orient.core.record.impl.ODocument; -import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper; import com.orientechnologies.orient.core.serialization.serializer.binary.impl.OLinkSerializer; -import com.orientechnologies.orient.core.serialization.serializer.string.OStringBuilderSerializable; import com.orientechnologies.orient.core.storage.impl.local.OStorageLocalAbstract; /** @@ -42,29 +40,39 @@ * * @author Artem Orobets */ -public class OSBTreeIndexRIDContainer implements Set, OStringBuilderSerializable { +public class OIndexRIDContainerSBTree implements Set { public static final String INDEX_FILE_EXTENSION = ".irs"; private OSBTreeBonsai tree; protected static final OProfilerMBean PROFILER = Orient.instance().getProfiler(); - public OSBTreeIndexRIDContainer(String fileName) { + public OIndexRIDContainerSBTree(long fileId) { tree = new OSBTreeBonsai(INDEX_FILE_EXTENSION, 1, false); - tree.create(fileName, OLinkSerializer.INSTANCE, OBooleanSerializer.INSTANCE, + tree.create(fileId, OLinkSerializer.INSTANCE, OBooleanSerializer.INSTANCE, (OStorageLocalAbstract) ODatabaseRecordThreadLocal.INSTANCE.get().getStorage().getUnderlying()); } - public OSBTreeIndexRIDContainer(String fileName, OBonsaiBucketPointer rootPointer) { + public OIndexRIDContainerSBTree(long fileId, OBonsaiBucketPointer rootPointer) { tree = new OSBTreeBonsai(INDEX_FILE_EXTENSION, 1, false); - tree.load(fileName, rootPointer, (OStorageLocalAbstract) ODatabaseRecordThreadLocal.INSTANCE.get().getStorage().getUnderlying()); + tree.load(fileId, rootPointer, (OStorageLocalAbstract) ODatabaseRecordThreadLocal.INSTANCE.get().getStorage().getUnderlying()); } - protected String getFileName() { - return tree.getName(); + public OIndexRIDContainerSBTree(String file, OBonsaiBucketPointer rootPointer) { + tree = new OSBTreeBonsai(INDEX_FILE_EXTENSION, 1, false); + + final OStorageLocalAbstract storage = (OStorageLocalAbstract) ODatabaseRecordThreadLocal.INSTANCE.get().getStorage() + .getUnderlying(); + final long fileId; + try { + fileId = storage.getDiskCache().openFile(file + INDEX_FILE_EXTENSION); + } catch (IOException e) { + throw new OSBTreeException("Exception during loading of sbtree " + file, e); + } + tree.load(fileId, rootPointer, storage); } - protected OBonsaiBucketPointer getRootPointer() { + public OBonsaiBucketPointer getRootPointer() { return tree.getRootBucketPointer(); } @@ -120,12 +128,7 @@ public T[] toArray(T[] a) { @Override public boolean add(OIdentifiable oIdentifiable) { - // TODO check if we can avoid get operation - if (this.tree.get(oIdentifiable) != null) - return false; - - this.tree.put(oIdentifiable, Boolean.TRUE); - return true; + return this.tree.put(oIdentifiable, Boolean.TRUE); } @Override @@ -182,47 +185,12 @@ public void clear() { tree.clear(); } - @Override - public OSBTreeIndexRIDContainer toStream(StringBuilder iOutput) throws OSerializationException { - final long timer = PROFILER.startChrono(); - - try { - iOutput.append(OStringSerializerHelper.LINKSET_PREFIX); - - final ODocument document = new ODocument(); - document.field("rootIndex", getRootPointer().getPageIndex()); - document.field("rootOffset", getRootPointer().getPageOffset()); - document.field("file", getFileName()); - iOutput.append(new String(document.toStream())); - - iOutput.append(OStringSerializerHelper.SET_END); - } finally { - PROFILER.stopChrono(PROFILER.getProcessMetric("mvrbtree.toStream"), "Serialize a MVRBTreeRID", timer); - } - return this; + public void delete() { + tree.delete(); } - public byte[] toStream() { - final StringBuilder iOutput = new StringBuilder(); - toStream(iOutput); - return iOutput.toString().getBytes(); - } - - @Override - public OStringBuilderSerializable fromStream(StringBuilder iInput) throws OSerializationException { - throw new UnsupportedOperationException("unimplemented yet"); - } - - public static OSBTreeIndexRIDContainer fromStream(String stream) { - stream = stream.substring(OStringSerializerHelper.LINKSET_PREFIX.length(), stream.length() - 1); - - final ODocument doc = new ODocument(); - doc.fromString(stream); - final OBonsaiBucketPointer rootIndex = new OBonsaiBucketPointer((Long) doc.field("rootIndex"), - (Integer) doc.field("rootOffset")); - final String fileName = doc.field("file"); - - return new OSBTreeIndexRIDContainer(fileName, rootIndex); + public String getFileName() { + return tree.getFileName(); } private static class TreeKeyIterator implements Iterator { diff --git a/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeCollectionManager.java b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeCollectionManager.java index b88866df208..a061bdb6b15 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeCollectionManager.java +++ b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeCollectionManager.java @@ -47,13 +47,13 @@ public OSBTreeBonsai createSBTree() { return tree; } - public OSBTreeBonsai loadSBTree(String fileName, OBonsaiBucketPointer rootIndex) { + public OSBTreeBonsai loadSBTree(long fileId, OBonsaiBucketPointer rootIndex) { OSBTreeBonsai tree = treeCache.get(rootIndex); if (tree != null) return tree; tree = new OSBTreeBonsai(".sbt", 1, true); - tree.load(fileName, rootIndex, (OStorageLocalAbstract) ODatabaseRecordThreadLocal.INSTANCE.get().getStorage().getUnderlying()); + tree.load(fileId, rootIndex, (OStorageLocalAbstract) ODatabaseRecordThreadLocal.INSTANCE.get().getStorage().getUnderlying()); treeCache.put(tree.getRootBucketPointer(), tree); diff --git a/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSet.java b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSet.java index e3a6019a8de..57a669a6bea 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSet.java +++ b/core/src/main/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSet.java @@ -43,7 +43,7 @@ * @author Artem Orobets */ public class OSBTreeRIDSet implements Set, OStringBuilderSerializable, ORecordLazyMultiValue { - private final String fileName; + private final long fileId; private final OBonsaiBucketPointer rootPointer; private ORecordInternal owner; private boolean autoConvertToRecord = true; @@ -56,7 +56,7 @@ private OSBTreeRIDSet(ODatabaseRecord database) { collectionManager = database.getSbTreeCollectionManager(); OSBTreeBonsai tree = collectionManager.createSBTree(); - fileName = tree.getName(); + fileId = tree.getFileId(); rootPointer = tree.getRootBucketPointer(); } @@ -70,9 +70,9 @@ public OSBTreeRIDSet(ORecordInternal owner) { this.owner = owner; } - public OSBTreeRIDSet(ORecordInternal owner, String fileName, OBonsaiBucketPointer rootPointer) { + public OSBTreeRIDSet(ORecordInternal owner, long fileId, OBonsaiBucketPointer rootPointer) { this.owner = owner; - this.fileName = fileName; + this.fileId = fileId; this.rootPointer = rootPointer; if (owner != null) @@ -87,11 +87,11 @@ public OSBTreeRIDSet(ODocument owner, Collection iValue) { } private OSBTreeBonsai getTree() { - return collectionManager.loadSBTree(fileName, rootPointer); + return collectionManager.loadSBTree(fileId, rootPointer); } - protected String getFileName() { - return fileName; + protected long getFileId() { + return fileId; } protected OBonsaiBucketPointer getRootPointer() { @@ -160,13 +160,7 @@ public boolean add(OIdentifiable oIdentifiable) { } private boolean add(OSBTreeBonsai tree, OIdentifiable oIdentifiable) { - // TODO check if we can avoid get operation - // TODO fix race condition - if (getTree().get(oIdentifiable) != null) - return false; - - getTree().put(oIdentifiable, Boolean.TRUE); - return true; + return tree.put(oIdentifiable, Boolean.TRUE); } @Override @@ -234,7 +228,7 @@ public OSBTreeRIDSet toStream(StringBuilder iOutput) throws OSerializationExcept final ODocument document = new ODocument(); document.field("rootIndex", getRootPointer().getPageIndex()); document.field("rootOffset", getRootPointer().getPageOffset()); - document.field("file", getFileName()); + document.field("fileId", getFileId()); iOutput.append(new String(document.toStream())); iOutput.append(OStringSerializerHelper.SET_END); @@ -262,9 +256,9 @@ public static OSBTreeRIDSet fromStream(String stream, ORecordInternal owner) doc.fromString(stream); final OBonsaiBucketPointer rootIndex = new OBonsaiBucketPointer((Long) doc.field("rootIndex"), (Integer) doc.field("rootOffset")); - final String fileName = doc.field("file"); + final long fileId = doc.field("fileId"); - return new OSBTreeRIDSet(owner, fileName, rootIndex); + return new OSBTreeRIDSet(owner, fileId, rootIndex); } @Override diff --git a/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseExport.java b/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseExport.java index ea0110e8e09..ab3ea0a0579 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseExport.java +++ b/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseExport.java @@ -15,7 +15,11 @@ */ package com.orientechnologies.orient.core.db.tool; -import java.io.*; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -34,7 +38,12 @@ import com.orientechnologies.orient.core.index.OIndexManagerProxy; import com.orientechnologies.orient.core.index.ORuntimeKeyIndexDefinition; import com.orientechnologies.orient.core.iterator.ORecordIteratorCluster; -import com.orientechnologies.orient.core.metadata.schema.*; +import com.orientechnologies.orient.core.metadata.schema.OClass; +import com.orientechnologies.orient.core.metadata.schema.OClassImpl; +import com.orientechnologies.orient.core.metadata.schema.OProperty; +import com.orientechnologies.orient.core.metadata.schema.OPropertyImpl; +import com.orientechnologies.orient.core.metadata.schema.OSchemaProxy; +import com.orientechnologies.orient.core.metadata.schema.OSchemaShared; import com.orientechnologies.orient.core.record.ORecordInternal; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.serialization.serializer.OJSONWriter; @@ -66,7 +75,7 @@ public ODatabaseExport(final ODatabaseRecord iDatabase, final String iFileName, if (f.exists()) f.delete(); - writer = new OJSONWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(fileName)))); + writer = new OJSONWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(fileName), 16384))); // 16KB writer.beginObject(); iDatabase.getLevel1Cache().setEnable(false); iDatabase.getLevel2Cache().setEnable(false); diff --git a/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseImport.java b/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseImport.java index 87177019a30..160e37ba324 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseImport.java +++ b/core/src/main/java/com/orientechnologies/orient/core/db/tool/ODatabaseImport.java @@ -112,7 +112,7 @@ public ODatabaseImport(final ODatabaseDocument database, final String iFileName, final BufferedInputStream bf = new BufferedInputStream(new FileInputStream(fileName)); bf.mark(1024); try { - inStream = new GZIPInputStream(bf); + inStream = new GZIPInputStream(bf, 16384); // 16KB } catch (Exception e) { bf.reset(); inStream = bf; diff --git a/core/src/main/java/com/orientechnologies/orient/core/fetch/OFetchHelper.java b/core/src/main/java/com/orientechnologies/orient/core/fetch/OFetchHelper.java index 206b2ffdec4..e11dc25f985 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/fetch/OFetchHelper.java +++ b/core/src/main/java/com/orientechnologies/orient/core/fetch/OFetchHelper.java @@ -188,7 +188,7 @@ public static void processRecordRidMap(final ORecordSchemaAware record, Map -1 && iCurrentLevel >= depthLevel) // MAX DEPTH REACHED: STOP TO FETCH THIS FIELD continue; diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OAbstractIndexDefinition.java b/core/src/main/java/com/orientechnologies/orient/core/index/OAbstractIndexDefinition.java new file mode 100644 index 00000000000..4146505a644 --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OAbstractIndexDefinition.java @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2012 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.core.index; + +import com.orientechnologies.orient.core.collate.OCollate; +import com.orientechnologies.orient.core.collate.ODefaultCollate; +import com.orientechnologies.orient.core.record.impl.ODocument; +import com.orientechnologies.orient.core.sql.OSQLEngine; +import com.orientechnologies.orient.core.type.ODocumentWrapperNoClass; + +/** + * Abstract index definiton implementation. + * + * @author Luca Garulli (l.garulli--at--orientechnologies.com) + * + */ +public abstract class OAbstractIndexDefinition extends ODocumentWrapperNoClass implements OIndexDefinition { + protected OCollate collate = new ODefaultCollate(); + + protected OAbstractIndexDefinition() { + super(new ODocument()); + } + + public OCollate getCollate() { + return collate; + } + + public void setCollate(final OCollate collate) { + if (collate == null) + throw new IllegalArgumentException("COLLATE cannot be null"); + this.collate = collate; + } + + public void setCollate(String iCollate) { + if (iCollate == null) + iCollate = ODefaultCollate.NAME; + + setCollate(OSQLEngine.getCollate(iCollate)); + } +} diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OClassIndexManager.java b/core/src/main/java/com/orientechnologies/orient/core/index/OClassIndexManager.java index 9ba82e5c5ad..920419df1d5 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OClassIndexManager.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OClassIndexManager.java @@ -53,6 +53,9 @@ * @author Andrey Lomakin, Artem Orobets */ public class OClassIndexManager extends ODocumentHookAbstract { + + private final Set lockedIndexes = new HashSet(); + public OClassIndexManager() { } @@ -202,14 +205,14 @@ public RESULT onRecordBeforeDelete(final ODocument iDocument) { ORecordOperation.DELETED); } - acquireModificationLock(iDocument, iDocument.getSchemaClass() != null ? iDocument.getSchemaClass().getIndexes() : null); + acquireModificationLock(iDocument.getSchemaClass() != null ? iDocument.getSchemaClass().getIndexes() : null); return RESULT.RECORD_NOT_CHANGED; } @Override public RESULT onRecordBeforeReplicaDelete(ODocument iDocument) { checkForLoading(iDocument); - acquireModificationLock(iDocument, iDocument.getSchemaClass() != null ? iDocument.getSchemaClass().getIndexes() : null); + acquireModificationLock(iDocument.getSchemaClass() != null ? iDocument.getSchemaClass().getIndexes() : null); return RESULT.RECORD_NOT_CHANGED; } @@ -516,7 +519,7 @@ private void checkIndexesAndAquireLock(ODocument document, TYPE hookType) { default: throw new IllegalArgumentException("Invalid hook type: " + hookType); } - acquireModificationLock(document, indexes); + acquireModificationLock(indexes); } } @@ -535,8 +538,8 @@ private static void checkIndexedPropertiesOnCreation(final ODocument iRecord, fi } } - private static void acquireModificationLock(final ODocument iRecord, final Collection> iIndexes) { - if (iIndexes == null) + private void acquireModificationLock(final Collection> indexes) { + if (indexes == null) return; final SortedSet> indexesToLock = new TreeSet>(new Comparator>() { @@ -545,10 +548,13 @@ public int compare(OIndex indexOne, OIndex indexTwo) { } }); - indexesToLock.addAll(iIndexes); + indexesToLock.addAll(indexes); + + lockedIndexes.clear(); for (final OIndex index : indexesToLock) { index.getInternal().acquireModificationLock(); + lockedIndexes.add(index.getName()); } } @@ -556,7 +562,7 @@ public int compare(OIndex indexOne, OIndex indexTwo) { * Releases the index modification lock. Incurs overhead of index retrieval: if you already have a list of indexes for the schema * class of this record, use the overloaded method that takes a collection. */ - private static void releaseModificationLock(final ODocument iRecord) { + private void releaseModificationLock(final ODocument iRecord) { final OClass cls = iRecord.getSchemaClass(); if (cls != null) { releaseModificationLock(iRecord, cls.getIndexes()); @@ -566,10 +572,13 @@ private static void releaseModificationLock(final ODocument iRecord) { /** * Releases the index modification lock. Avoids overhead of retrieving the schema class' indexes. */ - private static void releaseModificationLock(final ODocument iRecord, final Collection> iIndexes) { + private void releaseModificationLock(final ODocument iRecord, final Collection> iIndexes) { for (final OIndex index : iIndexes) { - index.getInternal().releaseModificationLock(); + if (lockedIndexes.contains(index.getName())) + index.getInternal().releaseModificationLock(); } + + lockedIndexes.clear(); } private static void checkIndexedPropertiesOnUpdate(final ODocument iRecord, final Collection> iIndexes) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OCompositeIndexDefinition.java b/core/src/main/java/com/orientechnologies/orient/core/index/OCompositeIndexDefinition.java index 1b25ddf8117..e1c92496ada 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OCompositeIndexDefinition.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OCompositeIndexDefinition.java @@ -31,13 +31,12 @@ import com.orientechnologies.orient.core.db.record.ORecordElement; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; -import com.orientechnologies.orient.core.type.ODocumentWrapperNoClass; /** * Index that consist of several indexDefinitions like {@link OPropertyIndexDefinition}. */ -public class OCompositeIndexDefinition extends ODocumentWrapperNoClass implements OIndexDefinition { +public class OCompositeIndexDefinition extends OAbstractIndexDefinition { private final List indexDefinitions; private String className; private int multiValueDefinitionIndex = -1; @@ -53,8 +52,6 @@ public OCompositeIndexDefinition() { * - name of class which is owner of this index */ public OCompositeIndexDefinition(final String iClassName) { - super(new ODocument()); - indexDefinitions = new ArrayList(5); className = iClassName; } @@ -68,8 +65,6 @@ public OCompositeIndexDefinition(final String iClassName) { * List of indexDefinitions to add in given index. */ public OCompositeIndexDefinition(final String iClassName, final List iIndexes) { - super(new ODocument()); - indexDefinitions = new ArrayList(5); for (OIndexDefinition indexDefinition : iIndexes) { indexDefinitions.add(indexDefinition); @@ -369,6 +364,7 @@ public ODocument toStream() { } finally { document.setInternalStatus(ORecordElement.STATUS.LOADED); } + document.field("collate", collate.getName()); return document; } @@ -428,6 +424,8 @@ protected void fromStream() { multiValueDefinitionIndex = indexDefinitions.size() - 1; } + setCollate((String) document.field("collate")); + } catch (final ClassNotFoundException e) { throw new OIndexException("Error during composite index deserialization", e); } catch (final NoSuchMethodException e) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndex.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndex.java index fa2cc5915e0..828225874c3 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndex.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndex.java @@ -104,20 +104,11 @@ OIndex create(String name, OIndexDefinition indexDefinition, String clusterIn /** * Removes an entry by its key. * - * @param iKey + * @param key * The entry's key to remove * @return True if the entry has been found and removed, otherwise false */ - boolean remove(Object iKey); - - /** - * Removes a value in all the index entries. - * - * @param iRID - * Record id to search - * @return Times the record was found, 0 if not found at all - */ - int remove(OIdentifiable iRID); + boolean remove(Object key); /** * Removes an entry by its key and value. @@ -165,6 +156,8 @@ OIndex create(String name, OIndexDefinition indexDefinition, String clusterIn */ OIndex delete(); + void deleteWithoutIndexLoad(String indexName); + /** * Returns the index name. * @@ -241,14 +234,6 @@ OIndex create(String name, OIndexDefinition indexDefinition, String clusterIn */ Set getClusters(); - /** - * Commits changes as atomic. It's called during the transaction's commit. - * - * @param iDocument - * Collection of entries to commit - */ - void commit(ODocument iDocument); - /** * Returns an iterator to walk across all the index items from the first to the latest one. * diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstract.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstract.java index 84db09c9640..8fca1b61f82 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstract.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstract.java @@ -17,8 +17,17 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Map.Entry; +import java.util.NoSuchElementException; +import java.util.Set; import com.orientechnologies.common.collection.OCompositeKey; import com.orientechnologies.common.concur.lock.OModificationLock; @@ -32,7 +41,7 @@ import com.orientechnologies.orient.core.db.record.ODatabaseRecord; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.db.record.ORecordElement; -import com.orientechnologies.orient.core.db.record.ridset.sbtree.OSBTreeIndexRIDContainer; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainer; import com.orientechnologies.orient.core.exception.OCommandExecutionException; import com.orientechnologies.orient.core.exception.OConfigurationException; import com.orientechnologies.orient.core.exception.OTransactionException; @@ -57,27 +66,34 @@ * */ public abstract class OIndexAbstract extends OSharedResourceAdaptiveExternal implements OIndexInternal { - protected final OModificationLock modificationLock = new OModificationLock(); + protected final OModificationLock modificationLock = new OModificationLock(); - protected static final String CONFIG_MAP_RID = "mapRid"; - protected static final String CONFIG_CLUSTERS = "clusters"; + protected static final String CONFIG_MAP_RID = "mapRid"; + protected static final String CONFIG_CLUSTERS = "clusters"; - private String name; - protected String type; - private String algorithm; - protected String valueContainerAlgorithm; + private String name; + protected String type; + private String algorithm; + protected String valueContainerAlgorithm; - protected final OIndexEngine indexEngine; - private Set clustersToIndex = new HashSet(); - private OIndexDefinition indexDefinition; - private final String databaseName; + protected final OIndexEngine indexEngine; + private Set clustersToIndex = new HashSet(); + private OIndexDefinition indexDefinition; + private final String databaseName; @ODocumentInstance - protected ODocument configuration; + protected ODocument configuration; - private volatile boolean rebuilding = false; + private volatile boolean rebuilding = false; - private Thread rebuildThread = null; + private Thread rebuildThread = null; + + private ThreadLocal txSnapshot = new ThreadLocal() { + @Override + protected IndexTxSnapshot initialValue() { + return new IndexTxSnapshot(); + } + }; public OIndexAbstract(final String type, String algorithm, final OIndexEngine indexEngine, String valueContainerAlgorithm) { super(OGlobalConfiguration.ENVIRONMENT_CONCURRENT.getValueAsBoolean(), OGlobalConfiguration.MVRBTREE_TIMEOUT @@ -96,6 +112,12 @@ public OIndexAbstract(final String type, String algorithm, final OIndexEngine } } + protected Object getCollatingValue(final Object key) { + if (key != null && getDefinition() != null) + return getDefinition().getCollate().transform(key); + return key; + } + public void flush() { acquireSharedLock(); try { @@ -254,14 +276,16 @@ public IndexMetadata loadMetadata(ODocument config) { } } - final Set clusters = new HashSet((Collection) config.field(CONFIG_CLUSTERS)); + final Set clusters = new HashSet((Collection) config.field(CONFIG_CLUSTERS, OType.EMBEDDEDSET)); return new IndexMetadata(indexName, loadedIndexDefinition, clusters, type, algorithm, valueContainerAlgorithm); } - public boolean contains(final Object key) { + public boolean contains(Object key) { checkForRebuild(); + key = getCollatingValue(key); + acquireSharedLock(); try { return indexEngine.contains(key); @@ -311,12 +335,12 @@ public Collection getValuesMajor(final Object fromKey, final bool final Set result = new HashSet(); getValuesMajor(fromKey, isInclusive, new IndexValuesResultListener() { - @Override - public boolean addResult(OIdentifiable value) { - result.add(value); - return true; - } - }); + @Override + public boolean addResult(OIdentifiable value) { + result.add(value); + return true; + } + }); return result; } @@ -327,12 +351,12 @@ public Collection getValuesMinor(final Object toKey, final boolea final Set result = new HashSet(); getValuesMinor(toKey, isInclusive, new IndexValuesResultListener() { - @Override - public boolean addResult(OIdentifiable value) { - result.add(value); - return true; - } - }); + @Override + public boolean addResult(OIdentifiable value) { + result.add(value); + return true; + } + }); return result; } @@ -343,12 +367,12 @@ public Collection getEntriesMajor(final Object fromKey, final boolean final Set result = new ODocumentFieldsHashSet(); getEntriesMajor(fromKey, isInclusive, new IndexEntriesResultListener() { - @Override - public boolean addResult(ODocument entry) { - result.add(entry); - return true; - } - }); + @Override + public boolean addResult(ODocument entry) { + result.add(entry); + return true; + } + }); return result; } @@ -359,12 +383,12 @@ public Collection getEntriesMinor(final Object toKey, final boolean i final Set result = new ODocumentFieldsHashSet(); getEntriesMinor(toKey, isInclusive, new IndexEntriesResultListener() { - @Override - public boolean addResult(ODocument entry) { - result.add(entry); - return true; - } - }); + @Override + public boolean addResult(ODocument entry) { + result.add(entry); + return true; + } + }); return result; } @@ -385,35 +409,41 @@ public boolean addResult(ODocument entry) { * @return Returns a set of records with key between the range passed as parameter. * @see com.orientechnologies.common.collection.OCompositeKey#compareTo(com.orientechnologies.common.collection.OCompositeKey) */ - public Collection getValuesBetween(final Object iRangeFrom, final boolean iFromInclusive, final Object iRangeTo, + public Collection getValuesBetween(Object iRangeFrom, final boolean iFromInclusive, Object iRangeTo, final boolean iToInclusive) { checkForRebuild(); + iRangeFrom = getCollatingValue(iRangeFrom); + iRangeTo = getCollatingValue(iRangeTo); + final Set result = new HashSet(); getValuesBetween(iRangeFrom, iFromInclusive, iRangeTo, iToInclusive, new IndexValuesResultListener() { - @Override - public boolean addResult(OIdentifiable value) { - result.add(value); - return true; - } - }); + @Override + public boolean addResult(OIdentifiable value) { + result.add(value); + return true; + } + }); return result; } - public Collection getEntriesBetween(final Object iRangeFrom, final Object iRangeTo, final boolean iInclusive) { + public Collection getEntriesBetween(Object iRangeFrom, Object iRangeTo, final boolean iInclusive) { checkForRebuild(); + iRangeFrom = getCollatingValue(iRangeFrom); + iRangeTo = getCollatingValue(iRangeTo); + final Set result = new ODocumentFieldsHashSet(); getEntriesBetween(iRangeFrom, iRangeTo, iInclusive, new IndexEntriesResultListener() { - @Override - public boolean addResult(ODocument entry) { - result.add(entry); - return true; - } - }); + @Override + public boolean addResult(ODocument entry) { + result.add(entry); + return true; + } + }); return result; } @@ -424,13 +454,13 @@ public Collection getValues(final Collection iKeys) { final Set result = new HashSet(); getValues(iKeys, new IndexValuesResultListener() { - @Override - public boolean addResult(OIdentifiable value) { - result.add(value); + @Override + public boolean addResult(OIdentifiable value) { + result.add(value); - return true; - } - }); + return true; + } + }); return result; } @@ -441,12 +471,12 @@ public Collection getEntries(final Collection iKeys) { final Set result = new ODocumentFieldsHashSet(); getEntries(iKeys, new IndexEntriesResultListener() { - @Override - public boolean addResult(ODocument entry) { - result.add(entry); - return true; - } - }); + @Override + public boolean addResult(ODocument entry) { + result.add(entry); + return true; + } + }); return result; } @@ -597,24 +627,6 @@ public boolean remove(final Object key, final OIdentifiable value) { } - @Override - public int remove(OIdentifiable iRID) { - checkForRebuild(); - - modificationLock.requestModificationLock(); - - try { - acquireExclusiveLock(); - try { - return indexEngine.removeValue(iRID, null); - } finally { - releaseExclusiveLock(); - } - } finally { - modificationLock.releaseModificationLock(); - } - } - public boolean remove(final Object key) { checkForRebuild(); @@ -664,7 +676,7 @@ public OIndexInternal delete() { if (storage instanceof OStorageLocal) { final ODiskCache diskCache = ((OStorageLocal) storage).getDiskCache(); try { - final String fileName = getName() + OSBTreeIndexRIDContainer.INDEX_FILE_EXTENSION; + final String fileName = getName() + OIndexRIDContainer.INDEX_FILE_EXTENSION; if (diskCache.exists(fileName)) { final long fileId = diskCache.openFile(fileName); diskCache.deleteFile(fileId); @@ -685,6 +697,21 @@ public OIndexInternal delete() { } } + @Override + public void deleteWithoutIndexLoad(String indexName) { + modificationLock.requestModificationLock(); + try { + acquireExclusiveLock(); + try { + indexEngine.deleteWithoutLoad(indexName); + } finally { + releaseExclusiveLock(); + } + } finally { + modificationLock.releaseModificationLock(); + } + } + public Iterator> iterator() { checkForRebuild(); @@ -749,10 +776,10 @@ public Set getClusters() { } } - public OIndexAbstract addCluster(final String iClusterName) { + public OIndexAbstract addCluster(final String clusterName) { acquireExclusiveLock(); try { - if (clustersToIndex.add(iClusterName)) + if (clustersToIndex.add(clusterName)) updateConfiguration(); return this; } finally { @@ -821,61 +848,59 @@ public ODocument updateConfiguration() { } @SuppressWarnings("unchecked") - public void commit(final ODocument document) { + public void addTxOperation(final ODocument operationDocument) { checkForRebuild(); - if (document == null) + if (operationDocument == null) return; acquireExclusiveLock(); try { indexEngine.startTransaction(); - final Boolean clearAll = document.field("clear"); - if (clearAll != null && clearAll) - clear(); + final IndexTxSnapshot indexTxSnapshot = txSnapshot.get(); - final Collection entries = document.field("entries"); + final Boolean clearAll = operationDocument.field("clear"); + if (clearAll != null && clearAll) { + indexTxSnapshot.clear = true; + indexTxSnapshot.indexSnapshot.clear(); + } + final Collection entries = operationDocument.field("entries"); + final Map snapshot = indexTxSnapshot.indexSnapshot; for (final ODocument entry : entries) { final String serializedKey = OStringSerializerHelper.decode((String) entry.field("k")); final Object key; try { - if (serializedKey.equals("*")) - key = "*"; - else { - final ODocument keyContainer = new ODocument(); - keyContainer.setLazyLoad(false); - - keyContainer.fromString(serializedKey); - - final Object storedKey = keyContainer.field("key"); - if (storedKey instanceof List) - key = new OCompositeKey((List>) storedKey); - else if (Boolean.TRUE.equals(keyContainer.field("binary"))) { - key = OStreamSerializerAnyStreamable.INSTANCE.fromStream((byte[]) storedKey); - } else - key = storedKey; - } + final ODocument keyContainer = new ODocument(); + keyContainer.setLazyLoad(false); + + keyContainer.fromString(serializedKey); + + final Object storedKey = keyContainer.field("key"); + if (storedKey instanceof List) + key = new OCompositeKey((List>) storedKey); + else if (Boolean.TRUE.equals(keyContainer.field("binary"))) { + key = OStreamSerializerAnyStreamable.INSTANCE.fromStream((byte[]) storedKey); + } else + key = storedKey; } catch (IOException ioe) { throw new OTransactionException("Error during index changes deserialization. ", ioe); } - final List operations = (List) entry.field("ops"); + final List operations = entry.field("ops"); if (operations != null) { for (final ODocument op : operations) { final int operation = (Integer) op.rawField("o"); final OIdentifiable value = op.field("v", OType.LINK); if (operation == OPERATION.PUT.ordinal()) - put(key, value); + putInSnapshot(key, value, snapshot); else if (operation == OPERATION.REMOVE.ordinal()) { - if (key.equals("*")) - remove(value); - else if (value == null) - remove(key); + if (value == null) + removeFromSnapshot(key, snapshot); else { - remove(key, value); + removeFromSnapshot(key, value, snapshot); } } @@ -889,6 +914,40 @@ else if (value == null) } } + @Override + public void commit() { + acquireExclusiveLock(); + try { + final IndexTxSnapshot indexTxSnapshot = txSnapshot.get(); + if (indexTxSnapshot.clear) + clear(); + + commitSnapshot(indexTxSnapshot.indexSnapshot); + } finally { + releaseExclusiveLock(); + } + } + + @Override + public void preCommit() { + txSnapshot.set(new IndexTxSnapshot()); + } + + @Override + public void postCommit() { + txSnapshot.set(new IndexTxSnapshot()); + } + + protected abstract void commitSnapshot(Map snapshot); + + protected abstract void putInSnapshot(Object key, OIdentifiable value, Map snapshot); + + protected abstract void removeFromSnapshot(Object key, OIdentifiable value, Map snapshot); + + protected void removeFromSnapshot(Object key, Map snapshot) { + snapshot.put(key, RemovedValue.INSTANCE); + } + public ODocument getConfiguration() { acquireSharedLock(); try { @@ -1059,4 +1118,13 @@ protected void checkForRebuild() { throw new OIndexException("Index " + name + " is rebuilding now and can not be used."); } } + + protected static final class RemovedValue { + public static final RemovedValue INSTANCE = new RemovedValue(); + } + + protected static final class IndexTxSnapshot { + public Map indexSnapshot = new HashMap(); + public boolean clear = false; + } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstractDelegate.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstractDelegate.java index 094843d51dd..f78134e25fd 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstractDelegate.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexAbstractDelegate.java @@ -88,13 +88,8 @@ public OIndex put(final Object iKey, final OIdentifiable iValue) { return delegate.put(iKey, iValue); } - public boolean remove(final Object iKey) { - return delegate.remove(iKey); - } - - @Override - public int remove(OIdentifiable iRID) { - return delegate.remove(iRID); + public boolean remove(final Object key) { + return delegate.remove(key); } public boolean remove(final Object iKey, final OIdentifiable iRID) { @@ -160,6 +155,11 @@ public OIndex delete() { return delegate.delete(); } + @Override + public void deleteWithoutIndexLoad(String indexName) { + delegate.deleteWithoutIndexLoad(indexName); + } + public String getName() { return delegate.getName(); } @@ -180,10 +180,6 @@ public ORID getIdentity() { return delegate.getIdentity(); } - public void commit(final ODocument iDocument) { - delegate.commit(iDocument); - } - public void unload() { delegate.unload(); } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDefinition.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDefinition.java index 74c5e333b01..e75511eb94e 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDefinition.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDefinition.java @@ -17,6 +17,7 @@ import java.util.List; +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; @@ -120,4 +121,8 @@ public interface OIndexDefinition extends OIndexCallback { public String toCreateIndexDDL(String indexName, String indexType); public boolean isAutomatic(); + + public OCollate getCollate(); + + public void setCollate(OCollate iCollate); } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDictionary.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDictionary.java index 5df282b3954..bdf001e03a7 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDictionary.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexDictionary.java @@ -15,6 +15,8 @@ */ package com.orientechnologies.orient.core.index; +import java.util.Map; + import com.orientechnologies.orient.core.db.record.OIdentifiable; /** @@ -30,18 +32,16 @@ public OIndexDictionary(String typeId, String algorithm, OIndexEngine snapshot) { + key = getCollatingValue(key); + snapshot.put(key, value.getIdentity()); + } + + @Override + protected void removeFromSnapshot(Object key, OIdentifiable value, Map snapshot) { + key = getCollatingValue(key); + snapshot.put(key, RemovedValue.INSTANCE); + } + + @Override + protected void commitSnapshot(Map snapshot) { + for (Map.Entry snapshotEntry : snapshot.entrySet()) { + Object key = snapshotEntry.getKey(); + checkForKeyType(key); + + Object snapshotValue = snapshotEntry.getValue(); + if (snapshotValue.equals(RemovedValue.INSTANCE)) + indexEngine.remove(key); + else + indexEngine.put(key, (OIdentifiable) snapshotValue); + } + } + /** * Disables check of entries. */ diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexEngine.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexEngine.java index ec01d82ec74..a382691c43c 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexEngine.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexEngine.java @@ -23,6 +23,8 @@ void create(String indexName, OIndexDefinition indexDefinition, String clusterIn void delete(); + void deleteWithoutLoad(String indexName); + void load(ORID indexRid, String indexName, OIndexDefinition indexDefinition, boolean isAutomatic); boolean contains(Object key); @@ -63,8 +65,6 @@ void create(String indexName, OIndexDefinition indexDefinition, String clusterIn void put(Object key, V value); - int removeValue(OIdentifiable value, ValuesTransformer transformer); - void getValuesBetween(Object rangeFrom, boolean fromInclusive, Object rangeTo, boolean toInclusive, ValuesTransformer transformer, ValuesResultListener valuesResultListener); diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexFullText.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexFullText.java index af0f1761f9b..1b742466101 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexFullText.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexFullText.java @@ -18,12 +18,13 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import com.orientechnologies.common.listener.OProgressListener; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.db.record.ORecordElement; -import com.orientechnologies.orient.core.db.record.ridset.sbtree.OSBTreeIndexRIDContainer; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainer; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper; import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializer; @@ -60,12 +61,14 @@ public OIndexFullText(String typeId, String algorithm, OIndexEngine snapshot) { + if (key == null) + return; + + key = getCollatingValue(key); + + final List words = splitIntoWords(key.toString()); + + // FOREACH WORD CREATE THE LINK TO THE CURRENT DOCUMENT + for (final String word : words) { + Set refs; + + final Object snapshotValue = snapshot.get(word); + if (snapshotValue == null) + refs = indexEngine.get(word); + else if (snapshotValue.equals(RemovedValue.INSTANCE)) + refs = null; + else + refs = (Set) snapshotValue; + + if (refs == null) { + // WORD NOT EXISTS: CREATE THE KEYWORD CONTAINER THE FIRST TIME THE WORD IS FOUND + if (ODefaultIndexFactory.SBTREEBONSAI_VALUE_CONTAINER.equals(valueContainerAlgorithm)) { + refs = new OIndexRIDContainer(getName()); + } else { + refs = new OMVRBTreeRIDSet(); + ((OMVRBTreeRIDSet) refs).setAutoConvertToRecord(false); + } + + snapshot.put(word, refs); + } + // ADD THE CURRENT DOCUMENT AS REF FOR THAT WORD + refs.add(value.getIdentity()); + } + } + /** * Splits passed in key on several words and remove records with keys equals to any item of split result and values equals to * passed in value. @@ -118,9 +158,11 @@ public OIndexFullText put(final Object key, final OIdentifiable iSingleValue) { * @return true if at least one record is removed. */ @Override - public boolean remove(final Object key, final OIdentifiable value) { + public boolean remove(Object key, final OIdentifiable value) { checkForRebuild(); + key = getCollatingValue(key); + modificationLock.requestModificationLock(); try { @@ -152,6 +194,32 @@ public boolean remove(final Object key, final OIdentifiable value) { } } + @Override + protected void removeFromSnapshot(Object key, OIdentifiable value, Map snapshot) { + key = getCollatingValue(key); + + final List words = splitIntoWords(key.toString()); + for (final String word : words) { + final Set recs; + final Object snapshotValue = snapshot.get(word); + if (snapshotValue == null) + recs = indexEngine.get(word); + else if (snapshotValue.equals(RemovedValue.INSTANCE)) + recs = null; + else + recs = (Set) snapshotValue; + + if (recs != null && !recs.isEmpty()) { + if (recs.remove(value)) { + if (recs.isEmpty()) + snapshot.put(word, RemovedValue.INSTANCE); + else + snapshot.put(word, recs); + } + } + } + } + @Override public OIndexInternal create(String name, OIndexDefinition indexDefinition, String clusterIndexName, Set clustersToIndex, boolean rebuild, OProgressListener progressListener, OStreamSerializer valueSerializer) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexInternal.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexInternal.java index c7ea8ab37c8..1ab7d60e859 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexInternal.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexInternal.java @@ -81,8 +81,6 @@ public interface OIndexInternal extends OIndex, Iterable> * @return {@code true} if given index can be used to calculate result of * {@link com.orientechnologies.orient.core.sql.operator.OQueryOperatorEquality} operators. * - * @see com.orientechnologies.orient.core.sql.operator.OQueryOperator#executeIndexQuery(com.orientechnologies.orient.core.command. - * OCommandContext, OIndex */ public boolean canBeUsedInEqualityOperators(); @@ -121,6 +119,14 @@ public interface OIndexInternal extends OIndex, Iterable> public String getAlgorithm(); + public void preCommit(); + + void addTxOperation(ODocument operationDocument); + + public void commit(); + + public void postCommit(); + public final class IndexMetadata { private final String name; private final OIndexDefinition indexDefinition; diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManager.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManager.java index e443af5a435..3c45fd1d680 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManager.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManager.java @@ -120,5 +120,7 @@ public OIndex createIndex(final String iName, final String iType, OIndexDefin public void waitTillIndexRestore(); - public boolean autoRecreateIndexesAfterCrash(); + public boolean autoRecreateIndexesAfterCrash(); + + public void addClusterToIndex(String clusterName, String indexName); } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerAbstract.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerAbstract.java index a53b9c70b16..aad3740bf8d 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerAbstract.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerAbstract.java @@ -185,6 +185,16 @@ public OIndex getIndex(final String iName) { return preProcessBeforeReturn(index); } + @Override + public void addClusterToIndex(String clusterName, String indexName) { + final OIndex index = indexes.get(indexName.toLowerCase()); + if (index == null) + throw new OIndexException("Index with name " + indexName + " does not exist."); + + index.getInternal().addCluster(clusterName); + save(); + } + public boolean existsIndex(final String iName) { return indexes.containsKey(iName.toLowerCase()); } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerProxy.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerProxy.java index d341ffa8cb0..ab4b505e111 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerProxy.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerProxy.java @@ -135,4 +135,9 @@ public void waitTillIndexRestore() { public boolean autoRecreateIndexesAfterCrash() { return delegate.autoRecreateIndexesAfterCrash(); } + + @Override + public void addClusterToIndex(String clusterName, String indexName) { + delegate.addClusterToIndex(clusterName, indexName); + } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerShared.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerShared.java index ce650f77f2c..6bd82b8e4e7 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerShared.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexManagerShared.java @@ -404,6 +404,9 @@ public void run() { if (indexName != null && indexDefinition != null && clusters != null && !clusters.isEmpty() && type != null) { OLogManager.instance().info(this, "Start creation of index %s", indexName); + if (algorithm.equals(ODefaultIndexFactory.SBTREE_ALGORITHM) || indexType.endsWith("HASH_INDEX")) + index.deleteWithoutIndexLoad(indexName); + index.create(indexName, indexDefinition, defaultClusterName, clusters, false, new OIndexRebuildOutputListener( index)); @@ -433,7 +436,7 @@ public void run() { } } catch (Exception e) { - OLogManager.instance().error(this, "Error during addition of index %s", idx); + OLogManager.instance().error(this, "Error during addition of index %s", e, idx); errors++; } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexMultiValues.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexMultiValues.java index 20762fb98c1..35c0d144364 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexMultiValues.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexMultiValues.java @@ -15,7 +15,14 @@ */ package com.orientechnologies.orient.core.index; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; import com.orientechnologies.common.collection.OMultiCollectionIterator; import com.orientechnologies.common.comparator.ODefaultComparator; @@ -23,7 +30,7 @@ import com.orientechnologies.common.listener.OProgressListener; import com.orientechnologies.orient.core.config.OGlobalConfiguration; import com.orientechnologies.orient.core.db.record.OIdentifiable; -import com.orientechnologies.orient.core.db.record.ridset.sbtree.OSBTreeIndexRIDContainer; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainer; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.ORecord; import com.orientechnologies.orient.core.record.impl.ODocument; @@ -44,9 +51,11 @@ public OIndexMultiValues(final String type, String algorithm, OIndexEngine get(final Object key) { + public Set get(Object key) { checkForRebuild(); + key = getCollatingValue(key); + acquireSharedLock(); try { @@ -62,9 +71,11 @@ public Set get(final Object key) { } } - public long count(final Object key) { + public long count(Object key) { checkForRebuild(); + key = getCollatingValue(key); + acquireSharedLock(); try { @@ -80,9 +91,11 @@ public long count(final Object key) { } } - public OIndexMultiValues put(final Object key, final OIdentifiable iSingleValue) { + public OIndexMultiValues put(Object key, final OIdentifiable iSingleValue) { checkForRebuild(); + key = getCollatingValue(key); + modificationLock.requestModificationLock(); try { acquireExclusiveLock(); @@ -92,7 +105,7 @@ public OIndexMultiValues put(final Object key, final OIdentifiable iSingleValue) if (values == null) { if (ODefaultIndexFactory.SBTREEBONSAI_VALUE_CONTAINER.equals(valueContainerAlgorithm)) { - values = new OSBTreeIndexRIDContainer(getName()); + values = new OIndexRIDContainer(getName()); } else { values = new OMVRBTreeRIDSet(OGlobalConfiguration.MVRBTREE_RID_BINARY_THRESHOLD.getValueAsInteger()); ((OMVRBTreeRIDSet) values).setAutoConvertToRecord(false); @@ -115,21 +128,42 @@ public OIndexMultiValues put(final Object key, final OIdentifiable iSingleValue) } } - public int remove(final OIdentifiable iRecord) { - checkForRebuild(); + @Override + protected void putInSnapshot(Object key, OIdentifiable value, final Map snapshot) { + key = getCollatingValue(key); - acquireExclusiveLock(); - try { - return indexEngine.removeValue(iRecord, MultiValuesTransformer.INSTANCE); - } finally { - releaseExclusiveLock(); + Object snapshotValue = snapshot.get(key); + + Set values; + if (snapshotValue == null) + values = indexEngine.get(key); + else if (snapshotValue.equals(RemovedValue.INSTANCE)) + values = null; + else + values = (Set) snapshotValue; + + if (values == null) { + if (ODefaultIndexFactory.SBTREEBONSAI_VALUE_CONTAINER.equals(valueContainerAlgorithm)) { + values = new OIndexRIDContainer(getName()); + } else { + values = new OMVRBTreeRIDSet(OGlobalConfiguration.MVRBTREE_RID_BINARY_THRESHOLD.getValueAsInteger()); + ((OMVRBTreeRIDSet) values).setAutoConvertToRecord(false); + } + + snapshot.put(key, values); } + + values.add(value.getIdentity()); + if (values instanceof OIndexRIDContainer && ((OIndexRIDContainer) values).isEmbedded()) + snapshot.put(key, values); } @Override - public boolean remove(final Object key, final OIdentifiable value) { + public boolean remove(Object key, final OIdentifiable value) { checkForRebuild(); + key = getCollatingValue(key); + modificationLock.requestModificationLock(); try { @@ -158,6 +192,45 @@ public boolean remove(final Object key, final OIdentifiable value) { } } + @Override + protected void removeFromSnapshot(Object key, final OIdentifiable value, final Map snapshot) { + key = getCollatingValue(key); + + final Object snapshotValue = snapshot.get(key); + + Set values; + if (snapshotValue == null) + values = indexEngine.get(key); + else if (snapshotValue.equals(RemovedValue.INSTANCE)) + values = null; + else + values = (Set) snapshotValue; + + if (values == null) + return; + + if (values.remove(value)) { + if (values.isEmpty()) + snapshot.put(key, RemovedValue.INSTANCE); + else + snapshot.put(key, values); + } + } + + @Override + protected void commitSnapshot(Map snapshot) { + for (Map.Entry snapshotEntry : snapshot.entrySet()) { + Object key = snapshotEntry.getKey(); + Object value = snapshotEntry.getValue(); + checkForKeyType(key); + + if (value.equals(RemovedValue.INSTANCE)) + indexEngine.remove(key); + else + indexEngine.put(key, (Set) value); + } + } + public OIndexMultiValues create(final String name, final OIndexDefinition indexDefinition, final String clusterIndexName, final Set clustersToIndex, boolean rebuild, final OProgressListener progressListener) { final OStreamSerializer serializer; @@ -170,12 +243,16 @@ public OIndexMultiValues create(final String name, final OIndexDefinition indexD serializer); } - public void getValuesBetween(final Object rangeFrom, final boolean fromInclusive, final Object rangeTo, - final boolean toInclusive, final IndexValuesResultListener resultListener) { + public void getValuesBetween(Object iRangeFrom, final boolean fromInclusive, Object iRangeTo, final boolean toInclusive, + final IndexValuesResultListener resultListener) { checkForRebuild(); + + iRangeFrom = getCollatingValue(iRangeFrom); + iRangeTo = getCollatingValue(iRangeTo); + acquireSharedLock(); try { - indexEngine.getValuesBetween(rangeFrom, fromInclusive, rangeTo, toInclusive, MultiValuesTransformer.INSTANCE, + indexEngine.getValuesBetween(iRangeFrom, fromInclusive, iRangeTo, toInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.ValuesResultListener() { @Override public boolean addResult(OIdentifiable identifiable) { @@ -187,11 +264,14 @@ public boolean addResult(OIdentifiable identifiable) { } } - public void getValuesMajor(final Object fromKey, final boolean isInclusive, final IndexValuesResultListener valuesResultListener) { + public void getValuesMajor(Object iRangeFrom, final boolean isInclusive, final IndexValuesResultListener valuesResultListener) { checkForRebuild(); + + iRangeFrom = getCollatingValue(iRangeFrom); + acquireSharedLock(); try { - indexEngine.getValuesMajor(fromKey, isInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.ValuesResultListener() { + indexEngine.getValuesMajor(iRangeFrom, isInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.ValuesResultListener() { @Override public boolean addResult(OIdentifiable identifiable) { return valuesResultListener.addResult(identifiable); @@ -202,11 +282,14 @@ public boolean addResult(OIdentifiable identifiable) { } } - public void getValuesMinor(final Object toKey, final boolean isInclusive, final IndexValuesResultListener resultListener) { + public void getValuesMinor(Object iRangeTo, final boolean isInclusive, final IndexValuesResultListener resultListener) { checkForRebuild(); + + iRangeTo = getCollatingValue(iRangeTo); + acquireSharedLock(); try { - indexEngine.getValuesMinor(toKey, isInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.ValuesResultListener() { + indexEngine.getValuesMinor(iRangeTo, isInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.ValuesResultListener() { @Override public boolean addResult(OIdentifiable identifiable) { return resultListener.addResult(identifiable); @@ -225,7 +308,9 @@ public void getValues(final Collection iKeys, final IndexValuesResultListener acquireSharedLock(); try { - for (final Object key : sortedKeys) { + for (Object key : sortedKeys) { + key = getCollatingValue(key); + final Set values = indexEngine.get(key); if (values == null) @@ -244,29 +329,33 @@ public void getValues(final Collection iKeys, final IndexValuesResultListener } } - public void getEntriesMajor(final Object fromKey, final boolean isInclusive, - final IndexEntriesResultListener entriesResultListener) { + public void getEntriesMajor(Object iRangeFrom, final boolean isInclusive, final IndexEntriesResultListener entriesResultListener) { checkForRebuild(); + iRangeFrom = getCollatingValue(iRangeFrom); + acquireSharedLock(); try { - indexEngine.getEntriesMajor(fromKey, isInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.EntriesResultListener() { - @Override - public boolean addResult(ODocument entry) { - return entriesResultListener.addResult(entry); - } - }); + indexEngine.getEntriesMajor(iRangeFrom, isInclusive, MultiValuesTransformer.INSTANCE, + new OIndexEngine.EntriesResultListener() { + @Override + public boolean addResult(ODocument entry) { + return entriesResultListener.addResult(entry); + } + }); } finally { releaseSharedLock(); } } - public void getEntriesMinor(Object toKey, boolean isInclusive, final IndexEntriesResultListener entriesResultListener) { + public void getEntriesMinor(Object iRangeTo, boolean isInclusive, final IndexEntriesResultListener entriesResultListener) { checkForRebuild(); + iRangeTo = getCollatingValue(iRangeTo); + acquireSharedLock(); try { - indexEngine.getEntriesMinor(toKey, isInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.EntriesResultListener() { + indexEngine.getEntriesMinor(iRangeTo, isInclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.EntriesResultListener() { @Override public boolean addResult(ODocument entry) { return entriesResultListener.addResult(entry); @@ -277,19 +366,22 @@ public boolean addResult(ODocument entry) { } } - public void getEntriesBetween(Object rangeFrom, Object rangeTo, boolean inclusive, + public void getEntriesBetween(Object iRangeFrom, Object iRangeTo, boolean inclusive, final IndexEntriesResultListener indexEntriesResultListener) { checkForRebuild(); + iRangeFrom = getCollatingValue(iRangeFrom); + iRangeTo = getCollatingValue(iRangeTo); + final OType[] types = getDefinition().getTypes(); if (types.length == 1) { - rangeFrom = OType.convert(rangeFrom, types[0].getDefaultJavaType()); - rangeTo = OType.convert(rangeTo, types[0].getDefaultJavaType()); + iRangeFrom = OType.convert(iRangeFrom, types[0].getDefaultJavaType()); + iRangeTo = OType.convert(iRangeTo, types[0].getDefaultJavaType()); } acquireSharedLock(); try { - indexEngine.getEntriesBetween(rangeFrom, rangeTo, inclusive, MultiValuesTransformer.INSTANCE, + indexEngine.getEntriesBetween(iRangeFrom, iRangeTo, inclusive, MultiValuesTransformer.INSTANCE, new OIndexEngine.EntriesResultListener() { @Override public boolean addResult(ODocument entry) { @@ -302,22 +394,25 @@ public boolean addResult(ODocument entry) { } - public long count(Object rangeFrom, final boolean fromInclusive, Object rangeTo, final boolean toInclusive, + public long count(Object iRangeFrom, final boolean fromInclusive, Object iRangeTo, final boolean toInclusive, final int maxValuesToFetch) { checkForRebuild(); + iRangeFrom = getCollatingValue(iRangeFrom); + iRangeTo = getCollatingValue(iRangeTo); + final OType[] types = getDefinition().getTypes(); if (types.length == 1) { - rangeFrom = OType.convert(rangeFrom, types[0].getDefaultJavaType()); - rangeTo = OType.convert(rangeTo, types[0].getDefaultJavaType()); + iRangeFrom = OType.convert(iRangeFrom, types[0].getDefaultJavaType()); + iRangeTo = OType.convert(iRangeTo, types[0].getDefaultJavaType()); } - if (rangeFrom != null && rangeTo != null && rangeFrom.getClass() != rangeTo.getClass()) + if (iRangeFrom != null && iRangeTo != null && iRangeFrom.getClass() != iRangeTo.getClass()) throw new IllegalArgumentException("Range from-to parameters are of different types"); acquireSharedLock(); try { - return indexEngine.count(rangeFrom, fromInclusive, rangeTo, toInclusive, maxValuesToFetch, MultiValuesTransformer.INSTANCE); + return indexEngine.count(iRangeFrom, fromInclusive, iRangeTo, toInclusive, maxValuesToFetch, MultiValuesTransformer.INSTANCE); } finally { releaseSharedLock(); } @@ -331,7 +426,9 @@ public void getEntries(Collection iKeys, IndexEntriesResultListener resultLis acquireSharedLock(); try { - for (final Object key : sortedKeys) { + for (Object key : sortedKeys) { + key = getCollatingValue(key); + final Set values = indexEngine.get(key); if (values == null) diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexOneValue.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexOneValue.java index 81edd40e62a..7494a3156ec 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexOneValue.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexOneValue.java @@ -15,7 +15,12 @@ */ package com.orientechnologies.orient.core.index; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import com.orientechnologies.common.comparator.ODefaultComparator; import com.orientechnologies.common.concur.resource.OSharedResourceIterator; @@ -23,12 +28,12 @@ import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.OIdentifiable; +import com.orientechnologies.orient.core.engine.local.OEngineLocal; +import com.orientechnologies.orient.core.engine.memory.OEngineMemory; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerRID; import com.orientechnologies.orient.core.tx.OTransactionIndexChanges; -import com.orientechnologies.orient.core.tx.OTransactionIndexChanges.OPERATION; import com.orientechnologies.orient.core.tx.OTransactionIndexChangesPerKey; -import com.orientechnologies.orient.core.tx.OTransactionIndexChangesPerKey.OTransactionIndexEntry; /** * Abstract Index implementation that allows only one value for a key. @@ -41,9 +46,11 @@ public OIndexOneValue(final String type, String algorithm, OIndexEngine keys, final IndexValuesResultListener acquireSharedLock(); try { - for (final Object key : sortedKeys) { + for (Object key : sortedKeys) { + key = getCollatingValue(key); + final OIdentifiable val = indexEngine.get(key); if (val != null) { if (!resultListener.addResult(val)) @@ -170,13 +193,14 @@ public void getValues(final Collection keys, final IndexValuesResultListener } } - public void getEntriesMajor(final Object fromKey, final boolean isInclusive, - final IndexEntriesResultListener entriesResultListener) { + public void getEntriesMajor(Object iRangeFrom, final boolean isInclusive, final IndexEntriesResultListener entriesResultListener) { checkForRebuild(); + iRangeFrom = getCollatingValue(iRangeFrom); + acquireSharedLock(); try { - indexEngine.getEntriesMajor(fromKey, isInclusive, null, new OIndexEngine.EntriesResultListener() { + indexEngine.getEntriesMajor(iRangeFrom, isInclusive, null, new OIndexEngine.EntriesResultListener() { @Override public boolean addResult(ODocument entry) { return entriesResultListener.addResult(entry); @@ -188,12 +212,14 @@ public boolean addResult(ODocument entry) { } } - public void getEntriesMinor(final Object toKey, final boolean isInclusive, final IndexEntriesResultListener entriesResultListener) { + public void getEntriesMinor(Object iRangeTo, final boolean isInclusive, final IndexEntriesResultListener entriesResultListener) { checkForRebuild(); + iRangeTo = getCollatingValue(iRangeTo); + acquireSharedLock(); try { - indexEngine.getEntriesMinor(toKey, isInclusive, null, new OIndexEngine.EntriesResultListener() { + indexEngine.getEntriesMinor(iRangeTo, isInclusive, null, new OIndexEngine.EntriesResultListener() { @Override public boolean addResult(ODocument entry) { return entriesResultListener.addResult(entry); @@ -204,16 +230,19 @@ public boolean addResult(ODocument entry) { } } - public void getEntriesBetween(final Object rangeFrom, final Object rangeTo, final boolean inclusive, + public void getEntriesBetween(Object iRangeFrom, Object iRangeTo, final boolean inclusive, final IndexEntriesResultListener entriesResultListener) { checkForRebuild(); - if (rangeFrom.getClass() != rangeTo.getClass()) + if (iRangeFrom.getClass() != iRangeTo.getClass()) throw new IllegalArgumentException("Range from-to parameters are of different types"); + iRangeFrom = getCollatingValue(iRangeFrom); + iRangeTo = getCollatingValue(iRangeTo); + acquireSharedLock(); try { - indexEngine.getEntriesBetween(rangeFrom, rangeTo, inclusive, null, new OIndexEngine.EntriesResultListener() { + indexEngine.getEntriesBetween(iRangeFrom, iRangeTo, inclusive, null, new OIndexEngine.EntriesResultListener() { @Override public boolean addResult(ODocument entry) { return entriesResultListener.addResult(entry); @@ -232,7 +261,9 @@ public void getEntries(final Collection keys, IndexEntriesResultListener resu acquireSharedLock(); try { - for (final Object key : sortedKeys) { + for (Object key : sortedKeys) { + key = getCollatingValue(key); + final OIdentifiable val = indexEngine.get(key); if (val != null) { final ODocument document = new ODocument(); @@ -260,13 +291,16 @@ public long getSize() { } } - public long count(final Object iRangeFrom, final boolean iFromInclusive, final Object iRangeTo, final boolean iToInclusive, + public long count(Object iRangeFrom, final boolean iFromInclusive, Object iRangeTo, final boolean iToInclusive, final int maxValuesToFetch) { checkForRebuild(); if (iRangeFrom != null && iRangeTo != null && iRangeFrom.getClass() != iRangeTo.getClass()) throw new IllegalArgumentException("Range from-to parameters are of different types"); + iRangeFrom = getCollatingValue(iRangeFrom); + iRangeTo = getCollatingValue(iRangeTo); + acquireSharedLock(); try { return indexEngine.count(iRangeFrom, iFromInclusive, iRangeTo, iToInclusive, maxValuesToFetch, null); @@ -297,7 +331,6 @@ public Iterator valuesIterator() { } } - @SuppressWarnings({ "rawtypes", "unchecked" }) public Iterator valuesInverseIterator() { checkForRebuild(); diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexRemote.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexRemote.java index 514de1f3b2f..54eb451f9d3 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexRemote.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexRemote.java @@ -104,6 +104,11 @@ public OIndexRemote delete() { return this; } + @Override + public void deleteWithoutIndexLoad(String indexName) { + throw new UnsupportedOperationException("deleteWithoutIndexLoad"); + } + public String getDatabaseName() { return databaseName; } @@ -231,9 +236,9 @@ public OIndexRemote put(final Object iKey, final OIdentifiable iValue) { return this; } - public boolean remove(final Object iKey) { + public boolean remove(final Object key) { final OCommandRequest cmd = formatCommand(QUERY_REMOVE, name); - return ((Integer) getDatabase().command(cmd).execute(iKey)) > 0; + return ((Integer) getDatabase().command(cmd).execute(key)) > 0; } public boolean remove(final Object iKey, final OIdentifiable iRID) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAware.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAware.java index 2f66fc313de..0fc62d6e321 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAware.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAware.java @@ -79,8 +79,8 @@ public OIndexTxAware put(final Object iKey, final OIdentifiable iValue) { } @Override - public boolean remove(final Object iKey) { - database.getTransaction().addIndexEntry(delegate, super.getName(), OPERATION.REMOVE, iKey, null); + public boolean remove(final Object key) { + database.getTransaction().addIndexEntry(delegate, super.getName(), OPERATION.REMOVE, key, null); return true; } @@ -90,12 +90,6 @@ public boolean remove(final Object iKey, final OIdentifiable iRID) { return true; } - @Override - public int remove(final OIdentifiable iRID) { - database.getTransaction().addIndexEntry(delegate, super.getName(), OPERATION.REMOVE, null, iRID); - return 1; - } - @Override public OIndexTxAware clear() { database.getTransaction().addIndexEntry(delegate, super.getName(), OPERATION.CLEAR, null, null); diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareMultiValue.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareMultiValue.java index ec3cf37f4a3..ea254282c8a 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareMultiValue.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareMultiValue.java @@ -15,11 +15,7 @@ */ package com.orientechnologies.orient.core.index; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; import com.orientechnologies.orient.core.db.record.ODatabaseRecord; import com.orientechnologies.orient.core.db.record.OIdentifiable; @@ -42,21 +38,23 @@ public OIndexTxAwareMultiValue(final ODatabaseRecord iDatabase, final OIndex get(final Object iKey) { + public Collection get(final Object key) { final OTransactionIndexChanges indexChanges = database.getTransaction().getIndexChanges(delegate.getName()); + if (indexChanges == null) + return super.get(key); final Set result = new TreeSet(); - if (indexChanges == null || !indexChanges.cleared) { + if (!indexChanges.cleared) { // BEGIN FROM THE UNDERLYING RESULT SET - final Collection subResult = super.get(iKey); + final Collection subResult = super.get(key); if (subResult != null) for (OIdentifiable oid : subResult) if (oid != null) result.add(oid); } - return filterIndexChanges(indexChanges, iKey, result); + return filterIndexChanges(indexChanges, key, result); } @Override @@ -184,26 +182,6 @@ protected Collection filterIndexChanges(final OTransactionIndexCh } } } - - if (indexChanges.containsChangesCrossKey()) { - final OTransactionIndexChangesPerKey value = indexChanges.getChangesCrossKey(); - if (value != null) { - for (final OTransactionIndexEntry entry : value.entries) { - if (entry.operation == OPERATION.REMOVE) { - if (entry.value == null) { - // REMOVE THE ENTIRE KEY, SO RESULT SET IS EMPTY - keyResult.clear(); - break; - } else - // REMOVE ONLY THIS RID - keyResult.remove(entry.value); - } else if (entry.operation == OPERATION.PUT) { - // ADD ALSO THIS RID - keyResult.add(entry.value); - } - } - } - } return keyResult; } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareOneValue.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareOneValue.java index d4ca3206aaf..d3e2d1d717b 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareOneValue.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexTxAwareOneValue.java @@ -15,13 +15,15 @@ */ package com.orientechnologies.orient.core.index; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.*; +import com.orientechnologies.common.collection.OAlwaysGreaterKey; +import com.orientechnologies.common.collection.OAlwaysLessKey; +import com.orientechnologies.common.collection.OCompositeKey; import com.orientechnologies.orient.core.db.record.ODatabaseRecord; import com.orientechnologies.orient.core.db.record.OIdentifiable; +import com.orientechnologies.orient.core.engine.local.OEngineLocal; +import com.orientechnologies.orient.core.engine.memory.OEngineMemory; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.storage.ORecordDuplicatedException; import com.orientechnologies.orient.core.tx.OTransactionIndexChanges; @@ -44,45 +46,53 @@ public OIndexTxAwareOneValue(final ODatabaseRecord iDatabase, final OIndex getValues(final Collection iKeys) { } final Set keysToRemove = new HashSet(); + final Map keyValueEntries = new HashMap(); + for (final Object key : keys) { if (indexChanges.cleared) keysToRemove.add(key); - final OIdentifiable keyResult = filterIndexChanges(indexChanges, key, null, keysToRemove); - - if (keyResult != null) - result.add(keyResult); + keyValueEntries.put(key, null); } + final Map keyResult = filterIndexChanges(indexChanges, keyValueEntries, keysToRemove); keys.removeAll(keysToRemove); + result.addAll(keyResult.values()); + if (!keys.isEmpty()) result.addAll(super.getValues(keys)); + return result; } @@ -118,83 +131,133 @@ public Collection getEntries(final Collection iKeys) { final Collection keys = new ArrayList(iKeys); final Set result = new ODocumentFieldsHashSet(); final OTransactionIndexChanges indexChanges = database.getTransaction().getIndexChanges(delegate.getName()); + if (indexChanges == null) { result.addAll(super.getEntries(keys)); return result; } final Set keysToRemove = new HashSet(); + final Map keyValueEntries = new HashMap(); + for (final Object key : keys) { if (indexChanges.cleared) keysToRemove.add(key); - final OIdentifiable keyResult = filterIndexChanges(indexChanges, key, null, keysToRemove); + keyValueEntries.put(key, null); + } - if (keyResult != null) { - final ODocument document = new ODocument(); - document.field("key", key); - document.field("rid", keyResult.getIdentity()); - document.unsetDirty(); - result.add(document); - } + final Map keyResult = filterIndexChanges(indexChanges, keyValueEntries, keysToRemove); + + for (Map.Entry keyResultEntry : keyResult.entrySet()) { + final ODocument document = new ODocument(); + document.field("key", keyResultEntry.getKey()); + document.field("rid", keyResultEntry.getValue().getIdentity()); + + document.unsetDirty(); + result.add(document); } keys.removeAll(keysToRemove); if (!keys.isEmpty()) result.addAll(super.getEntries(keys)); + return result; } - protected OIdentifiable filterIndexChanges(final OTransactionIndexChanges indexChanges, final Object key, OIdentifiable iValue, - final Set keysToRemove) { - if (indexChanges == null) - return iValue; - - OIdentifiable keyResult = iValue; - // CHECK FOR THE RECEIVED KEY - if (indexChanges.containsChangesPerKey(key)) { - final OTransactionIndexChangesPerKey value = indexChanges.getChangesPerKey(key); - if (value != null) { - for (final OTransactionIndexEntry entry : value.entries) { - if (entry.operation == OPERATION.REMOVE) { - if (entry.value == null || entry.value.equals(keyResult)) { - // REMOVE THE ENTIRE KEY, SO RESULT SET IS EMPTY + protected Map filterIndexChanges(OTransactionIndexChanges indexChanges, + Map keyValueEntries, final Set keysToRemove) { + final Map result = new HashMap(); + for (Map.Entry keyValueEntry : keyValueEntries.entrySet()) { + OIdentifiable keyResult = keyValueEntry.getValue(); + Object key = keyValueEntry.getKey(); + + // CHECK FOR THE RECEIVED KEY + + if (indexChanges.containsChangesPerKey(key)) { + final OTransactionIndexChangesPerKey value = indexChanges.getChangesPerKey(key); + if (value != null) { + for (final OTransactionIndexEntry entry : value.entries) { + if (entry.operation == OPERATION.REMOVE) { + if (entry.value == null || entry.value.equals(keyResult)) { + // REMOVE THE ENTIRE KEY, SO RESULT SET IS EMPTY + if (keysToRemove != null) + keysToRemove.add(key); + keyResult = null; + } + } else if (entry.operation == OPERATION.PUT) { + // ADD ALSO THIS RID if (keysToRemove != null) keysToRemove.add(key); - keyResult = null; + keyResult = entry.value; } - } else if (entry.operation == OPERATION.PUT) { - // ADD ALSO THIS RID - if (keysToRemove != null) - keysToRemove.add(key); - keyResult = entry.value; } } } + + if (keyResult != null) + result.put(key, keyResult.getIdentity()); } - // CHECK FOR ANY KEYS - if (indexChanges.containsChangesCrossKey()) { - final OTransactionIndexChangesPerKey value = indexChanges.getChangesCrossKey(); - if (value != null) { - for (final OTransactionIndexEntry entry : value.entries) { - if (entry.operation == OPERATION.REMOVE) { - if (entry.value == null || entry.value.equals(keyResult)) { - // REMOVE THE ENTIRE KEY, SO RESULT SET IS EMPTY - if (keysToRemove != null) - keysToRemove.add(key); - keyResult = null; - } - } else if (entry.operation == OPERATION.PUT) { - // ADD ALSO THIS RID - if (keysToRemove != null) - keysToRemove.add(key); - keyResult = entry.value; - } - } - } + return result; + } + + @Override + public Collection getEntriesBetween(Object rangeFrom, Object rangeTo) { + final OTransactionIndexChanges indexChanges = database.getTransaction().getIndexChanges(delegate.getName()); + if (indexChanges == null) + return super.getEntriesBetween(rangeFrom, rangeTo); + + final OIndexDefinition indexDefinition = getDefinition(); + Object compRangeFrom = rangeFrom; + Object compRangeTo = rangeTo; + if (indexDefinition instanceof OCompositeIndexDefinition || indexDefinition.getParamCount() > 1) { + int keySize = indexDefinition.getParamCount(); + + final OCompositeKey fullKeyFrom = new OCompositeKey((Comparable) rangeFrom); + final OCompositeKey fullKeyTo = new OCompositeKey((Comparable) rangeTo); + + while (fullKeyFrom.getKeys().size() < keySize) + fullKeyFrom.addKey(new OAlwaysLessKey()); + + while (fullKeyTo.getKeys().size() < keySize) + fullKeyTo.addKey(new OAlwaysGreaterKey()); + + compRangeFrom = fullKeyFrom; + compRangeTo = fullKeyTo; + } + + final Collection rangeChanges = indexChanges.getChangesForKeys(compRangeFrom, compRangeTo); + if (rangeChanges.isEmpty()) + return super.getEntriesBetween(rangeFrom, rangeTo); + + final Map keyValueEntries = new HashMap(); + if (indexChanges.cleared) { + for (OTransactionIndexChangesPerKey changesPerKey : rangeChanges) + keyValueEntries.put(changesPerKey.key, null); + } else { + final Collection storedEntries = super.getEntriesBetween(rangeFrom, rangeTo); + for (ODocument entry : storedEntries) + keyValueEntries.put(entry.field("key"), entry. field("rid")); + + for (OTransactionIndexChangesPerKey changesPerKey : rangeChanges) + if (!keyValueEntries.containsKey(changesPerKey.key)) + keyValueEntries.put(changesPerKey.key, null); + } + + final Map keyValuesResult = filterIndexChanges(indexChanges, keyValueEntries, null); + + final Set result = new ODocumentFieldsHashSet(); + for (Map.Entry keyResultEntry : keyValuesResult.entrySet()) { + final ODocument document = new ODocument(); + document.field("key", keyResultEntry.getKey()); + document.field("rid", keyResultEntry.getValue().getIdentity()); + + document.unsetDirty(); + result.add(document); } - return keyResult; + + return result; } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexUnique.java b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexUnique.java index 26064eaf369..5ad86b478fa 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OIndexUnique.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OIndexUnique.java @@ -15,6 +15,11 @@ */ package com.orientechnologies.orient.core.index; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.record.ORecord; import com.orientechnologies.orient.core.storage.ORecordDuplicatedException; @@ -30,9 +35,12 @@ public OIndexUnique(String typeId, String algorithm, OIndexEngine super(typeId, algorithm, engine, valueContainerAlgorithm); } - public OIndexOneValue put(final Object key, final OIdentifiable iSingleValue) { + @Override + public OIndexOneValue put(Object key, final OIdentifiable iSingleValue) { checkForRebuild(); + key = getCollatingValue(key); + modificationLock.requestModificationLock(); try { acquireExclusiveLock(); @@ -64,6 +72,81 @@ public OIndexOneValue put(final Object key, final OIdentifiable iSingleValue) { } } + @Override + protected void putInSnapshot(Object key, OIdentifiable value, Map snapshot) { + key = getCollatingValue(key); + + Object snapshotValue = snapshot.get(key); + if (snapshotValue == null) { + final OIdentifiable storedValue = indexEngine.get(key); + + final Set values = new LinkedHashSet(); + + if (storedValue != null) + values.add(storedValue.getIdentity()); + + values.add(value.getIdentity()); + + snapshot.put(key, values); + } else if (snapshotValue instanceof Set) { + final Set values = (Set) snapshotValue; + + values.add(value.getIdentity()); + } else { + final Set values = new LinkedHashSet(); + + values.add(value); + snapshot.put(key, values); + } + } + + @Override + protected void removeFromSnapshot(Object key, OIdentifiable value, Map snapshot) { + key = getCollatingValue(key); + + Object snapshotValue = snapshot.get(key); + + if (snapshotValue instanceof Set) { + final Set values = (Set) snapshotValue; + if (values.isEmpty()) + snapshot.put(key, RemovedValue.INSTANCE); + else + values.remove(value); + } else + snapshot.put(key, RemovedValue.INSTANCE); + } + + @Override + protected void commitSnapshot(Map snapshot) { + for (Map.Entry snapshotEntry : snapshot.entrySet()) { + Object key = snapshotEntry.getKey(); + checkForKeyType(key); + + Object snapshotValue = snapshotEntry.getValue(); + if (snapshotValue instanceof Set) { + Set values = (Set) snapshotValue; + if (values.isEmpty()) + continue; + + final Iterator valuesIterator = values.iterator(); + if (values.size() > 1) { + final OIdentifiable valueOne = valuesIterator.next(); + final OIdentifiable valueTwo = valuesIterator.next(); + throw new ORecordDuplicatedException(String.format( + "Cannot index record %s: found duplicated key '%s' in index '%s' previously assigned to the record %s", + valueTwo.getIdentity(), key, getName(), valueOne.getIdentity()), valueOne.getIdentity()); + } + + final OIdentifiable value = valuesIterator.next(); + indexEngine.put(key, value.getIdentity()); + } else if (snapshotValue.equals(RemovedValue.INSTANCE)) + indexEngine.remove(key); + else + assert false : "Provided value can not be committed"; + } + } + + @Override public boolean canBeUsedInEqualityOperators() { return true; } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OPropertyIndexDefinition.java b/core/src/main/java/com/orientechnologies/orient/core/index/OPropertyIndexDefinition.java index 4a4676f2ccf..9fc8e18a01f 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OPropertyIndexDefinition.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OPropertyIndexDefinition.java @@ -18,24 +18,22 @@ import java.util.Collections; import java.util.List; +import com.orientechnologies.orient.core.collate.ODefaultCollate; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.db.record.ORecordElement; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; -import com.orientechnologies.orient.core.type.ODocumentWrapperNoClass; /** * Index implementation bound to one schema class property. * */ -public class OPropertyIndexDefinition extends ODocumentWrapperNoClass implements OIndexDefinition { +public class OPropertyIndexDefinition extends OAbstractIndexDefinition { protected String className; protected String field; protected OType keyType; public OPropertyIndexDefinition(final String iClassName, final String iField, final OType iType) { - super(new ODocument()); - className = iClassName; field = iField; keyType = iType; @@ -144,6 +142,7 @@ protected void serializeToStream() { document.field("className", className); document.field("field", field); document.field("keyType", keyType.toString()); + document.field("collate", collate.getName()); } protected void serializeFromStream() { @@ -152,6 +151,8 @@ protected void serializeFromStream() { final String keyTypeStr = document.field("keyType"); keyType = OType.valueOf(keyTypeStr); + + setCollate((String) document.field("collate")); } /** @@ -178,7 +179,10 @@ protected StringBuilder createIndexDDLWithoutFieldType(final String indexName, f ddl.append(shortName).append(" "); } else { ddl.append(indexName).append(" on "); - ddl.append(className).append(" ( ").append(field).append(" ) "); + ddl.append(className).append(" ( ").append(field); + if (!collate.getName().equals(ODefaultCollate.NAME)) + ddl.append(" COLLATE ").append(collate.getName()); + ddl.append(" ) "); } ddl.append(indexType); diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/ORuntimeKeyIndexDefinition.java b/core/src/main/java/com/orientechnologies/orient/core/index/ORuntimeKeyIndexDefinition.java index 03f6d3e0b20..a79619cb394 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/ORuntimeKeyIndexDefinition.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/ORuntimeKeyIndexDefinition.java @@ -20,12 +20,12 @@ import java.util.List; import com.orientechnologies.common.serialization.types.OBinarySerializer; +import com.orientechnologies.orient.core.collate.ODefaultCollate; import com.orientechnologies.orient.core.db.record.ORecordElement; import com.orientechnologies.orient.core.exception.OConfigurationException; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.serialization.serializer.binary.OBinarySerializerFactory; -import com.orientechnologies.orient.core.type.ODocumentWrapperNoClass; /** * Index definition that use the serializer specified at run-time not based on type. This is useful to have custom type keys for @@ -34,12 +34,11 @@ * @author Luca Garulli (l.garulli--at--orientechnologies.com) * */ -public class ORuntimeKeyIndexDefinition extends ODocumentWrapperNoClass implements OIndexDefinition { +public class ORuntimeKeyIndexDefinition extends OAbstractIndexDefinition { private OBinarySerializer serializer; @SuppressWarnings("unchecked") public ORuntimeKeyIndexDefinition(final byte iId) { - super(new ODocument()); serializer = (OBinarySerializer) OBinarySerializerFactory.INSTANCE.getObjectSerializer(iId); if (serializer == null) throw new OConfigurationException("Runtime index definition cannot find binary serializer with id=" + iId @@ -82,6 +81,7 @@ public ODocument toStream() { document.setInternalStatus(ORecordElement.STATUS.UNMARSHALLING); try { document.field("keySerializerId", serializer.getId()); + document.field("collate", collate.getName()); return document; } finally { document.setInternalStatus(ORecordElement.STATUS.LOADED); @@ -96,6 +96,10 @@ protected void fromStream() { if (serializer == null) throw new OConfigurationException("Runtime index definition cannot find binary serializer with id=" + keySerializerId + ". Assure to plug custom serializer into the server."); + + String collateField = document.field("collate"); + if (collateField == null) + collateField = ODefaultCollate.NAME; } public Object getDocumentValueToIndex(final ODocument iDocument) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/OSimpleKeyIndexDefinition.java b/core/src/main/java/com/orientechnologies/orient/core/index/OSimpleKeyIndexDefinition.java index eaf3e2e500a..576504bf987 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/OSimpleKeyIndexDefinition.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/OSimpleKeyIndexDefinition.java @@ -9,13 +9,11 @@ import com.orientechnologies.orient.core.db.record.ORecordElement; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; -import com.orientechnologies.orient.core.type.ODocumentWrapperNoClass; -public class OSimpleKeyIndexDefinition extends ODocumentWrapperNoClass implements OIndexDefinition { +public class OSimpleKeyIndexDefinition extends OAbstractIndexDefinition { private OType[] keyTypes; public OSimpleKeyIndexDefinition(final OType... keyTypes) { - super(new ODocument()); this.keyTypes = keyTypes; } @@ -77,6 +75,7 @@ public ODocument toStream() { keyTypeNames.add(keyType.toString()); document.field("keyTypes", keyTypeNames, OType.EMBEDDEDLIST); + document.field("collate", collate.getName()); return document; } finally { document.setInternalStatus(ORecordElement.STATUS.LOADED); @@ -93,6 +92,8 @@ protected void fromStream() { keyTypes[i] = OType.valueOf(keyTypeName); i++; } + + setCollate((String) document.field("collate")); } public Object getDocumentValueToIndex(final ODocument iDocument) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OLocalHashTableIndexEngine.java b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OLocalHashTableIndexEngine.java index e970b3a6384..1c4aca7720b 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OLocalHashTableIndexEngine.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OLocalHashTableIndexEngine.java @@ -15,12 +15,13 @@ */ package com.orientechnologies.orient.core.index.engine; -import java.util.*; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; import com.orientechnologies.common.serialization.types.OBinarySerializer; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.ODatabaseRecord; -import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.id.ORID; import com.orientechnologies.orient.core.index.OIndexDefinition; import com.orientechnologies.orient.core.index.OIndexEngine; @@ -93,6 +94,11 @@ public void flush() { hashTable.flush(); } + @Override + public void deleteWithoutLoad(String indexName) { + hashTable.deleteWithoutLoad(indexName, (OStorageLocalAbstract) getDatabase().getStorage().getUnderlying()); + } + @Override public void delete() { hashTable.delete(); @@ -144,42 +150,6 @@ public void put(Object key, V value) { hashTable.put(key, value); } - @Override - public int removeValue(OIdentifiable valueToRemove, ValuesTransformer transformer) { - Map entriesToUpdate = new HashMap(); - OHashIndexBucket.Entry firstEntry = hashTable.firstEntry(); - if (firstEntry == null) - return 0; - - OHashIndexBucket.Entry[] entries = hashTable.ceilingEntries(firstEntry.key); - - while (entries.length > 0) { - for (OHashIndexBucket.Entry entry : entries) - if (transformer != null) { - Collection rids = transformer.transformFromValue(entry.value); - if (rids.remove(valueToRemove)) - entriesToUpdate.put(entry.key, transformer.transformToValue(rids)); - } else if (entry.value.equals(valueToRemove)) - entriesToUpdate.put(entry.key, entry.value); - - entries = hashTable.higherEntries(entries[entries.length - 1].key); - } - - for (Map.Entry entry : entriesToUpdate.entrySet()) { - V value = entry.getValue(); - if (value instanceof Collection) { - Collection col = (Collection) value; - if (col.isEmpty()) - hashTable.remove(entry.getKey()); - else - hashTable.put(entry.getKey(), value); - } else - hashTable.remove(entry.getKey()); - } - - return entriesToUpdate.size(); - } - @Override public long size(ValuesTransformer transformer) { if (transformer == null) diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMVRBTreeIndexEngine.java b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMVRBTreeIndexEngine.java index b88146c1851..c7c9ecb6148 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMVRBTreeIndexEngine.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMVRBTreeIndexEngine.java @@ -15,11 +15,13 @@ */ package com.orientechnologies.orient.core.index.engine; -import java.util.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; import com.orientechnologies.common.collection.OMVRBTree; import com.orientechnologies.common.collection.OMVRBTreeEntry; -import com.orientechnologies.common.comparator.ODefaultComparator; import com.orientechnologies.common.concur.resource.OSharedResourceAdaptiveExternal; import com.orientechnologies.common.profiler.OProfiler; import com.orientechnologies.common.profiler.OProfilerMBean; @@ -157,6 +159,11 @@ public void delete() { } } + @Override + public void deleteWithoutLoad(String indexName) { + throw new UnsupportedOperationException("deleteWithoutLoad"); + } + public void load(ORID indexRid, String indexName, OIndexDefinition indexDefinition, boolean isAutomatic) { acquireExclusiveLock(); try { @@ -209,51 +216,6 @@ public boolean remove(Object key) { } } - @Override - public int removeValue(OIdentifiable valueToRemove, ValuesTransformer transformer) { - acquireExclusiveLock(); - try { - Map entriesToUpdate = new TreeMap(ODefaultComparator.INSTANCE); - final OMVRBTreeEntry firstEntry = map.getFirstEntry(); - if (firstEntry == null) - return 0; - - OMVRBTreeEntry entry = firstEntry; - while (entry != null) { - final Object key = entry.getKey(); - final V value = entry.getValue(); - - if (transformer != null) { - Collection rids = transformer.transformFromValue(value); - if (rids.remove(valueToRemove)) { - entriesToUpdate.put(key, transformer.transformToValue(rids)); - } - } else if (value.equals(valueToRemove)) { - entriesToUpdate.put(key, value); - } - - entry = OMVRBTree.next(entry); - } - - for (Map.Entry entryToUpdate : entriesToUpdate.entrySet()) { - V value = entryToUpdate.getValue(); - if (value instanceof Collection) { - Collection col = (Collection) value; - if (col.isEmpty()) - map.remove(entryToUpdate.getKey()); - else - map.put(entryToUpdate.getKey(), value); - } else - map.remove(entryToUpdate.getKey()); - - } - - return entriesToUpdate.size(); - } finally { - releaseExclusiveLock(); - } - } - @Override public Iterator> iterator() { acquireExclusiveLock(); diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMemoryHashMapIndexEngine.java b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMemoryHashMapIndexEngine.java index e608ff19724..a19e63a69d4 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMemoryHashMapIndexEngine.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OMemoryHashMapIndexEngine.java @@ -15,8 +15,6 @@ */ package com.orientechnologies.orient.core.index.engine; -import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -24,7 +22,6 @@ import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.ODatabaseRecord; -import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.id.ORID; import com.orientechnologies.orient.core.index.OIndexDefinition; import com.orientechnologies.orient.core.index.OIndexEngine; @@ -61,6 +58,10 @@ public void create(String indexName, OIndexDefinition indexDefinition, String cl public void delete() { } + @Override + public void deleteWithoutLoad(String indexName) { + } + @Override public void load(ORID indexRid, String indexName, OIndexDefinition indexDefinition, boolean isAutomatic) { } @@ -152,34 +153,6 @@ public void put(Object key, V value) { concurrentHashMap.put(key, value); } - @Override - public int removeValue(OIdentifiable valueToRemove, ValuesTransformer transformer) { - Map entriesToUpdate = new HashMap(); - - for (Map.Entry entry : concurrentHashMap.entrySet()) { - if (transformer != null) { - Collection rids = transformer.transformFromValue(entry.getValue()); - if (rids.remove(valueToRemove)) - entriesToUpdate.put(entry.getKey(), transformer.transformToValue(rids)); - } else if (entry.getValue().equals(valueToRemove)) - entriesToUpdate.put(entry.getKey(), entry.getValue()); - } - - for (Map.Entry entry : entriesToUpdate.entrySet()) { - V value = entry.getValue(); - if (value instanceof Collection) { - Collection col = (Collection) value; - if (col.isEmpty()) - concurrentHashMap.remove(entry.getKey()); - else - concurrentHashMap.put(entry.getKey(), value); - } else - concurrentHashMap.remove(entry.getKey()); - } - - return entriesToUpdate.size(); - } - @Override public void getValuesBetween(Object rangeFrom, boolean fromInclusive, Object rangeTo, boolean toInclusive, ValuesTransformer transformer, ValuesResultListener valuesResultListener) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/engine/ORemoteIndexEngine.java b/core/src/main/java/com/orientechnologies/orient/core/index/engine/ORemoteIndexEngine.java index 95b767712a5..25bdcd69b15 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/engine/ORemoteIndexEngine.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/engine/ORemoteIndexEngine.java @@ -18,7 +18,6 @@ import java.util.Iterator; import java.util.Map; -import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.id.ORID; import com.orientechnologies.orient.core.index.OIndexDefinition; import com.orientechnologies.orient.core.index.OIndexEngine; @@ -42,6 +41,10 @@ public void create(String indexName, OIndexDefinition indexDefinition, String cl OStreamSerializer valueSerializer, boolean isAutomatic) { } + @Override + public void deleteWithoutLoad(String indexName) { + } + @Override public void delete() { } @@ -135,11 +138,6 @@ public Object get(Object key) { public void put(Object key, Object value) { } - @Override - public int removeValue(OIdentifiable value, ValuesTransformer transformer) { - return 0; - } - @Override public void getValuesBetween(Object rangeFrom, boolean fromInclusive, Object rangeTo, boolean toInclusive, ValuesTransformer transformer, ValuesResultListener resultListener) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OSBTreeIndexEngine.java b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OSBTreeIndexEngine.java index f351e9b9e11..a374d27c92a 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/engine/OSBTreeIndexEngine.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/engine/OSBTreeIndexEngine.java @@ -16,7 +16,10 @@ package com.orientechnologies.orient.core.index.engine; -import java.util.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; import com.orientechnologies.common.concur.resource.OSharedResourceAdaptiveExternal; import com.orientechnologies.common.serialization.types.OBinarySerializer; @@ -120,6 +123,20 @@ public void delete() { } } + @Override + public void deleteWithoutLoad(String indexName) { + acquireExclusiveLock(); + try { + final ODatabaseRecord database = getDatabase(); + final OStorageLocalAbstract storageLocalAbstract = (OStorageLocalAbstract) database.getStorage().getUnderlying(); + + sbTree = new OSBTree(DATA_FILE_EXTENSION, 1, OGlobalConfiguration.INDEX_DURABLE_IN_NON_TX_MODE.getValueAsBoolean()); + sbTree.deleteWithoutLoad(indexName, storageLocalAbstract); + } finally { + releaseExclusiveLock(); + } + } + @Override public void load(ORID indexRid, String indexName, OIndexDefinition indexDefinition, boolean isAutomatic) { acquireExclusiveLock(); @@ -348,43 +365,6 @@ public void put(Object key, V value) { } } - @Override - public int removeValue(final OIdentifiable value, final ValuesTransformer transformer) { - acquireExclusiveLock(); - try { - final Set keySetToRemove = new HashSet(); - - if (sbTree.size() == 0) - return 0; - - final Object firstKey = sbTree.firstKey(); - final Object lastKey = sbTree.lastKey(); - sbTree.loadEntriesBetween(firstKey, true, lastKey, true, new OSBTree.RangeResultListener() { - @Override - public boolean addResult(Map.Entry entry) { - if (transformer == null) { - if (entry.getValue().equals(value)) - keySetToRemove.add(entry.getKey()); - } else { - Collection identifiables = transformer.transformFromValue(entry.getValue()); - for (OIdentifiable identifiable : identifiables) { - if (identifiable.equals(value)) - keySetToRemove.add(entry.getKey()); - } - } - return true; - } - }); - - for (Object keyToRemove : keySetToRemove) - sbTree.remove(keyToRemove); - - return keySetToRemove.size(); - } finally { - releaseExclusiveLock(); - } - } - @Override public void getValuesBetween(Object rangeFrom, boolean fromInclusive, Object rangeTo, boolean toInclusive, final ValuesTransformer transformer, final ValuesResultListener valuesResultListener) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OHashIndexBucket.java b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OHashIndexBucket.java index db054187958..726262fa834 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OHashIndexBucket.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OHashIndexBucket.java @@ -175,37 +175,21 @@ public int updateEntry(int index, V value) { entryPosition += OLongSerializer.LONG_SIZE; entryPosition += keySerializer.getObjectSizeInDirectMemory(bufferPointer, entryPosition); - if (valueSerializer.isFixedLength()) { - byte[] newSerializedValue = new byte[valueSerializer.getFixedLength()]; - valueSerializer.serializeNative(value, newSerializedValue, 0); + final int newSize = valueSerializer.getObjectSize(value); + final int oldSize = valueSerializer.getObjectSizeInDirectMemory(bufferPointer, entryPosition); + if (newSize != oldSize) + return -1; - byte[] oldSerializedValue = bufferPointer.get(entryPosition, newSerializedValue.length); + byte[] newSerializedValue = new byte[newSize]; + valueSerializer.serializeNative(value, newSerializedValue, 0); - if (ODefaultComparator.INSTANCE.compare(oldSerializedValue, newSerializedValue) == 0) - return 0; + byte[] oldSerializedValue = bufferPointer.get(entryPosition, oldSize); - bufferPointer.set(entryPosition, newSerializedValue, 0, newSerializedValue.length); - return 1; - } else { - final int newSize = valueSerializer.getObjectSize(value); - final int oldSize = valueSerializer.getObjectSizeInDirectMemory(bufferPointer, entryPosition); + if (ODefaultComparator.INSTANCE.compare(oldSerializedValue, newSerializedValue) == 0) + return 0; - byte[] newSerializedValue = new byte[newSize]; - valueSerializer.serializeNative(value, newSerializedValue, 0); - - byte[] oldSerializedValue = bufferPointer.get(entryPosition, oldSize); - - if (ODefaultComparator.INSTANCE.compare(oldSerializedValue, newSerializedValue) == 0) - return 0; - - if (oldSize == newSize) { - bufferPointer.set(entryPosition, newSerializedValue, 0, newSerializedValue.length); - - return 1; - } - } - - return -1; + bufferPointer.set(entryPosition, newSerializedValue, 0, newSerializedValue.length); + return 1; } public Entry deleteEntry(int index) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OLocalHashTable.java b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OLocalHashTable.java index 66151aa4d6c..db81bcf9f41 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OLocalHashTable.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/OLocalHashTable.java @@ -40,52 +40,52 @@ * @since 12.03.13 */ public class OLocalHashTable extends OSharedResourceAdaptive { - private static final double MERGE_THRESHOLD = 0.2; + private static final double MERGE_THRESHOLD = 0.2; - private static final long HASH_CODE_MIN_VALUE = 0; - private static final long HASH_CODE_MAX_VALUE = 0xFFFFFFFFFFFFFFFFL; + private static final long HASH_CODE_MIN_VALUE = 0; + private static final long HASH_CODE_MAX_VALUE = 0xFFFFFFFFFFFFFFFFL; - private long[][] hashTree; - private OHashTreeNodeMetadata[] nodesMetadata; + private long[][] hashTree; + private OHashTreeNodeMetadata[] nodesMetadata; - private int hashTreeSize; + private int hashTreeSize; - private long size; + private long size; - private int hashTreeTombstone = -1; - private long bucketTombstonePointer = -1; + private int hashTreeTombstone = -1; + private long bucketTombstonePointer = -1; - private final String metadataConfigurationFileExtension; - private final String treeStateFileExtension; - private final String bucketFileExtension; + private final String metadataConfigurationFileExtension; + private final String treeStateFileExtension; + private final String bucketFileExtension; - public static final int HASH_CODE_SIZE = 64; - public static final int MAX_LEVEL_DEPTH = 8; - public static final int MAX_LEVEL_SIZE = 1 << MAX_LEVEL_DEPTH; + public static final int HASH_CODE_SIZE = 64; + public static final int MAX_LEVEL_DEPTH = 8; + public static final int MAX_LEVEL_SIZE = 1 << MAX_LEVEL_DEPTH; - public static final int LEVEL_MASK = Integer.MAX_VALUE >>> (31 - MAX_LEVEL_DEPTH); + public static final int LEVEL_MASK = Integer.MAX_VALUE >>> (31 - MAX_LEVEL_DEPTH); - private OStorageLocalAbstract storage; + private OStorageLocalAbstract storage; - private String name; + private String name; - private OHashIndexBufferStore metadataStore; - private OHashIndexTreeStateStore treeStateStore; + private OHashIndexBufferStore metadataStore; + private OHashIndexTreeStateStore treeStateStore; - private ODiskCache diskCache; - private final OHashFunction keyHashFunction; + private ODiskCache diskCache; + private final OHashFunction keyHashFunction; - private OBinarySerializer keySerializer; - private OBinarySerializer valueSerializer; - private OType[] keyTypes; + private OBinarySerializer keySerializer; + private OBinarySerializer valueSerializer; + private OType[] keyTypes; - private OHashIndexFileLevelMetadata[] filesMetadata = new OHashIndexFileLevelMetadata[HASH_CODE_SIZE]; - private final long[] fileLevelIds = new long[HASH_CODE_SIZE]; + private OHashIndexFileLevelMetadata[] filesMetadata = new OHashIndexFileLevelMetadata[HASH_CODE_SIZE]; + private final long[] fileLevelIds = new long[HASH_CODE_SIZE]; private final KeyHashCodeComparator comparator; public OLocalHashTable(String metadataConfigurationFileExtension, String treeStateFileExtension, String bucketFileExtension, - OHashFunction keyHashFunction) { + OHashFunction keyHashFunction) { super(OGlobalConfiguration.ENVIRONMENT_CONCURRENT.getValueAsBoolean()); this.metadataConfigurationFileExtension = metadataConfigurationFileExtension; this.treeStateFileExtension = treeStateFileExtension; @@ -107,7 +107,7 @@ private void initStores(String metadataConfigurationFileExtension, String treeSt } public void create(String name, OBinarySerializer keySerializer, OBinarySerializer valueSerializer, OType[] keyTypes, - OStorageLocalAbstract storageLocal) { + OStorageLocalAbstract storageLocal) { acquireExclusiveLock(); try { this.storage = storageLocal; @@ -424,6 +424,35 @@ public void load(String name, OType[] keyTypes, OStorageLocalAbstract storageLoc } } + public void deleteWithoutLoad(String name, OStorageLocalAbstract storageLocal) { + acquireExclusiveLock(); + try { + final ODiskCache diskCache = storageLocal.getDiskCache(); + + initStores(metadataConfigurationFileExtension, treeStateFileExtension); + + metadataStore.open(); + treeStateStore.open(); + + filesMetadata = metadataStore.loadMetadata(); + + for (int i = 0; i < filesMetadata.length; i++) { + OHashIndexFileLevelMetadata fileLevelMetadata = filesMetadata[i]; + if (fileLevelMetadata != null) { + fileLevelIds[i] = diskCache.openFile(fileLevelMetadata.getFileName()); + diskCache.deleteFile(fileLevelIds[i]); + } + } + + metadataStore.delete(); + treeStateStore.delete(); + } catch (IOException ioe) { + throw new OIndexException("Can not delete hash table with name " + name, ioe); + } finally { + releaseExclusiveLock(); + } + } + private OHashIndexBucket.Entry[] convertBucketToEntries(final OHashIndexBucket bucket, int startIndex, int endIndex) { final OHashIndexBucket.Entry[] entries = new OHashIndexBucket.Entry[endIndex - startIndex]; final Iterator> iterator = bucket.iterator(startIndex); @@ -472,8 +501,7 @@ private BucketPath nextBucketToFind(final BucketPath bucketPath, int bucketDepth } private BucketPath nextNonEmptyNode(BucketPath bucketPath) { - nextBucketLoop: - while (bucketPath != null) { + nextBucketLoop: while (bucketPath != null) { final long[] node = hashTree[bucketPath.nodeIndex]; final int startIndex = bucketPath.itemIndex + bucketPath.hashMapOffset; final int endIndex = MAX_LEVEL_SIZE; @@ -827,8 +855,7 @@ private BucketPath prevBucketToFind(final BucketPath bucketPath, int bucketDepth } private BucketPath prevNonEmptyNode(BucketPath nodePath) { - prevBucketLoop: - while (nodePath != null) { + prevBucketLoop: while (nodePath != null) { final long[] node = hashTree[nodePath.nodeIndex]; final int startIndex = 0; final int endIndex = nodePath.itemIndex + nodePath.hashMapOffset; @@ -1274,7 +1301,7 @@ private void doPut(K key, V value) throws IOException { } private void updateNodesAfterSplit(BucketPath bucketPath, long[] node, long[] newNode, int nodeLocalDepth, int hashMapSize, - boolean allLeftHashMapEquals, boolean allRightHashMapsEquals, int newNodeIndex) { + boolean allLeftHashMapEquals, boolean allRightHashMapsEquals, int newNodeIndex) { final int startIndex = findParentNodeStartIndex(bucketPath); @@ -1586,7 +1613,7 @@ private void deleteNode(int nodeIndex) { } if (hashTreeTombstone > -1) { - final long[] tombstone = new long[]{hashTreeTombstone}; + final long[] tombstone = new long[] { hashTreeTombstone }; hashTree[nodeIndex] = tombstone; hashTreeTombstone = nodeIndex; } else { @@ -1598,7 +1625,7 @@ private void deleteNode(int nodeIndex) { } private void splitBucketContent(OHashIndexBucket bucket, OHashIndexBucket updatedBucket, - OHashIndexBucket newBucket, int newBucketDepth) { + OHashIndexBucket newBucket, int newBucketDepth) { assert checkBucketDepth(bucket); for (OHashIndexBucket.Entry entry : bucket) { @@ -1806,11 +1833,11 @@ private BucketPath getBucket(final long hashCode) { private static final class BucketPath { private final BucketPath parent; - private final int hashMapOffset; - private final int itemIndex; - private final int nodeIndex; - private final int nodeGlobalDepth; - private final int nodeLocalDepth; + private final int hashMapOffset; + private final int itemIndex; + private final int nodeIndex; + private final int nodeGlobalDepth; + private final int nodeLocalDepth; private BucketPath(BucketPath parent, int hashMapOffset, int itemIndex, int nodeIndex, int nodeLocalDepth, int nodeGlobalDepth) { this.parent = parent; @@ -1825,7 +1852,7 @@ private BucketPath(BucketPath parent, int hashMapOffset, int itemIndex, int node private static final class BucketSplitResult { private final long updatedBucketPointer; private final long newBucketPointer; - private final int newDepth; + private final int newDepth; private BucketSplitResult(long updatedBucketPointer, long newBucketPointer, int newDepth) { this.updatedBucketPointer = updatedBucketPointer; @@ -1835,7 +1862,7 @@ private BucketSplitResult(long updatedBucketPointer, long newBucketPointer, int } private static final class NodeSplitResult { - private final long[] newNode; + private final long[] newNode; private final boolean allLeftHashMapsEqual; private final boolean allRightHashMapsEqual; @@ -1849,7 +1876,7 @@ private NodeSplitResult(long[] newNode, boolean allLeftHashMapsEqual, boolean al private static final class KeyHashCodeComparator implements Comparator { private final Comparator comparator = ODefaultComparator.INSTANCE; - private final OHashFunction keyHashFunction; + private final OHashFunction keyHashFunction; public KeyHashCodeComparator(OHashFunction keyHashFunction) { this.keyHashFunction = keyHashFunction; diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/ODiskCache.java b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/ODiskCache.java index 41469eacc4e..ae76b5813b0 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/ODiskCache.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/ODiskCache.java @@ -62,4 +62,6 @@ public interface ODiskCache { boolean isOpen(long fileId); boolean exists(String name); + + String fileNameById(long fileId); } diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OReadWriteDiskCache.java b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OReadWriteDiskCache.java index 8ba7a00674c..16fb9745588 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OReadWriteDiskCache.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OReadWriteDiskCache.java @@ -105,7 +105,11 @@ LRUList getA1in() { @Override public long openFile(final String fileName) throws IOException { synchronized (syncObject) { - final long fileId = writeCache.openFile(fileName); + long fileId = writeCache.isOpen(fileName); + if (fileId >= 0) + return fileId; + + fileId = writeCache.openFile(fileName); filePages.put(fileId, new HashSet()); return fileId; @@ -115,6 +119,9 @@ public long openFile(final String fileName) throws IOException { @Override public void openFile(final long fileId) throws IOException { synchronized (syncObject) { + if (writeCache.isOpen(fileId)) + return; + writeCache.openFile(fileId); filePages.put(fileId, new HashSet()); } @@ -127,6 +134,13 @@ public boolean exists(final String fileName) { } } + @Override + public String fileNameById(long fileId) { + synchronized (syncObject) { + return writeCache.fileNameById(fileId); + } + } + @Override public void pinPage(final OCacheEntry cacheEntry) throws IOException { synchronized (syncObject) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OWOWCache.java b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OWOWCache.java index 3f9c8199b83..f4382b31e34 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OWOWCache.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/hashindex/local/cache/OWOWCache.java @@ -19,8 +19,23 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; -import java.util.*; -import java.util.concurrent.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.CRC32; @@ -364,6 +379,22 @@ public boolean isOpen(long fileId) { } } + public long isOpen(String fileName) throws IOException { + synchronized (syncObject) { + initNameIdMapping(); + + final Long fileId = nameIdMap.get(fileName); + if (fileId == null) + return -1; + + final OFileClassic fileClassic = files.get(fileId); + if (fileClassic == null || !fileClassic.isOpen()) + return -1; + + return fileId; + } + } + public void setSoftlyClosed(long fileId, boolean softlyClosed) throws IOException { synchronized (syncObject) { OFileClassic fileClassic = files.get(fileId); @@ -682,6 +713,12 @@ public void delete() throws IOException { } } + public String fileNameById(long fileId) { + synchronized (syncObject) { + return files.get(fileId).getName(); + } + } + private final class GroupKey implements Comparable { private final long fileId; private final long groupIndex; diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/OSBTreeMapEntryIterator.java b/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/OSBTreeMapEntryIterator.java index 1ca6be04264..50188ca264e 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/OSBTreeMapEntryIterator.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/OSBTreeMapEntryIterator.java @@ -23,7 +23,7 @@ import java.util.Map; import com.orientechnologies.orient.core.db.record.OIdentifiable; -import com.orientechnologies.orient.core.db.record.ridset.sbtree.OSBTreeIndexRIDContainer; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainer; /** * @author Artem Orobets @@ -53,7 +53,7 @@ private void prefetchData(boolean firstTime) { public boolean addResult(final Map.Entry entry) { final V value = entry.getValue(); final V resultValue; - if (value instanceof OSBTreeIndexRIDContainer) + if (value instanceof OIndexRIDContainer) resultValue = (V) new HashSet((Collection) value); else resultValue = value; diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTree.java b/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTree.java index 3b5eed82d48..2ab9ab1fc6e 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTree.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTree.java @@ -16,6 +16,14 @@ package com.orientechnologies.orient.core.index.sbtree.local; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + import com.orientechnologies.common.collection.OAlwaysGreaterKey; import com.orientechnologies.common.collection.OAlwaysLessKey; import com.orientechnologies.common.collection.OCompositeKey; @@ -35,50 +43,42 @@ import com.orientechnologies.orient.core.storage.impl.local.paginated.OStorageTransaction; import com.orientechnologies.orient.core.storage.impl.local.paginated.wal.OWriteAheadLog; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - /** * @author Andrey Lomakin * @since 8/7/13 */ public class OSBTree extends ODurableComponent implements OTreeInternal { - private static final int MAX_KEY_SIZE = OGlobalConfiguration.SBTREE_MAX_KEY_SIZE - .getValueAsInteger(); - private static final int MAX_EMBEDDED_VALUE_SIZE = OGlobalConfiguration.SBTREE_MAX_EMBEDDED_VALUE_SIZE - .getValueAsInteger(); - private static final OAlwaysLessKey ALWAYS_LESS_KEY = new OAlwaysLessKey(); - private static final OAlwaysGreaterKey ALWAYS_GREATER_KEY = new OAlwaysGreaterKey(); + private static final int MAX_KEY_SIZE = OGlobalConfiguration.SBTREE_MAX_KEY_SIZE + .getValueAsInteger(); + private static final int MAX_EMBEDDED_VALUE_SIZE = OGlobalConfiguration.SBTREE_MAX_EMBEDDED_VALUE_SIZE + .getValueAsInteger(); + private static final OAlwaysLessKey ALWAYS_LESS_KEY = new OAlwaysLessKey(); + private static final OAlwaysGreaterKey ALWAYS_GREATER_KEY = new OAlwaysGreaterKey(); - private final static long ROOT_INDEX = 0; + private final static long ROOT_INDEX = 0; - private final Comparator comparator = ODefaultComparator.INSTANCE; + private final Comparator comparator = ODefaultComparator.INSTANCE; - private OStorageLocalAbstract storage; - private String name; + private OStorageLocalAbstract storage; + private String name; - private final String dataFileExtension; + private final String dataFileExtension; - private ODiskCache diskCache; + private ODiskCache diskCache; - private long fileId; + private long fileId; - private int keySize; + private int keySize; - private OBinarySerializer keySerializer; - private OType[] keyTypes; + private OBinarySerializer keySerializer; + private OType[] keyTypes; - private OBinarySerializer valueSerializer; + private OBinarySerializer valueSerializer; - private final boolean durableInNonTxMode; - private static final ODurablePage.TrackMode txTrackMode = ODurablePage.TrackMode - .valueOf(OGlobalConfiguration.INDEX_TX_MODE - .getValueAsString().toUpperCase()); + private final boolean durableInNonTxMode; + private static final ODurablePage.TrackMode txTrackMode = ODurablePage.TrackMode + .valueOf(OGlobalConfiguration.INDEX_TX_MODE + .getValueAsString().toUpperCase()); public OSBTree(String dataFileExtension, int keySize, boolean durableInNonTxMode) { super(OGlobalConfiguration.ENVIRONMENT_CONCURRENT.getValueAsBoolean()); @@ -88,7 +88,7 @@ public OSBTree(String dataFileExtension, int keySize, boolean durableInNonTxMode } public void create(String name, OBinarySerializer keySerializer, OBinarySerializer valueSerializer, OType[] keyTypes, - OStorageLocalAbstract storageLocal) { + OStorageLocalAbstract storageLocal) { acquireExclusiveLock(); try { this.storage = storageLocal; @@ -217,18 +217,22 @@ public void put(K key, V value) { int insertionIndex; int sizeDiff; if (bucketSearchResult.itemIndex >= 0) { - boolean canBeUpdated = keyBucket.updateValue(bucketSearchResult.itemIndex, treeValue); + int updateResult = keyBucket.updateValue(bucketSearchResult.itemIndex, treeValue); - if (canBeUpdated) { + if (updateResult == 1) { logPageChanges(keyBucket, fileId, keyBucketCacheEntry.getPageIndex(), false); keyBucketCacheEntry.markDirty(); + } + if (updateResult >= 0) { keyBucketPointer.releaseExclusiveLock(); diskCache.release(keyBucketCacheEntry); endDurableOperation(transaction, false); return; } else { + assert updateResult == -1; + long removedLinkedValue = keyBucket.remove(bucketSearchResult.itemIndex); if (removedLinkedValue >= 0) removeLinkedValue(removedLinkedValue); @@ -265,7 +269,8 @@ public void put(K key, V value) { keyBucketPointer.releaseExclusiveLock(); diskCache.release(keyBucketCacheEntry); - setSize(size() + sizeDiff); + if (sizeDiff != 0) + setSize(size() + sizeDiff); endDurableOperation(transaction, false); } catch (IOException e) { @@ -533,6 +538,20 @@ public void delete() { } } + public void deleteWithoutLoad(String name, OStorageLocalAbstract storageLocal) { + acquireExclusiveLock(); + try { + final ODiskCache diskCache = storageLocal.getDiskCache(); + + final long fileId = diskCache.openFile(name + dataFileExtension); + diskCache.deleteFile(fileId); + } catch (IOException ioe) { + throw new OSBTreeException("Exception during deletion of sbtree " + name, ioe); + } finally { + releaseExclusiveLock(); + } + } + public void load(String name, OType[] keyTypes, OStorageLocalAbstract storageLocal) { acquireExclusiveLock(); try { @@ -731,8 +750,7 @@ public void loadEntriesMinor(K key, boolean inclusive, RangeResultListener } boolean firstBucket = true; - resultsLoop: - while (true) { + resultsLoop: while (true) { long nextPageIndex = -1; OCacheEntry cacheEntry = diskCache.load(fileId, pageIndex, false); final OCachePointer pointer = cacheEntry.getCachePointer(); @@ -803,8 +821,7 @@ public void loadEntriesMajor(K key, boolean inclusive, RangeResultListener index = -bucketSearchResult.itemIndex - 1; } - resultsLoop: - while (true) { + resultsLoop: while (true) { long nextPageIndex = -1; final OCacheEntry cacheEntry = diskCache.load(fileId, pageIndex, false); final OCachePointer pointer = cacheEntry.getCachePointer(); @@ -992,7 +1009,7 @@ public K lastKey() { } public void loadEntriesBetween(K keyFrom, boolean fromInclusive, K keyTo, boolean toInclusive, - OTreeInternal.RangeResultListener listener) { + OTreeInternal.RangeResultListener listener) { acquireSharedLock(); try { keyFrom = keySerializer.preprocess(keyFrom, (Object[]) keyTypes); @@ -1035,8 +1052,7 @@ public void loadEntriesBetween(K keyFrom, boolean fromInclusive, K keyTo, boolea int endIndex; long pageIndex = pageIndexFrom; - resultsLoop: - while (true) { + resultsLoop: while (true) { long nextPageIndex = -1; final OCacheEntry cacheEntry = diskCache.load(fileId, pageIndex, false); @@ -1409,7 +1425,7 @@ public V setValue(V value) { } private static class BucketSearchResult { - private final int itemIndex; + private final int itemIndex; private final ArrayList path; private BucketSearchResult(int itemIndex, ArrayList path) { @@ -1444,7 +1460,7 @@ private static enum PartialSearchMode { private static final class PagePathItemUnit { private final long pageIndex; - private final int itemIndex; + private final int itemIndex; private PagePathItemUnit(long pageIndex, int itemIndex) { this.pageIndex = pageIndex; diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTreeBucket.java b/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTreeBucket.java index d8b2d4817a2..3167dd22425 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTreeBucket.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/sbtree/local/OSBTreeBucket.java @@ -350,20 +350,26 @@ public boolean addEntry(int index, SBTreeEntry treeEntry, boolean updateNe return true; } - public boolean updateValue(int index, OSBTreeValue value) throws IOException { - if (valueSerializer.isFixedLength()) { - int entryPosition = getIntValue(index * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET); + public int updateValue(int index, OSBTreeValue value) throws IOException { + int entryPosition = getIntValue(index * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET); + entryPosition += keySerializer.getObjectSizeInDirectMemory(pagePointer, entryPosition) + OByteSerializer.BYTE_SIZE; - entryPosition += keySerializer.getObjectSizeInDirectMemory(pagePointer, entryPosition) + OByteSerializer.BYTE_SIZE; + final int newSize = valueSerializer.getObjectSize(value.getValue()); + final int oldSize = valueSerializer.getObjectSizeInDirectMemory(pagePointer, entryPosition); + if (newSize != oldSize) + return -1; - byte[] serializedValue = new byte[valueSerializer.getFixedLength()]; - valueSerializer.serializeNative(value.getValue(), serializedValue, 0); + byte[] serializedValue = new byte[newSize]; + valueSerializer.serializeNative(value.getValue(), serializedValue, 0); - setBinaryValue(entryPosition, serializedValue); - return true; - } + byte[] oldSerializedValue = pagePointer.get(entryPosition, oldSize); + + if (ODefaultComparator.INSTANCE.compare(oldSerializedValue, serializedValue) == 0) + return 0; + + setBinaryValue(entryPosition, serializedValue); - return false; + return 1; } public void setLeftSibling(long pageIndex) throws IOException { diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsai.java b/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsai.java index 095deda3bad..46952085e59 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsai.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsai.java @@ -17,7 +17,13 @@ package com.orientechnologies.orient.core.index.sbtreebonsai.local; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; import com.orientechnologies.common.collection.OAlwaysGreaterKey; import com.orientechnologies.common.collection.OAlwaysLessKey; @@ -87,20 +93,51 @@ public OSBTreeBonsai(String dataFileExtension, int keySize, boolean durableInNon public void create(String name, OBinarySerializer keySerializer, OBinarySerializer valueSerializer, OStorageLocalAbstract storageLocal) { - acquireExclusiveLock(); try { this.storage = storageLocal; this.diskCache = storage.getDiskCache(); + this.keySerializer = keySerializer; + this.valueSerializer = valueSerializer; + + this.fileId = diskCache.openFile(name + dataFileExtension); this.name = name; + + initAfterCreate(); + } catch (IOException e) { + throw new OSBTreeException("Error creation of sbtree with name" + name, e); + } + create(fileId, keySerializer, valueSerializer, storageLocal); + } + + public void create(long fileId, OBinarySerializer keySerializer, OBinarySerializer valueSerializer, + OStorageLocalAbstract storageLocal) { + acquireExclusiveLock(); + try { + this.storage = storageLocal; + + this.diskCache = storage.getDiskCache(); + this.keySerializer = keySerializer; this.valueSerializer = valueSerializer; - fileId = diskCache.openFile(name + dataFileExtension); + diskCache.openFile(fileId); + this.fileId = fileId; + this.name = resolveTreeName(fileId); - initDurableComponent(storageLocal); + initAfterCreate(); + } catch (IOException e) { + throw new OSBTreeException("Error creation of sbtree with name" + name, e); + } finally { + releaseExclusiveLock(); + } + } + private void initAfterCreate() { + initDurableComponent(storage); + + try { initSysBucket(); super.startDurableOperation(null); @@ -134,8 +171,6 @@ public void create(String name, OBinarySerializer keySerializer, OBinarySeria OLogManager.instance().error(this, "Error during sbtree data rollback", e1); } throw new OSBTreeException("Error creation of sbtree with name" + name, e); - } finally { - releaseExclusiveLock(); } } @@ -153,6 +188,15 @@ public String getName() { } } + public long getFileId() { + acquireSharedLock(); + try { + return fileId; + } finally { + releaseSharedLock(); + } + } + public OBonsaiBucketPointer getRootBucketPointer() { acquireSharedLock(); try { @@ -188,7 +232,7 @@ public V get(K key) { } } - public void put(K key, V value) { + public boolean put(K key, V value) { acquireExclusiveLock(); final OStorageTransaction transaction = storage.getStorageTransaction(); try { @@ -205,24 +249,18 @@ public void put(K key, V value) { bucketPointer.getPageOffset(), keySerializer, valueSerializer, getTrackMode()); final boolean itemFound = bucketSearchResult.itemIndex >= 0; - + boolean result = true; if (itemFound) { - while (!keyBucket.updateValue(bucketSearchResult.itemIndex, value)) { - keyBucketPointer.releaseExclusiveLock(); - diskCache.release(keyBucketCacheEntry); - - bucketSearchResult = splitBucket(bucketSearchResult.path, bucketSearchResult.itemIndex, key); - bucketPointer = bucketSearchResult.getLastPathItem(); - - keyBucketCacheEntry = diskCache.load(fileId, bucketPointer.getPageIndex(), false); - keyBucketPointer = keyBucketCacheEntry.getCachePointer(); - keyBucketPointer.acquireExclusiveLock(); + final int updateResult = keyBucket.updateValue(bucketSearchResult.itemIndex, value); - keyBucket = new OSBTreeBonsaiBucket(keyBucketPointer.getDataPointer(), bucketPointer.getPageOffset(), - keySerializer, valueSerializer, getTrackMode()); + if (updateResult == 1) { + logPageChanges(keyBucket, fileId, bucketSearchResult.getLastPathItem().getPageIndex(), false); + keyBucketCacheEntry.markDirty(); } - logPageChanges(keyBucket, fileId, bucketSearchResult.getLastPathItem().getPageIndex(), false); + assert updateResult == 0 || updateResult == 1; + + result = updateResult != 0; } else { int insertionIndex = -bucketSearchResult.itemIndex - 1; @@ -245,9 +283,9 @@ public void put(K key, V value) { } logPageChanges(keyBucket, fileId, bucketPointer.getPageIndex(), false); + keyBucketCacheEntry.markDirty(); } - keyBucketCacheEntry.markDirty(); keyBucketPointer.releaseExclusiveLock(); diskCache.release(keyBucketCacheEntry); @@ -255,6 +293,7 @@ public void put(K key, V value) { setSize(size() + 1); endDurableOperation(transaction, false); + return result; } catch (IOException e) { rollback(transaction); throw new OSBTreeException("Error during index update with key " + key + " and value " + value, e); @@ -409,16 +448,25 @@ private void attachFreeListHead(OBonsaiBucketPointer bucketPointer, OBonsaiBucke public void delete() { acquireExclusiveLock(); + OStorageTransaction transaction = storage.getStorageTransaction(); try { - diskCache.deleteFile(fileId); + startDurableOperation(transaction); + + final Queue subTreesToDelete = new LinkedList(); + subTreesToDelete.add(rootBucketPointer); + recycleSubTrees(subTreesToDelete); + + endDurableOperation(transaction, false); } catch (IOException e) { + rollback(transaction); + throw new OSBTreeException("Error during delete of sbtree with name " + name, e); } finally { releaseExclusiveLock(); } } - public void load(String name, OBonsaiBucketPointer rootBucketPointer, OStorageLocalAbstract storageLocal) { + public void load(long fileId, OBonsaiBucketPointer rootBucketPointer, OStorageLocalAbstract storageLocal) { acquireExclusiveLock(); try { this.storage = storageLocal; @@ -426,11 +474,11 @@ public void load(String name, OBonsaiBucketPointer rootBucketPointer, OStorageLo diskCache = storage.getDiskCache(); - this.name = name; - - fileId = diskCache.openFile(name + dataFileExtension); + diskCache.openFile(fileId); + this.fileId = fileId; + this.name = resolveTreeName(fileId); - OCacheEntry rootCacheEntry = diskCache.load(fileId, this.rootBucketPointer.getPageIndex(), false); + OCacheEntry rootCacheEntry = diskCache.load(this.fileId, this.rootBucketPointer.getPageIndex(), false); OCachePointer rootPointer = rootCacheEntry.getCachePointer(); try { OSBTreeBonsaiBucket rootBucket = new OSBTreeBonsaiBucket(rootPointer.getDataPointer(), @@ -445,12 +493,17 @@ public void load(String name, OBonsaiBucketPointer rootBucketPointer, OStorageLo initDurableComponent(storageLocal); } catch (IOException e) { - throw new OSBTreeException("Exception during loading of sbtree " + name, e); + throw new OSBTreeException("Exception during loading of sbtree " + fileId, e); } finally { releaseExclusiveLock(); } } + private String resolveTreeName(long fileId) { + final String fileName = diskCache.fileNameById(fileId); + return fileName.substring(0, fileName.length() - dataFileExtension.length()); + } + private void setSize(long size) throws IOException { OCacheEntry rootCacheEntry = diskCache.load(fileId, rootBucketPointer.getPageIndex(), false); @@ -1291,6 +1344,10 @@ private AllocationResult reuseBucketFromFreeList(OSysBucket sysBucket) throws IO return new AllocationResult(oldFreeListHead, cacheEntry, false); } + public String getFileName() { + return name + dataFileExtension; + } + private static class AllocationResult { private final OBonsaiBucketPointer pointer; private final OCacheEntry cacheEntry; diff --git a/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsaiBucket.java b/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsaiBucket.java index ba671afb796..f23c00bbd7f 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsaiBucket.java +++ b/core/src/main/java/com/orientechnologies/orient/core/index/sbtreebonsai/local/OSBTreeBonsaiBucket.java @@ -263,8 +263,15 @@ public boolean addEntry(int index, SBTreeEntry treeEntry, boolean updateNe int size = size(); int freePointer = getIntValue(offset + FREE_POINTER_OFFSET); - if (freePointer - entrySize < (size + 1) * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET) - return false; + if (freePointer - entrySize < (size + 1) * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET) { + if (size > 1) + return false; + else + throw new OSBTreeException("Entry size ('key + value') is more than is more than allowed " + + (freePointer - 2 * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET) + + " bytes, either increase page size using '" + OGlobalConfiguration.SBTREEBONSAI_BUCKET_SIZE.getKey() + + "' parameter, or decrease 'key + value' size."); + } if (index <= size - 1) { moveData(offset + POSITIONS_ARRAY_OFFSET + index * OIntegerSerializer.INT_SIZE, offset + POSITIONS_ARRAY_OFFSET + (index + 1) @@ -318,29 +325,25 @@ public boolean addEntry(int index, SBTreeEntry treeEntry, boolean updateNe return true; } - public boolean updateValue(int index, V value) throws IOException { - if (valueSerializer.isFixedLength()) { - int entryPosition = getIntValue(offset + index * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET); + public int updateValue(int index, V value) throws IOException { + assert valueSerializer.isFixedLength(); - entryPosition += keySerializer.getObjectSizeInDirectMemory(pagePointer, offset + entryPosition); + int entryPosition = getIntValue(offset + index * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET); + entryPosition += keySerializer.getObjectSizeInDirectMemory(pagePointer, offset + entryPosition); - byte[] serializedValue = new byte[valueSerializer.getFixedLength()]; - valueSerializer.serializeNative(value, serializedValue, 0); + final int size = valueSerializer.getFixedLength(); - setBinaryValue(offset + entryPosition, serializedValue); - return true; - } + byte[] serializedValue = new byte[size]; + valueSerializer.serializeNative(value, serializedValue, 0); - final int entryPosition = getIntValue(offset + index * OIntegerSerializer.INT_SIZE + POSITIONS_ARRAY_OFFSET); + byte[] oldSerializedValue = pagePointer.get(offset + entryPosition, size); - int entreeSize = keySerializer.getObjectSizeInDirectMemory(pagePointer, offset + entryPosition); - entreeSize += valueSerializer.getObjectSize(value); + if (ODefaultComparator.INSTANCE.compare(oldSerializedValue, serializedValue) == 0) + return 0; - checkEntreeSize(entreeSize); + setBinaryValue(offset + entryPosition, serializedValue); - final K key = getKey(index); - remove(index); - return addEntry(index, new SBTreeEntry(OBonsaiBucketPointer.NULL, OBonsaiBucketPointer.NULL, key, value), false); + return 1; } private void checkEntreeSize(int entreeSize) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OClassImpl.java b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OClassImpl.java index 23cd2cd6d36..7b7f7d8dfc0 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OClassImpl.java +++ b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OClassImpl.java @@ -834,6 +834,7 @@ public static int[] readableClusters(final ODatabaseRecord iDatabase, final int[ iDatabase.checkSecurity(ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_READ, clusterName); listOfReadableIds.add(clusterId); } catch (OSecurityAccessException securityException) { + all = false; // if the cluster is inaccessible it's simply not processed in the list.add } } @@ -1179,6 +1180,14 @@ public OIndex createIndex(final String iName, String iType, final OProgressLi final OIndexDefinition indexDefinition = OIndexDefinitionFactory.createIndexDefinition(this, Arrays.asList(fields), extractFieldTypes(fields)); + if (fields.length == 1) { + // TRY TO DETERMINE THE COLLATE IF ANY + final OProperty p = getProperty(fields[0]); + if (p != null) { + indexDefinition.setCollate(p.getCollate()); + } + } + return getDatabase().getMetadata().getIndexManager() .createIndex(iName, iType, indexDefinition, polymorphicClusterIds, iProgressListener); } diff --git a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OProperty.java b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OProperty.java index 2f331bec59b..aab8c980b02 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OProperty.java +++ b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OProperty.java @@ -18,6 +18,7 @@ import java.util.Collection; import java.util.Set; +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.index.OIndex; /** @@ -28,8 +29,8 @@ */ public interface OProperty extends Comparable { - public static enum ATTRIBUTES { - LINKEDTYPE, LINKEDCLASS, MIN, MAX, MANDATORY, NAME, NOTNULL, REGEXP, TYPE, CUSTOM, READONLY + public static enum ATTRIBUTES { + LINKEDTYPE, LINKEDCLASS, MIN, MAX, MANDATORY, NAME, NOTNULL, REGEXP, TYPE, CUSTOM, READONLY, COLLATE } public String getName(); @@ -58,6 +59,10 @@ public static enum ATTRIBUTES { public OProperty setNotNull(boolean iNotNull); + public OCollate getCollate(); + + public OProperty setCollate(String iCollateName); + public boolean isMandatory(); public OProperty setMandatory(boolean mandatory); @@ -65,6 +70,7 @@ public static enum ATTRIBUTES { boolean isReadonly(); OPropertyImpl setReadonly(boolean iReadonly); + /** * Min behavior depends on the Property OType. *

@@ -191,8 +197,11 @@ public static enum ATTRIBUTES { public String getCustom(final String iName); public OPropertyImpl setCustom(final String iName, final String iValue); + public void removeCustom(final String iName); + public void clearCustom(); + public Set getCustomKeys(); public Object get(ATTRIBUTES iAttribute); diff --git a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OPropertyImpl.java b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OPropertyImpl.java index 497d8f0540b..330f31635e8 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OPropertyImpl.java +++ b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OPropertyImpl.java @@ -16,11 +16,22 @@ package com.orientechnologies.orient.core.metadata.schema; import java.text.ParseException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; import com.orientechnologies.common.comparator.OCaseInsentiveComparator; import com.orientechnologies.common.util.OCollections; import com.orientechnologies.orient.core.annotation.OBeforeSerialization; +import com.orientechnologies.orient.core.collate.OCollate; +import com.orientechnologies.orient.core.collate.ODefaultCollate; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.ODatabaseRecord; import com.orientechnologies.orient.core.db.record.ORecordElement; @@ -34,6 +45,7 @@ import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper; import com.orientechnologies.orient.core.sql.OCommandSQL; +import com.orientechnologies.orient.core.sql.OSQLEngine; import com.orientechnologies.orient.core.storage.OStorageProxy; import com.orientechnologies.orient.core.type.ODocumentWrapperNoClass; @@ -60,6 +72,7 @@ public class OPropertyImpl extends ODocumentWrapperNoClass implements OProperty private String regexp; private boolean readonly; private Map customFields; + private OCollate collate = new ODefaultCollate(); /** * Constructor used in unmarshalling. @@ -480,6 +493,8 @@ public Object get(final ATTRIBUTES iAttribute) { return getRegexp(); case TYPE: return getType(); + case COLLATE: + return getCollate(); } throw new IllegalArgumentException("Cannot find attribute '" + iAttribute + "'"); @@ -523,6 +538,9 @@ public void setInternalAndSave(final ATTRIBUTES attribute, final Object iValue) case TYPE: setTypeInternal(isNull ? null : OType.valueOf(stringValue.toUpperCase(Locale.ENGLISH))); break; + case COLLATE: + setCollateInternal(stringValue); + break; case CUSTOM: if (iValue.toString().indexOf("=") == -1) { if (iValue.toString().equalsIgnoreCase("clear")) { @@ -581,6 +599,9 @@ public void set(final ATTRIBUTES attribute, final Object iValue) { case TYPE: setType(OType.valueOf(stringValue.toUpperCase(Locale.ENGLISH))); break; + case COLLATE: + setCollate(stringValue); + break; case CUSTOM: if (iValue.toString().indexOf("=") == -1) { if (iValue.toString().equalsIgnoreCase("clear")) { @@ -595,6 +616,36 @@ public void set(final ATTRIBUTES attribute, final Object iValue) { } } + public OCollate getCollate() { + return collate; + } + + public OProperty setCollate(final OCollate collate) { + if (collate == null) + throw new IllegalArgumentException("COLLATE cannot be null"); + this.collate = collate; + return this; + } + + public OProperty setCollate(String iCollate) { + if (iCollate == null) + iCollate = ODefaultCollate.NAME; + + getDatabase().checkSecurity(ODatabaseSecurityResources.SCHEMA, ORole.PERMISSION_UPDATE); + final String cmd = String.format("alter property %s collate %s", getFullName(), iCollate); + getDatabase().command(new OCommandSQL(cmd)).execute(); + setCollateInternal(iCollate); + return this; + } + + public OProperty setCollateInternal(String iCollate) { + if (iCollate == null) + iCollate = ODefaultCollate.NAME; + + collate = OSQLEngine.getCollate(iCollate); + return this; + } + @Override public String toString() { return name + " (type=" + type + ")"; @@ -635,6 +686,8 @@ public void fromStream() { mandatory = document.containsField("mandatory") ? (Boolean) document.field("mandatory") : false; readonly = document.containsField("readonly") ? (Boolean) document.field("readonly") : false; notNull = document.containsField("notNull") ? (Boolean) document.field("notNull") : false; + if (document.containsField("collate")) + setCollateInternal((String) document.field("collate")); min = (String) (document.containsField("min") ? document.field("min") : null); max = (String) (document.containsField("max") ? document.field("max") : null); @@ -679,6 +732,7 @@ public ODocument toStream() { document.field("linkedClass", linkedClass != null ? linkedClass.getName() : linkedClassName); document.field("customFields", customFields != null && customFields.size() > 0 ? customFields : null, OType.EMBEDDEDMAP); + document.field("collate", collate.getName()); } finally { document.setInternalStatus(ORecordElement.STATUS.LOADED); diff --git a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OSchemaShared.java b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OSchemaShared.java index 4c1c835a099..33b36f3b0f6 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OSchemaShared.java +++ b/core/src/main/java/com/orientechnologies/orient/core/metadata/schema/OSchemaShared.java @@ -220,7 +220,7 @@ public OClass call() throws Exception { }, true); } - public OClass createClassInternal(final String iClassName, final OClass iSuperClass, final int[] iClusterIds) { + public OClass createClassInternal(final String iClassName, final OClass superClass, final int[] iClusterIds) { if (iClassName == null || iClassName.length() == 0) throw new OSchemaException("Found class name null"); @@ -242,6 +242,7 @@ public OClass createClassInternal(final String iClassName, final OClass iSuperCl final String key = iClassName.toLowerCase(); final OSchemaShared me = this; + return getDatabase().getStorage().callInLock(new Callable() { @Override public OClass call() throws Exception { @@ -255,19 +256,19 @@ public OClass call() throws Exception { // BIND SHORT NAME TOO classes.put(cls.getShortName().toLowerCase(), cls); - if (iSuperClass != null) { - cls.setSuperClassInternal(iSuperClass); + if (superClass != null) { + cls.setSuperClassInternal(superClass); // UPDATE INDEXES - final int[] clustersToIndex = iSuperClass.getPolymorphicClusterIds(); + final int[] clustersToIndex = superClass.getPolymorphicClusterIds(); final String[] clusterNames = new String[clustersToIndex.length]; for (int i = 0; i < clustersToIndex.length; i++) clusterNames[i] = database.getClusterNameById(clustersToIndex[i]); - for (OIndex index : iSuperClass.getIndexes()) + for (OIndex index : superClass.getIndexes()) for (String clusterName : clusterNames) if (clusterName != null) - index.getInternal().addCluster(clusterName); + database.getMetadata().getIndexManager().addClusterToIndex(clusterName, index.getName()); } return cls; diff --git a/core/src/main/java/com/orientechnologies/orient/core/metadata/security/OSecurityShared.java b/core/src/main/java/com/orientechnologies/orient/core/metadata/security/OSecurityShared.java index 54309cf8ac3..8bf6ccc6232 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/metadata/security/OSecurityShared.java +++ b/core/src/main/java/com/orientechnologies/orient/core/metadata/security/OSecurityShared.java @@ -404,7 +404,7 @@ else if (roleClass.getSuperClass() == null) roleClass.setSuperClass(identityClass); if (!roleClass.existsProperty("name")) { - roleClass.createProperty("name", OType.STRING).setMandatory(true).setNotNull(true); + roleClass.createProperty("name", OType.STRING).setMandatory(true).setNotNull(true).setCollate("ci"); roleClass.createIndex("ORole.name", INDEX_TYPE.UNIQUE, ONullOutputListener.INSTANCE, "name"); } else { final Set> indexes = roleClass.getInvolvedIndexes("name"); @@ -427,7 +427,7 @@ else if (userClass.getSuperClass() == null) userClass.setSuperClass(identityClass); if (!userClass.existsProperty("name")) { - userClass.createProperty("name", OType.STRING).setMandatory(true).setNotNull(true); + userClass.createProperty("name", OType.STRING).setMandatory(true).setNotNull(true).setCollate("ci"); userClass.createIndex("OUser.name", INDEX_TYPE.UNIQUE, ONullOutputListener.INSTANCE, "name"); } if (!userClass.existsProperty("password")) diff --git a/core/src/main/java/com/orientechnologies/orient/core/query/OQueryRuntimeValueMulti.java b/core/src/main/java/com/orientechnologies/orient/core/query/OQueryRuntimeValueMulti.java index 3a1a48d0c8f..8ee69fdf606 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/query/OQueryRuntimeValueMulti.java +++ b/core/src/main/java/com/orientechnologies/orient/core/query/OQueryRuntimeValueMulti.java @@ -15,6 +15,9 @@ */ package com.orientechnologies.orient.core.query; +import java.util.List; + +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.sql.filter.OSQLFilterItemFieldMultiAbstract; /** @@ -24,32 +27,43 @@ * */ public class OQueryRuntimeValueMulti { - protected OSQLFilterItemFieldMultiAbstract definition; - public Object[] values; - - public OQueryRuntimeValueMulti(final OSQLFilterItemFieldMultiAbstract iDefinition, final Object[] iValues) { - definition = iDefinition; - values = iValues; - } - - @Override - public String toString() { - if (values == null) - return ""; - - StringBuilder buffer = new StringBuilder(); - buffer.append("["); - int i = 0; - for (Object v : values) { - if (i++ > 0) - buffer.append(","); - buffer.append(v); - } - buffer.append("]"); - return buffer.toString(); - } - - public OSQLFilterItemFieldMultiAbstract getDefinition() { - return definition; - } + protected final OSQLFilterItemFieldMultiAbstract definition; + protected final List collates; + protected final Object[] values; + + public OQueryRuntimeValueMulti(final OSQLFilterItemFieldMultiAbstract iDefinition, final Object[] iValues, + final List iCollates) { + definition = iDefinition; + values = iValues; + collates = iCollates; + } + + @Override + public String toString() { + if (getValues() == null) + return ""; + + StringBuilder buffer = new StringBuilder(); + buffer.append("["); + int i = 0; + for (Object v : getValues()) { + if (i++ > 0) + buffer.append(","); + buffer.append(v); + } + buffer.append("]"); + return buffer.toString(); + } + + public OSQLFilterItemFieldMultiAbstract getDefinition() { + return definition; + } + + public OCollate getCollate(final int iIndex) { + return collates.get(iIndex); + } + + public Object[] getValues() { + return values; + } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/serialization/OBase64Utils.java b/core/src/main/java/com/orientechnologies/orient/core/serialization/OBase64Utils.java index 4c9e000206c..87d5a06be6a 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/serialization/OBase64Utils.java +++ b/core/src/main/java/com/orientechnologies/orient/core/serialization/OBase64Utils.java @@ -590,7 +590,7 @@ public static String encodeObject(java.io.Serializable serializableObject, int o b64os = new OBase64Utils.OutputStream(baos, ENCODE | options); if ((options & GZIP) != 0) { // Gzip - gzos = new java.util.zip.GZIPOutputStream(b64os); + gzos = new java.util.zip.GZIPOutputStream(b64os, 16384); // 16KB oos = new java.io.ObjectOutputStream(gzos); } else { // Not gzipped @@ -888,7 +888,7 @@ public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int opt // GZip -> Base64 -> ByteArray baos = new java.io.ByteArrayOutputStream(); b64os = new OBase64Utils.OutputStream(baos, ENCODE | options); - gzos = new java.util.zip.GZIPOutputStream(b64os); + gzos = new java.util.zip.GZIPOutputStream(b64os, 16384); // 16KB gzos.write(source, off, len); gzos.close(); @@ -1228,7 +1228,7 @@ public static byte[] decode(String s, int options) { try { baos = new java.io.ByteArrayOutputStream(); bais = new java.io.ByteArrayInputStream(bytes); - gzis = new java.util.zip.GZIPInputStream(bais); + gzis = new java.util.zip.GZIPInputStream(bais, 16384); // 16KB while ((length = gzis.read(buffer)) >= 0) { baos.write(buffer, 0, length); diff --git a/core/src/main/java/com/orientechnologies/orient/core/serialization/compression/impl/OGZIPCompression.java b/core/src/main/java/com/orientechnologies/orient/core/serialization/compression/impl/OGZIPCompression.java index 65021be457c..c3624aa714f 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/serialization/compression/impl/OGZIPCompression.java +++ b/core/src/main/java/com/orientechnologies/orient/core/serialization/compression/impl/OGZIPCompression.java @@ -39,7 +39,7 @@ public byte[] compress(final byte[] content) { try { final byte[] result; final OMemoryStream memoryOutputStream = new OMemoryStream(); - final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(memoryOutputStream); + final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(memoryOutputStream, 16384); // 16KB try { gzipOutputStream.write(content); gzipOutputStream.finish(); @@ -58,7 +58,7 @@ public byte[] compress(final byte[] content) { public byte[] uncompress(byte[] content) { try { final OMemoryInputStream memoryInputStream = new OMemoryInputStream(content); - final GZIPInputStream gzipInputStream = new GZIPInputStream(memoryInputStream); + final GZIPInputStream gzipInputStream = new GZIPInputStream(memoryInputStream, 16384); // 16KB try { final byte[] buffer = new byte[1024]; diff --git a/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/binary/OBinarySerializerFactory.java b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/binary/OBinarySerializerFactory.java index d0080d6c9c1..0bba5b4ea25 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/binary/OBinarySerializerFactory.java +++ b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/binary/OBinarySerializerFactory.java @@ -40,6 +40,7 @@ import com.orientechnologies.orient.core.serialization.serializer.binary.impl.index.OCompositeKeySerializer; import com.orientechnologies.orient.core.serialization.serializer.binary.impl.index.OSimpleKeySerializer; import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerListRID; +import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerOldRIDContainer; import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerRID; import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerSBTreeIndexRIDContainer; import com.orientechnologies.orient.core.storage.impl.local.eh.OClusterPositionSerializer; @@ -89,6 +90,7 @@ private OBinarySerializerFactory() { registerSerializer(ODecimalSerializer.INSTANCE, OType.DECIMAL); registerSerializer(OStreamSerializerListRID.INSTANCE, null); + registerSerializer(OStreamSerializerOldRIDContainer.INSTANCE, null); registerSerializer(OStreamSerializerSBTreeIndexRIDContainer.INSTANCE, null); registerSerializer(OPhysicalPositionSerializer.INSTANCE, null); diff --git a/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/stream/OStreamSerializerOldRIDContainer.java b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/stream/OStreamSerializerOldRIDContainer.java new file mode 100644 index 00000000000..dd6115c3036 --- /dev/null +++ b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/stream/OStreamSerializerOldRIDContainer.java @@ -0,0 +1,187 @@ +/* + * Copyright 2010-2012 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.core.serialization.serializer.stream; + +import java.io.IOException; + +import com.orientechnologies.common.directmemory.ODirectMemoryPointer; +import com.orientechnologies.common.serialization.types.OBinarySerializer; +import com.orientechnologies.common.serialization.types.OBinaryTypeSerializer; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainerSBTree; +import com.orientechnologies.orient.core.index.sbtreebonsai.local.OBonsaiBucketPointer; +import com.orientechnologies.orient.core.metadata.schema.OType; +import com.orientechnologies.orient.core.record.impl.ODocument; +import com.orientechnologies.orient.core.serialization.OBinaryProtocol; +import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper; +import com.orientechnologies.orient.core.serialization.serializer.record.ORecordSerializerFactory; +import com.orientechnologies.orient.core.serialization.serializer.record.string.ORecordSerializerSchemaAware2CSV; + +/** + * Created to make + */ +public class OStreamSerializerOldRIDContainer implements OStreamSerializer, OBinarySerializer { + public static final String NAME = "ic"; + public static final OStreamSerializerOldRIDContainer INSTANCE = new OStreamSerializerOldRIDContainer(); + private static final ORecordSerializerSchemaAware2CSV FORMAT = (ORecordSerializerSchemaAware2CSV) ORecordSerializerFactory + .instance().getFormat(ORecordSerializerSchemaAware2CSV.NAME); + + public static final byte ID = 20; + + public Object fromStream(final byte[] iStream) throws IOException { + if (iStream == null) + return null; + + final String s = OBinaryProtocol.bytes2string(iStream); + + return FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); + } + + public byte[] toStream(final Object object) throws IOException { + if (object == null) + return null; + + return containerToStream((OIndexRIDContainerSBTree) object); + } + + public String getName() { + return NAME; + } + + @Override + public int getObjectSize(OIndexRIDContainerSBTree object, Object... hints) { + final byte[] serializedSet = containerToStream(object); + return OBinaryTypeSerializer.INSTANCE.getObjectSize(serializedSet); + } + + @Override + public int getObjectSize(byte[] stream, int startPosition) { + return OBinaryTypeSerializer.INSTANCE.getObjectSize(stream, startPosition); + } + + @Override + public void serialize(OIndexRIDContainerSBTree object, byte[] stream, int startPosition, Object... hints) { + final byte[] serializedSet = containerToStream(object); + OBinaryTypeSerializer.INSTANCE.serialize(serializedSet, stream, startPosition); + } + + @Override + public OIndexRIDContainerSBTree deserialize(byte[] stream, int startPosition) { + final byte[] serializedSet = OBinaryTypeSerializer.INSTANCE.deserialize(stream, startPosition); + + final String s = OBinaryProtocol.bytes2string(serializedSet); + + if (s.startsWith("<#@")) { + return containerFromStream(s); + } + + return (OIndexRIDContainerSBTree) FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); + } + + @Override + public byte getId() { + return ID; + } + + @Override + public boolean isFixedLength() { + return false; + } + + @Override + public int getFixedLength() { + return 0; + } + + @Override + public void serializeNative(OIndexRIDContainerSBTree object, byte[] stream, int startPosition, Object... hints) { + final byte[] serializedSet = containerToStream(object); + OBinaryTypeSerializer.INSTANCE.serializeNative(serializedSet, stream, startPosition); + + } + + @Override + public OIndexRIDContainerSBTree deserializeNative(byte[] stream, int startPosition) { + final byte[] serializedSet = OBinaryTypeSerializer.INSTANCE.deserializeNative(stream, startPosition); + + final String s = OBinaryProtocol.bytes2string(serializedSet); + + if (s.startsWith("<#@")) { + return containerFromStream(s); + } + + return (OIndexRIDContainerSBTree) FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); + } + + @Override + public int getObjectSizeNative(byte[] stream, int startPosition) { + return OBinaryTypeSerializer.INSTANCE.getObjectSizeNative(stream, startPosition); + } + + @Override + public void serializeInDirectMemory(OIndexRIDContainerSBTree object, ODirectMemoryPointer pointer, long offset, Object... hints) { + final byte[] serializedSet = containerToStream(object); + OBinaryTypeSerializer.INSTANCE.serializeInDirectMemory(serializedSet, pointer, offset); + } + + @Override + public OIndexRIDContainerSBTree deserializeFromDirectMemory(ODirectMemoryPointer pointer, long offset) { + final byte[] serializedSet = OBinaryTypeSerializer.INSTANCE.deserializeFromDirectMemory(pointer, offset); + + final String s = OBinaryProtocol.bytes2string(serializedSet); + + if (s.startsWith("<#@")) { + return containerFromStream(s); + } + + return (OIndexRIDContainerSBTree) FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); + } + + @Override + public int getObjectSizeInDirectMemory(ODirectMemoryPointer pointer, long offset) { + return OBinaryTypeSerializer.INSTANCE.getObjectSizeInDirectMemory(pointer, offset); + } + + @Override + public OIndexRIDContainerSBTree preprocess(OIndexRIDContainerSBTree value, Object... hints) { + return value; + } + + private byte[] containerToStream(OIndexRIDContainerSBTree object) { + StringBuilder iOutput = new StringBuilder(); + iOutput.append(OStringSerializerHelper.LINKSET_PREFIX); + + final ODocument document = new ODocument(); + document.field("rootIndex", object.getRootPointer().getPageIndex()); + document.field("rootOffset", object.getRootPointer().getPageOffset()); + document.field("file", object.getFileName()); + iOutput.append(new String(document.toStream())); + + iOutput.append(OStringSerializerHelper.SET_END); + return iOutput.toString().getBytes(); + } + + private OIndexRIDContainerSBTree containerFromStream(String stream) { + stream = stream.substring(OStringSerializerHelper.LINKSET_PREFIX.length(), stream.length() - 1); + + final ODocument doc = new ODocument(); + doc.fromString(stream); + final OBonsaiBucketPointer rootPointer = new OBonsaiBucketPointer((Long) doc.field("rootIndex"), + (Integer) doc.field("rootOffset")); + final String fileName = doc.field("file"); + + return new OIndexRIDContainerSBTree(fileName, rootPointer); + } +} diff --git a/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/stream/OStreamSerializerSBTreeIndexRIDContainer.java b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/stream/OStreamSerializerSBTreeIndexRIDContainer.java index 20a94acef27..476df6a391a 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/stream/OStreamSerializerSBTreeIndexRIDContainer.java +++ b/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/stream/OStreamSerializerSBTreeIndexRIDContainer.java @@ -15,41 +15,61 @@ */ package com.orientechnologies.orient.core.serialization.serializer.stream; -import com.orientechnologies.common.directmemory.ODirectMemoryPointer; -import com.orientechnologies.common.serialization.types.OBinarySerializer; -import com.orientechnologies.common.serialization.types.OBinaryTypeSerializer; -import com.orientechnologies.orient.core.db.record.ridset.sbtree.OSBTreeIndexRIDContainer; -import com.orientechnologies.orient.core.db.record.ridset.sbtree.OSBTreeRIDSet; -import com.orientechnologies.orient.core.metadata.schema.OType; -import com.orientechnologies.orient.core.serialization.OBinaryProtocol; -import com.orientechnologies.orient.core.serialization.serializer.record.ORecordSerializerFactory; -import com.orientechnologies.orient.core.serialization.serializer.record.string.ORecordSerializerSchemaAware2CSV; +import static com.orientechnologies.orient.core.serialization.serializer.binary.impl.OLinkSerializer.RID_SIZE; import java.io.IOException; +import java.util.HashSet; +import java.util.Set; -public class OStreamSerializerSBTreeIndexRIDContainer implements OStreamSerializer, OBinarySerializer { - public static final String NAME = "ic"; - public static final OStreamSerializerSBTreeIndexRIDContainer INSTANCE = new OStreamSerializerSBTreeIndexRIDContainer(); - private static final ORecordSerializerSchemaAware2CSV FORMAT = (ORecordSerializerSchemaAware2CSV) ORecordSerializerFactory - .instance().getFormat( - ORecordSerializerSchemaAware2CSV.NAME); - - public static final byte ID = 20; +import com.orientechnologies.common.directmemory.ODirectMemoryPointer; +import com.orientechnologies.common.serialization.types.OBinarySerializer; +import com.orientechnologies.common.serialization.types.OBooleanSerializer; +import com.orientechnologies.common.serialization.types.OIntegerSerializer; +import com.orientechnologies.common.serialization.types.OLongSerializer; +import com.orientechnologies.orient.core.db.record.OIdentifiable; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainer; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainerSBTree; +import com.orientechnologies.orient.core.index.sbtreebonsai.local.OBonsaiBucketPointer; +import com.orientechnologies.orient.core.serialization.serializer.binary.impl.OLinkSerializer; + +public class OStreamSerializerSBTreeIndexRIDContainer implements OStreamSerializer, OBinarySerializer { + public static final String NAME = "icn"; + public static final OStreamSerializerSBTreeIndexRIDContainer INSTANCE = new OStreamSerializerSBTreeIndexRIDContainer(); + + public static final byte ID = 21; + public static final int FILE_ID_OFFSET = 0; + public static final int EMBEDDED_OFFSET = FILE_ID_OFFSET + + OLongSerializer.LONG_SIZE; + public static final int SBTREE_ROOTINDEX_OFFSET = EMBEDDED_OFFSET + + OBooleanSerializer.BOOLEAN_SIZE; + public static final int SBTREE_ROOTOFFSET_OFFSET = SBTREE_ROOTINDEX_OFFSET + + OLongSerializer.LONG_SIZE; + + public static final int EMBEDDED_SIZE_OFFSET = EMBEDDED_OFFSET + + OBooleanSerializer.BOOLEAN_SIZE; + public static final int EMBEDDED_VALUES_OFFSET = EMBEDDED_SIZE_OFFSET + + OIntegerSerializer.INT_SIZE; + + public static final OLongSerializer LONG_SERIALIZER = OLongSerializer.INSTANCE; + public static final OBooleanSerializer BOOLEAN_SERIALIZER = OBooleanSerializer.INSTANCE; + public static final OIntegerSerializer INT_SERIALIZER = OIntegerSerializer.INSTANCE; + public static final int SBTREE_CONTAINER_SIZE = OBooleanSerializer.BOOLEAN_SIZE + 2 + * OLongSerializer.LONG_SIZE + + OIntegerSerializer.INT_SIZE; + public static final OLinkSerializer LINK_SERIALIZER = OLinkSerializer.INSTANCE; public Object fromStream(final byte[] iStream) throws IOException { if (iStream == null) return null; - final String s = OBinaryProtocol.bytes2string(iStream); - - return FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); + throw new UnsupportedOperationException("not implemented yet"); } public byte[] toStream(final Object iObject) throws IOException { if (iObject == null) return null; - return ((OSBTreeRIDSet) iObject).toStream(); + throw new UnsupportedOperationException("not implemented yet"); } public String getName() { @@ -57,34 +77,27 @@ public String getName() { } @Override - public int getObjectSize(OSBTreeIndexRIDContainer object, Object... hints) { - final byte[] serializedSet = object.toStream(); - return OBinaryTypeSerializer.INSTANCE.getObjectSize(serializedSet); + public int getObjectSize(OIndexRIDContainer object, Object... hints) { + if (object.isEmbedded()) { + return embeddedObjectSerializedSize(object.size()); + } else { + return SBTREE_CONTAINER_SIZE; + } } @Override public int getObjectSize(byte[] stream, int startPosition) { - return OBinaryTypeSerializer.INSTANCE.getObjectSize(stream, startPosition); + throw new UnsupportedOperationException("not implemented yet"); } @Override - public void serialize(OSBTreeIndexRIDContainer object, byte[] stream, int startPosition, Object... hints) { - final byte[] serializedSet = object.toStream(); - OBinaryTypeSerializer.INSTANCE.serialize(serializedSet, stream, startPosition); + public void serialize(OIndexRIDContainer object, byte[] stream, int startPosition, Object... hints) { + throw new UnsupportedOperationException("not implemented yet"); } @Override - public OSBTreeIndexRIDContainer deserialize(byte[] stream, int startPosition) { - final byte[] serializedSet = OBinaryTypeSerializer.INSTANCE.deserialize(stream, startPosition); - - final String s = OBinaryProtocol.bytes2string(serializedSet); - - if (s.startsWith("<#@")) { - final OSBTreeIndexRIDContainer set = OSBTreeIndexRIDContainer.fromStream(s); - return set; - } - - return (OSBTreeIndexRIDContainer) FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); + public OIndexRIDContainer deserialize(byte[] stream, int startPosition) { + throw new UnsupportedOperationException("not implemented yet"); } @Override @@ -99,62 +112,121 @@ public boolean isFixedLength() { @Override public int getFixedLength() { - return 0; + throw new UnsupportedOperationException("Length is not fixed"); } @Override - public void serializeNative(OSBTreeIndexRIDContainer object, byte[] stream, int startPosition, Object... hints) { - final byte[] serializedSet = object.toStream(); - OBinaryTypeSerializer.INSTANCE.serializeNative(serializedSet, stream, startPosition); - + public void serializeNative(OIndexRIDContainer object, byte[] stream, int offset, Object... hints) { + LONG_SERIALIZER.serializeNative(object.getFileId(), stream, offset + FILE_ID_OFFSET); + + final boolean embedded = object.isEmbedded(); + BOOLEAN_SERIALIZER.serializeNative(embedded, stream, offset + EMBEDDED_OFFSET); + + if (embedded) { + INT_SERIALIZER.serializeNative(object.size(), stream, offset + EMBEDDED_SIZE_OFFSET); + + int p = offset + EMBEDDED_VALUES_OFFSET; + for (OIdentifiable ids : object) { + LINK_SERIALIZER.serializeNative(ids, stream, p); + p += RID_SIZE; + } + } else { + final OIndexRIDContainerSBTree underlying = (OIndexRIDContainerSBTree) object.getUnderlying(); + final OBonsaiBucketPointer rootPointer = underlying.getRootPointer(); + LONG_SERIALIZER.serializeNative(rootPointer.getPageIndex(), stream, offset + SBTREE_ROOTINDEX_OFFSET); + INT_SERIALIZER.serializeNative(rootPointer.getPageOffset(), stream, offset + SBTREE_ROOTOFFSET_OFFSET); + } } @Override - public OSBTreeIndexRIDContainer deserializeNative(byte[] stream, int startPosition) { - final byte[] serializedSet = OBinaryTypeSerializer.INSTANCE.deserializeNative(stream, startPosition); - - final String s = OBinaryProtocol.bytes2string(serializedSet); - - if (s.startsWith("<#@")) { - final OSBTreeIndexRIDContainer set = OSBTreeIndexRIDContainer.fromStream(s); - return set; + public OIndexRIDContainer deserializeNative(byte[] stream, int offset) { + final long fileId = LONG_SERIALIZER.deserializeNative(stream, offset + FILE_ID_OFFSET); + if (BOOLEAN_SERIALIZER.deserializeNative(stream, offset + EMBEDDED_OFFSET)) { + final int size = INT_SERIALIZER.deserializeNative(stream, offset + EMBEDDED_SIZE_OFFSET); + final Set underlying = new HashSet(Math.max((int) (size / .75f) + 1, 16)); + + int p = offset + EMBEDDED_VALUES_OFFSET; + for (int i = 0; i < size; i++) { + underlying.add(LINK_SERIALIZER.deserializeNative(stream, p)); + p += RID_SIZE; + } + + return new OIndexRIDContainer(fileId, underlying); + } else { + final long pageIndex = LONG_SERIALIZER.deserializeNative(stream, offset + SBTREE_ROOTINDEX_OFFSET); + final int pageOffset = INT_SERIALIZER.deserializeNative(stream, offset + SBTREE_ROOTOFFSET_OFFSET); + final OBonsaiBucketPointer rootPointer = new OBonsaiBucketPointer(pageIndex, pageOffset); + final OIndexRIDContainerSBTree underlying = new OIndexRIDContainerSBTree(fileId, rootPointer); + return new OIndexRIDContainer(fileId, underlying); } - - return (OSBTreeIndexRIDContainer) FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); } @Override public int getObjectSizeNative(byte[] stream, int startPosition) { - return OBinaryTypeSerializer.INSTANCE.getObjectSizeNative(stream, startPosition); + throw new UnsupportedOperationException("not implemented yet"); } @Override - public void serializeInDirectMemory(OSBTreeIndexRIDContainer object, ODirectMemoryPointer pointer, long offset, Object... hints) { - final byte[] serializedSet = object.toStream(); - OBinaryTypeSerializer.INSTANCE.serializeInDirectMemory(serializedSet, pointer, offset); + public void serializeInDirectMemory(OIndexRIDContainer object, ODirectMemoryPointer pointer, long offset, Object... hints) { + LONG_SERIALIZER.serializeInDirectMemory(object.getFileId(), pointer, offset + FILE_ID_OFFSET); + + final boolean embedded = object.isEmbedded(); + BOOLEAN_SERIALIZER.serializeInDirectMemory(embedded, pointer, offset + EMBEDDED_OFFSET); + + if (embedded) { + INT_SERIALIZER.serializeInDirectMemory(object.size(), pointer, offset + EMBEDDED_SIZE_OFFSET); + + long p = offset + EMBEDDED_VALUES_OFFSET; + for (OIdentifiable ids : object) { + LINK_SERIALIZER.serializeInDirectMemory(ids, pointer, p); + p += RID_SIZE; + } + } else { + final OIndexRIDContainerSBTree underlying = (OIndexRIDContainerSBTree) object.getUnderlying(); + final OBonsaiBucketPointer rootPointer = underlying.getRootPointer(); + LONG_SERIALIZER.serializeInDirectMemory(rootPointer.getPageIndex(), pointer, offset + SBTREE_ROOTINDEX_OFFSET); + INT_SERIALIZER.serializeInDirectMemory(rootPointer.getPageOffset(), pointer, offset + SBTREE_ROOTOFFSET_OFFSET); + } } @Override - public OSBTreeIndexRIDContainer deserializeFromDirectMemory(ODirectMemoryPointer pointer, long offset) { - final byte[] serializedSet = OBinaryTypeSerializer.INSTANCE.deserializeFromDirectMemory(pointer, offset); - - final String s = OBinaryProtocol.bytes2string(serializedSet); - - if (s.startsWith("<#@")) { - final OSBTreeIndexRIDContainer set = OSBTreeIndexRIDContainer.fromStream(s); - return set; + public OIndexRIDContainer deserializeFromDirectMemory(ODirectMemoryPointer pointer, long offset) { + final long fileId = LONG_SERIALIZER.deserializeFromDirectMemory(pointer, offset + FILE_ID_OFFSET); + if (BOOLEAN_SERIALIZER.deserializeFromDirectMemory(pointer, offset + EMBEDDED_OFFSET)) { + final int size = INT_SERIALIZER.deserializeFromDirectMemory(pointer, offset + EMBEDDED_SIZE_OFFSET); + final Set underlying = new HashSet(Math.max((int) (size / .75f) + 1, 16)); + + long p = offset + EMBEDDED_VALUES_OFFSET; + for (int i = 0; i < size; i++) { + underlying.add(LINK_SERIALIZER.deserializeFromDirectMemory(pointer, p)); + p += RID_SIZE; + } + + return new OIndexRIDContainer(fileId, underlying); + } else { + final long pageIndex = LONG_SERIALIZER.deserializeFromDirectMemory(pointer, offset + SBTREE_ROOTINDEX_OFFSET); + final int pageOffset = INT_SERIALIZER.deserializeFromDirectMemory(pointer, offset + SBTREE_ROOTOFFSET_OFFSET); + final OBonsaiBucketPointer rootPointer = new OBonsaiBucketPointer(pageIndex, pageOffset); + final OIndexRIDContainerSBTree underlying = new OIndexRIDContainerSBTree(fileId, rootPointer); + return new OIndexRIDContainer(fileId, underlying); } - - return (OSBTreeIndexRIDContainer) FORMAT.embeddedCollectionFromStream(null, OType.EMBEDDEDSET, null, OType.LINK, s); } @Override public int getObjectSizeInDirectMemory(ODirectMemoryPointer pointer, long offset) { - return OBinaryTypeSerializer.INSTANCE.getObjectSizeInDirectMemory(pointer, offset); + if (BOOLEAN_SERIALIZER.deserializeFromDirectMemory(pointer, offset + EMBEDDED_OFFSET)) { + return embeddedObjectSerializedSize(INT_SERIALIZER.deserializeFromDirectMemory(pointer, offset + EMBEDDED_SIZE_OFFSET)); + } else { + return SBTREE_CONTAINER_SIZE; + } } @Override - public OSBTreeIndexRIDContainer preprocess(OSBTreeIndexRIDContainer value, Object... hints) { + public OIndexRIDContainer preprocess(OIndexRIDContainer value, Object... hints) { return value; } + + private int embeddedObjectSerializedSize(int size) { + return OLongSerializer.LONG_SIZE + OBooleanSerializer.BOOLEAN_SIZE + OIntegerSerializer.INT_SIZE + size * RID_SIZE; + } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/OChainedIndexProxy.java b/core/src/main/java/com/orientechnologies/orient/core/sql/OChainedIndexProxy.java index 1b4804228cb..9e219764b13 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/OChainedIndexProxy.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/OChainedIndexProxy.java @@ -1,3 +1,18 @@ +/* + * Copyright 2010-2013 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.orientechnologies.orient.core.sql; import com.orientechnologies.common.listener.OProgressListener; @@ -51,6 +66,7 @@ public class OChainedIndexProxy implements OIndex { private final List> indexChain; private final OIndex lastIndex; + private final boolean isOneValue; /** * Create proxies that support maximum number of different operations. In case when several different indexes which support @@ -77,6 +93,16 @@ private OChainedIndexProxy(OIndex index, List> indexChain) { this.index = index; this.indexChain = Collections.unmodifiableList(indexChain); lastIndex = indexChain.get(indexChain.size() - 1); + + isOneValue = isAllOneValue(indexChain); + } + + private boolean isAllOneValue(List> indexChain) { + for (OIndex oIndex : indexChain) { + if (!(oIndex.getInternal() instanceof OIndexOneValue)) + return false; + } + return true; } public String getDatabaseName() { @@ -126,7 +152,7 @@ public boolean addResult(OIdentifiable value) { } }); - if (getInternal() instanceof OIndexOneValue) + if (isOneValue) return (T) (result.isEmpty() ? null : result.iterator().next()); return (T) result; @@ -550,7 +576,7 @@ public OIndex put(Object iKey, OIdentifiable iValue) { throw new UnsupportedOperationException("Not allowed operation"); } - public boolean remove(Object iKey) { + public boolean remove(Object key) { throw new UnsupportedOperationException("Not allowed operation"); } @@ -587,6 +613,11 @@ public OIndex delete() { throw new UnsupportedOperationException("Not allowed operation"); } + @Override + public void deleteWithoutIndexLoad(String indexName) { + throw new UnsupportedOperationException("Not allowed operation"); + } + public String getType() { throw new UnsupportedOperationException("Not allowed operation"); } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLCreateIndex.java b/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLCreateIndex.java index a0e0431bbae..a16fd7ec87f 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLCreateIndex.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLCreateIndex.java @@ -154,7 +154,7 @@ public OCommandExecutorSQLCreateIndex parse(final OCommandRequest iRequest) { keyTypeList.toArray(keyTypes); if (fields != null && fields.length != 0 && fields.length != keyTypes.length) { - throw new OCommandSQLParsingException("Count of fields doesn't match with count of property types. " + "Fields: " + throw new OCommandSQLParsingException("Count of fields does not match with count of property types. " + "Fields: " + Arrays.toString(fields) + "; Types: " + Arrays.toString(keyTypes), parserText, oldPos); } } @@ -205,7 +205,7 @@ else if (serializerKeyId != 0) { } private void checkMapIndexSpecifier(final String fieldName, final String text, final int pos) { - String[] fieldNameParts = fieldName.split("\\s+"); + final String[] fieldNameParts = fieldName.split("\\s+"); if (fieldNameParts.length == 1) return; @@ -229,6 +229,6 @@ private void checkMapIndexSpecifier(final String fieldName, final String text, f @Override public String getSyntax() { - return "CREATE INDEX [ON (prop-names)] []"; + return "CREATE INDEX [ON (prop-names [COLLATE ])] []"; } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLDelete.java b/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLDelete.java index 3936e2d46f1..b761d19b201 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLDelete.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLDelete.java @@ -147,12 +147,10 @@ else if (KEYWORD_RID.equalsIgnoreCase(compiledFilter.getRootCondition().getLeft( } final boolean result; - if (value != VALUE_NOT_FOUND) - if (key != null) - result = index.remove(key, (OIdentifiable) value); - else - return index.remove((OIdentifiable) value); - else + if (value != VALUE_NOT_FOUND) { + assert key != null; + result = index.remove(key, (OIdentifiable) value); + } else result = index.remove(key); return result ? 1 : 0; diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLSelect.java b/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLSelect.java index b7c81b26bdd..c8e493f0391 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLSelect.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/OCommandExecutorSQLSelect.java @@ -1364,12 +1364,14 @@ protected boolean parseFetchplan(final String w) throws OCommandSQLParsingExcept if (!w.equals(KEYWORD_FETCHPLAN)) return false; - parserNextWord(true); - fetchPlan = OStringSerializerHelper.getStringContent(parserGetLastWord()); parserSkipWhiteSpaces(); + int start = parserGetCurrentPosition(); - final int position = parserGetCurrentPosition(); + parserNextWord(true); + int end = parserGetCurrentPosition(); + parserSkipWhiteSpaces(); + int position = parserGetCurrentPosition(); while (!parserIsEnded()) { parserNextWord(true); @@ -1377,12 +1379,14 @@ protected boolean parseFetchplan(final String w) throws OCommandSQLParsingExcept if (!word.matches(".*:-?\\d+")) break; - fetchPlan += " " + word; + end = parserGetCurrentPosition(); parserSkipWhiteSpaces(); + position = parserGetCurrentPosition(); } parserSetCurrentPosition(position); + fetchPlan = OStringSerializerHelper.getStringContent(parserText.substring(start, end)); request.setFetchPlan(fetchPlan); return true; diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/OSQLEngine.java b/core/src/main/java/com/orientechnologies/orient/core/sql/OSQLEngine.java index 8e805ea7f47..e91b1f57bee 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/OSQLEngine.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/OSQLEngine.java @@ -32,6 +32,8 @@ import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.common.util.OCallable; import com.orientechnologies.common.util.OCollections; +import com.orientechnologies.orient.core.collate.OCollate; +import com.orientechnologies.orient.core.collate.OCollateFactory; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.ODatabaseRecord; import com.orientechnologies.orient.core.db.record.OIdentifiable; @@ -51,6 +53,7 @@ public class OSQLEngine { private static List FUNCTION_FACTORIES = null; private static List EXECUTOR_FACTORIES = null; private static List OPERATOR_FACTORIES = null; + private static List COLLATE_FACTORIES = null; private static OQueryOperator[] SORTED_OPERATORS = null; protected static final OSQLEngine INSTANCE = new OSQLEngine(); @@ -179,6 +182,23 @@ public static synchronized Iterator getFunctionFactories() return FUNCTION_FACTORIES.iterator(); } + /** + * @return Iterator of all function factories + */ + public static synchronized Iterator getCollateFactories() { + if (COLLATE_FACTORIES == null) { + + final Iterator ite = lookupProviderWithOrientClassLoader(OCollateFactory.class, orientClassLoader); + + final List factories = new ArrayList(); + while (ite.hasNext()) { + factories.add(ite.next()); + } + COLLATE_FACTORIES = Collections.unmodifiableList(factories); + } + return COLLATE_FACTORIES.iterator(); + } + /** * @return Iterator of all operator factories */ @@ -234,6 +254,20 @@ public static Set getFunctionNames() { return types; } + /** + * Iterates on all factories and append all collate names. + * + * @return Set of all colate names. + */ + public static Set getCollateNames() { + final Set types = new HashSet(); + final Iterator ite = getCollateFactories(); + while (ite.hasNext()) { + types.addAll(ite.next().getNames()); + } + return types; + } + /** * Iterates on all factories and append all command names. * @@ -386,4 +420,13 @@ public Set parseRIDTarget(final ODatabaseRecord database, final String iTa return ids; } + public static OCollate getCollate(final String name) { + for (Iterator iter = getCollateFactories(); iter.hasNext();) { + OCollateFactory f = iter.next(); + final OCollate c = f.getCollate(name); + if (c != null) + return c; + } + return null; + } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterCondition.java b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterCondition.java index 330a6522dc8..e531d5bfde6 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterCondition.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterCondition.java @@ -24,6 +24,7 @@ import java.util.regex.Pattern; import com.orientechnologies.common.collection.OMultiValue; +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.config.OStorageConfiguration; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; @@ -75,7 +76,9 @@ public Object evaluate(final OIdentifiable iCurrentRecord, final ODocument iCurr Object l = evaluate(iCurrentRecord, iCurrentResult, left, iContext); Object r = evaluate(iCurrentRecord, iCurrentResult, right, iContext); - final Object[] convertedValues = checkForConversion(iCurrentRecord, l, r); + final OCollate collate = getCollate(); + + final Object[] convertedValues = checkForConversion(iCurrentRecord, l, r, collate); if (convertedValues != null) { l = convertedValues[0]; r = convertedValues[1]; @@ -100,6 +103,14 @@ public Object evaluate(final OIdentifiable iCurrentRecord, final ODocument iCurr return result; } + public OCollate getCollate() { + if (left instanceof OSQLFilterItemField) + return ((OSQLFilterItemField) left).getCollate(); + else if (right instanceof OSQLFilterItemField) + return ((OSQLFilterItemField) right).getCollate(); + return null; + } + public ORID getBeginRidRange() { if (operator == null) if (left instanceof OSQLFilterCondition) @@ -120,9 +131,21 @@ public ORID getEndRidRange() { return operator.getEndRidRange(left, right); } - private Object[] checkForConversion(final OIdentifiable o, final Object l, final Object r) { + private Object[] checkForConversion(final OIdentifiable o, Object l, Object r, final OCollate collate) { Object[] result = null; + if (collate != null) { + final Object oldL = l; + final Object oldR = r; + + l = collate.transform(l); + r = collate.transform(r); + + if (l != oldL || r != oldR) + // CHANGED + result = new Object[] { l, r }; + } + try { // DEFINED OPERATOR if ((r instanceof String && r.equals(OSQLHelper.DEFINED)) || (l instanceof String && l.equals(OSQLHelper.DEFINED))) { @@ -177,6 +200,7 @@ else if (r instanceof ORID && l instanceof String && !l.equals(OSQLHelper.NOT_NU } catch (Exception e) { // JUST IGNORE CONVERSION ERRORS } + return result; } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemAbstract.java b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemAbstract.java index 6bf28872a2c..91321d992b1 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemAbstract.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemAbstract.java @@ -24,10 +24,13 @@ import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.common.parser.OBaseParser; import com.orientechnologies.common.util.OPair; +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.exception.OCommandExecutionException; import com.orientechnologies.orient.core.exception.OQueryParsingException; +import com.orientechnologies.orient.core.metadata.schema.OProperty; +import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper; import com.orientechnologies.orient.core.sql.OSQLEngine; import com.orientechnologies.orient.core.sql.OSQLHelper; @@ -103,7 +106,8 @@ public OSQLFilterItemAbstract(final OBaseParser iQueryToParse, final String iTex operationsChain.add(new OPair(method, arguments)); } else { - operationsChain.add(new OPair(OSQLHelper.getMethodByName(OSQLMethodField.NAME), new Object[] { part })); + operationsChain.add(new OPair(OSQLHelper.getMethodByName(OSQLMethodField.NAME), + new Object[] { part })); } } } @@ -163,4 +167,14 @@ public String toString() { } return buffer.toString(); } + + protected OCollate getCollateForField(final ODocument doc, final String iFieldName) { + if (doc.getSchemaClass() != null) { + final OProperty p = doc.getSchemaClass().getProperty(iFieldName); + if (p != null) + return p.getCollate(); + } + return null; + } + } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemField.java b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemField.java index 55d122673fc..7c8b661dce9 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemField.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemField.java @@ -19,6 +19,7 @@ import com.orientechnologies.common.parser.OBaseParser; import com.orientechnologies.common.util.OPair; +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.exception.OCommandExecutionException; @@ -37,6 +38,7 @@ public class OSQLFilterItemField extends OSQLFilterItemAbstract { protected Set preLoadedFields; protected String[] preLoadedFieldsArray; protected String name; + protected OCollate collate; public OSQLFilterItemField(final OBaseParser iQueryToParse, final String iName) { super(iQueryToParse, iName); @@ -55,10 +57,14 @@ public Object getValue(final OIdentifiable iRecord, OCommandContext iContext) { } // UNMARSHALL THE SINGLE FIELD - if (doc.deserializeFields(preLoadedFieldsArray)) + if (doc.deserializeFields(preLoadedFieldsArray)) { // FIELD FOUND - return transformValue(iRecord, iContext, ODocumentHelper.getFieldValue(doc, name)); + Object v = ODocumentHelper.getFieldValue(doc, name); + collate = getCollateForField(doc, name); + + return transformValue(iRecord, iContext, v); + } return null; } @@ -142,4 +148,8 @@ public boolean isLong() { public void setPreLoadedFields(final Set iPrefetchedFieldList) { this.preLoadedFields = iPrefetchedFieldList; } + + public OCollate getCollate() { + return collate; + } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemFieldMultiAbstract.java b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemFieldMultiAbstract.java index ef3869e9d34..70c5e3a9fe4 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemFieldMultiAbstract.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/filter/OSQLFilterItemFieldMultiAbstract.java @@ -15,8 +15,10 @@ */ package com.orientechnologies.orient.core.sql.filter; +import java.util.ArrayList; import java.util.List; +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.query.OQueryRuntimeValueMulti; @@ -38,10 +40,19 @@ public OSQLFilterItemFieldMultiAbstract(final OSQLPredicate iQueryCompiled, fina } public Object getValue(final OIdentifiable iRecord, OCommandContext iContext) { + final ODocument doc = ((ODocument) iRecord); + if (names.size() == 1) return transformValue(iRecord, iContext, ODocumentHelper.getIdentifiableValue(iRecord, names.get(0))); - final Object[] values = ((ODocument) iRecord).fieldValues(); + final String[] fieldNames = doc.fieldNames(); + final Object[] values = new Object[fieldNames.length]; + final List collates = new ArrayList(); + + for (int i = 0; i < fieldNames.length; ++i) { + values[i] = doc.field(fieldNames[i]); + collates.add(getCollateForField(doc, fieldNames[i])); + } if (hasChainOperators()) { // TRANSFORM ALL THE VALUES @@ -49,6 +60,6 @@ public Object getValue(final OIdentifiable iRecord, OCommandContext iContext) { values[i] = transformValue(iRecord, iContext, values[i]); } - return new OQueryRuntimeValueMulti(this, values); + return new OQueryRuntimeValueMulti(this, values, collates); } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContains.java b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContains.java index 3623c87a687..ad6c2d51400 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContains.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContains.java @@ -15,12 +15,20 @@ */ package com.orientechnologies.orient.core.sql.operator; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.id.ORID; -import com.orientechnologies.orient.core.index.*; +import com.orientechnologies.orient.core.index.OCompositeIndexDefinition; +import com.orientechnologies.orient.core.index.OIndex; +import com.orientechnologies.orient.core.index.OIndexDefinition; +import com.orientechnologies.orient.core.index.OIndexDefinitionMultiValue; +import com.orientechnologies.orient.core.index.OIndexInternal; import com.orientechnologies.orient.core.sql.filter.OSQLFilterCondition; /** @@ -105,7 +113,6 @@ public OIndexReuseType getIndexReuseType(final Object iLeft, final Object iRight return OIndexReuseType.NO_INDEX; } - @SuppressWarnings("unchecked") @Override public Object executeIndexQuery(OCommandContext iContext, OIndex index, INDEX_OPERATION_TYPE iOperationType, List keyParams, IndexResultListener resultListener, int fetchLimit) { @@ -182,7 +189,7 @@ public Object executeIndexQuery(OCommandContext iContext, OIndex index, INDEX private Object convertIndexResult(Object indexResult) { Object result; if (indexResult instanceof Collection) - result = (Collection) indexResult; + result = (Collection) indexResult; else if (indexResult == null) result = Collections.emptyList(); else diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsKey.java b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsKey.java index 8ca916241cd..b136f7e90dd 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsKey.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsKey.java @@ -23,7 +23,12 @@ import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.id.ORID; -import com.orientechnologies.orient.core.index.*; +import com.orientechnologies.orient.core.index.OCompositeIndexDefinition; +import com.orientechnologies.orient.core.index.OIndex; +import com.orientechnologies.orient.core.index.OIndexDefinition; +import com.orientechnologies.orient.core.index.OIndexDefinitionMultiValue; +import com.orientechnologies.orient.core.index.OIndexInternal; +import com.orientechnologies.orient.core.index.OPropertyMapIndexDefinition; import com.orientechnologies.orient.core.sql.filter.OSQLFilterCondition; /** @@ -60,7 +65,6 @@ public OIndexReuseType getIndexReuseType(final Object iLeft, final Object iRight return OIndexReuseType.INDEX_METHOD; } - @SuppressWarnings("unchecked") @Override public Object executeIndexQuery(OCommandContext iContext, OIndex index, INDEX_OPERATION_TYPE iOperationType, List keyParams, IndexResultListener resultListener, int fetchLimit) { diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsValue.java b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsValue.java index 1a929c55023..079b1333c75 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsValue.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorContainsValue.java @@ -26,7 +26,12 @@ import com.orientechnologies.orient.core.db.record.ORecordElement; import com.orientechnologies.orient.core.exception.ORecordNotFoundException; import com.orientechnologies.orient.core.id.ORID; -import com.orientechnologies.orient.core.index.*; +import com.orientechnologies.orient.core.index.OCompositeIndexDefinition; +import com.orientechnologies.orient.core.index.OIndex; +import com.orientechnologies.orient.core.index.OIndexDefinition; +import com.orientechnologies.orient.core.index.OIndexDefinitionMultiValue; +import com.orientechnologies.orient.core.index.OIndexInternal; +import com.orientechnologies.orient.core.index.OPropertyMapIndexDefinition; import com.orientechnologies.orient.core.record.ORecord; import com.orientechnologies.orient.core.record.ORecordSchemaAware; import com.orientechnologies.orient.core.sql.filter.OSQLFilterCondition; @@ -105,7 +110,6 @@ public OIndexReuseType getIndexReuseType(final Object iLeft, final Object iRight return OIndexReuseType.NO_INDEX; } - @SuppressWarnings("unchecked") @Override public Object executeIndexQuery(OCommandContext iContext, OIndex index, INDEX_OPERATION_TYPE iOperationType, List keyParams, IndexResultListener resultListener, int fetchLimit) { @@ -168,7 +172,7 @@ public Object executeIndexQuery(OCommandContext iContext, OIndex index, INDEX private Object convertIndexResult(Object indexResult) { Object result; if (indexResult instanceof Collection) - result = (Collection) indexResult; + result = (Collection) indexResult; else if (indexResult == null) result = Collections.emptyList(); else diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquality.java b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquality.java index 9b0ba92d534..188a50a38e9 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquality.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquality.java @@ -15,6 +15,7 @@ */ package com.orientechnologies.orient.core.sql.operator; +import com.orientechnologies.orient.core.collate.OCollate; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.query.OQueryRuntimeValueMulti; @@ -54,20 +55,40 @@ public Object evaluateRecord(final OIdentifiable iRecord, ODocument iCurrentResu // LEFT = MULTI final OQueryRuntimeValueMulti left = (OQueryRuntimeValueMulti) iLeft; - if (left.values.length == 0) + if (left.getValues().length == 0) return false; - if (left.getDefinition().getRoot().equals(OSQLFilterItemFieldAll.NAME)) { + if (left.getDefinition().getRoot().startsWith(OSQLFilterItemFieldAll.NAME)) { // ALL VALUES - for (final Object v : left.values) - if (v == null || !evaluateExpression(iRecord, iCondition, v, iRight, iContext)) + for (int i = 0; i < left.getValues().length; ++i) { + Object v = left.getValues()[i]; + Object r = iRight; + + final OCollate collate = left.getCollate(i); + if (collate != null) { + v = collate.transform(v); + r = collate.transform(iRight); + } + + if (v == null || !evaluateExpression(iRecord, iCondition, v, r, iContext)) return false; + } return true; } else { // ANY VALUES - for (final Object v : left.values) - if (v != null && evaluateExpression(iRecord, iCondition, v, iRight, iContext)) + for (int i = 0; i < left.getValues().length; ++i) { + Object v = left.getValues()[i]; + Object r = iRight; + + final OCollate collate = left.getCollate(i); + if (collate != null) { + v = collate.transform(v); + r = collate.transform(iRight); + } + + if (v != null && evaluateExpression(iRecord, iCondition, v, r, iContext)) return true; + } return false; } @@ -75,20 +96,40 @@ public Object evaluateRecord(final OIdentifiable iRecord, ODocument iCurrentResu // RIGHT = MULTI final OQueryRuntimeValueMulti right = (OQueryRuntimeValueMulti) iRight; - if (right.values.length == 0) + if (right.getValues().length == 0) return false; - if (right.getDefinition().getRoot().equals(OSQLFilterItemFieldAll.NAME)) { + if (right.getDefinition().getRoot().startsWith(OSQLFilterItemFieldAll.NAME)) { // ALL VALUES - for (final Object v : right.values) - if (v == null || !evaluateExpression(iRecord, iCondition, iLeft, v, iContext)) + for (int i = 0; i < right.getValues().length; ++i) { + Object v = right.getValues()[i]; + Object l = iLeft; + + final OCollate collate = right.getCollate(i); + if (collate != null) { + v = collate.transform(v); + l = collate.transform(iLeft); + } + + if (v == null || !evaluateExpression(iRecord, iCondition, l, v, iContext)) return false; + } return true; } else { // ANY VALUES - for (final Object v : right.values) - if (v != null && evaluateExpression(iRecord, iCondition, iLeft, v, iContext)) + for (int i = 0; i < right.getValues().length; ++i) { + Object v = right.getValues()[i]; + Object l = iLeft; + + final OCollate collate = right.getCollate(i); + if (collate != null) { + v = collate.transform(v); + l = collate.transform(iLeft); + } + + if (v != null && evaluateExpression(iRecord, iCondition, l, v, iContext)) return true; + } return false; } } else diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquals.java b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquals.java index 2c5c2f8efa6..eea6fd865f0 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquals.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorEquals.java @@ -23,7 +23,11 @@ import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.id.ORID; -import com.orientechnologies.orient.core.index.*; +import com.orientechnologies.orient.core.index.OCompositeIndexDefinition; +import com.orientechnologies.orient.core.index.OIndex; +import com.orientechnologies.orient.core.index.OIndexDefinition; +import com.orientechnologies.orient.core.index.OIndexDefinitionMultiValue; +import com.orientechnologies.orient.core.index.OIndexInternal; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.ORecord; import com.orientechnologies.orient.core.record.impl.ODocument; @@ -172,7 +176,7 @@ public Object executeIndexQuery(OCommandContext iContext, OIndex index, final private Object convertIndexResult(Object indexResult) { Object result; if (indexResult instanceof Collection) - result = (Collection) indexResult; + result = (Collection) indexResult; else if (indexResult == null) result = Collections.emptyList(); else if (indexResult instanceof OIdentifiable) diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorTraverse.java b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorTraverse.java index 79014e6d70d..d0356d199c2 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorTraverse.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/operator/OQueryOperatorTraverse.java @@ -135,7 +135,7 @@ private boolean traverse(Object iTarget, final OSQLFilterCondition iCondition, f } else if (iTarget instanceof OQueryRuntimeValueMulti) { final OQueryRuntimeValueMulti multi = (OQueryRuntimeValueMulti) iTarget; - for (final Object o : multi.values) { + for (final Object o : multi.getValues()) { if (traverse(o, iCondition, iLevel + 1, iEvaluatedRecords, iContext) == Boolean.TRUE) return true; } diff --git a/core/src/main/java/com/orientechnologies/orient/core/storage/impl/local/paginated/OLocalPaginatedStorage.java b/core/src/main/java/com/orientechnologies/orient/core/storage/impl/local/paginated/OLocalPaginatedStorage.java index 79cabd192d5..b8b0ff63605 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/storage/impl/local/paginated/OLocalPaginatedStorage.java +++ b/core/src/main/java/com/orientechnologies/orient/core/storage/impl/local/paginated/OLocalPaginatedStorage.java @@ -37,7 +37,7 @@ import com.orientechnologies.orient.core.config.OStorageConfiguration; import com.orientechnologies.orient.core.config.OStoragePaginatedClusterConfiguration; import com.orientechnologies.orient.core.db.record.ORecordOperation; -import com.orientechnologies.orient.core.db.record.ridset.sbtree.OSBTreeIndexRIDContainer; +import com.orientechnologies.orient.core.db.record.ridset.sbtree.OIndexRIDContainer; import com.orientechnologies.orient.core.engine.local.OEngineLocalPaginated; import com.orientechnologies.orient.core.exception.OConcurrentModificationException; import com.orientechnologies.orient.core.exception.OConfigurationException; @@ -85,7 +85,7 @@ public class OLocalPaginatedStorage extends OStorageLocalAbstract { ".ocs", ".oef", ".oem", ".oet", OWriteAheadLog.WAL_SEGMENT_EXTENSION, OWriteAheadLog.MASTER_RECORD_EXTENSION, OLocalHashTableIndexEngine.BUCKET_FILE_EXTENSION, OLocalHashTableIndexEngine.METADATA_FILE_EXTENSION, OLocalHashTableIndexEngine.TREE_FILE_EXTENSION, OClusterPositionMap.DEF_EXTENSION, OSBTreeIndexEngine.DATA_FILE_EXTENSION, - OWOWCache.NAME_ID_MAP_EXTENSION, OSBTreeIndexRIDContainer.INDEX_FILE_EXTENSION }; + OWOWCache.NAME_ID_MAP_EXTENSION, OIndexRIDContainer.INDEX_FILE_EXTENSION }; private OModificationLock modificationLock = new OModificationLock(); @@ -266,6 +266,7 @@ private void restoreFromWAL() throws IOException { if (lastCheckPoint == null) { OLogManager.instance().info(this, "Checkpoints are absent will restore from beginning."); restoreFromBegging(); + return; } OWALRecord checkPointRecord = writeAheadLog.read(lastCheckPoint); diff --git a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionIndexChanges.java b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionIndexChanges.java index eb9bf28755a..645710e75e0 100644 --- a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionIndexChanges.java +++ b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionIndexChanges.java @@ -15,7 +15,8 @@ */ package com.orientechnologies.orient.core.tx; -import java.util.Map; +import java.util.Collection; +import java.util.NavigableMap; import java.util.TreeMap; import com.orientechnologies.common.comparator.ODefaultComparator; @@ -32,11 +33,10 @@ public static enum OPERATION { PUT, REMOVE, CLEAR } - public Map changesPerKey = new TreeMap( - ODefaultComparator.INSTANCE); + public NavigableMap changesPerKey = new TreeMap( + ODefaultComparator.INSTANCE); - public OTransactionIndexChangesPerKey changesCrossKey; - public boolean cleared = false; + public boolean cleared = false; public OTransactionIndexChangesPerKey getChangesPerKey(final Object iKey) { OTransactionIndexChangesPerKey changes = changesPerKey.get(iKey); @@ -48,6 +48,10 @@ public OTransactionIndexChangesPerKey getChangesPerKey(final Object iKey) { return changes; } + public Collection getChangesForKeys(final Object firstKey, final Object lastKey) { + return changesPerKey.subMap(firstKey, lastKey).values(); + } + public void setCleared() { changesPerKey.clear(); cleared = true; @@ -57,13 +61,4 @@ public boolean containsChangesPerKey(final Object iKey) { return changesPerKey.containsKey(iKey); } - public boolean containsChangesCrossKey() { - return changesCrossKey != null; - } - - public OTransactionIndexChangesPerKey getChangesCrossKey() { - if (changesCrossKey == null) - changesCrossKey = new OTransactionIndexChangesPerKey(null); - return changesCrossKey; - } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionNoTx.java b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionNoTx.java index 8557272cd0c..c6f7e79f7de 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionNoTx.java +++ b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionNoTx.java @@ -170,22 +170,20 @@ public OTransactionIndexChangesPerKey getIndexEntry(final String iIndexName, fin return null; } - public void addIndexEntry(final OIndex delegate, final String iIndexName, final OPERATION iStatus, final Object iKey, - final OIdentifiable iValue) { - switch (iStatus) { + public void addIndexEntry(final OIndex delegate, final String indexName, final OPERATION status, final Object key, + final OIdentifiable value) { + switch (status) { case CLEAR: delegate.clear(); break; case PUT: - delegate.put(iKey, iValue); + delegate.put(key, value); break; case REMOVE: - if (iKey == null) - delegate.remove(iValue); - else - delegate.remove(iKey, iValue); + assert key != null; + delegate.remove(key, value); break; } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionOptimistic.java b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionOptimistic.java index 75d18c091f0..96543d8b65d 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionOptimistic.java +++ b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionOptimistic.java @@ -16,13 +16,7 @@ package com.orientechnologies.orient.core.tx; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; @@ -45,6 +39,7 @@ import com.orientechnologies.orient.core.index.OIndex; import com.orientechnologies.orient.core.index.OIndexAbstract; import com.orientechnologies.orient.core.index.OIndexException; +import com.orientechnologies.orient.core.index.OIndexInternal; import com.orientechnologies.orient.core.metadata.OMetadataDefault; import com.orientechnologies.orient.core.record.ORecord; import com.orientechnologies.orient.core.record.ORecordInternal; @@ -136,23 +131,40 @@ public int compare(final OIndex indexOne, final OIndex indexTwo) { } final Map indexes = new HashMap(); - for (OIndex index : database.getMetadata().getIndexManager().getIndexes()) { - indexes.put(index.getName().toLowerCase(), index); - } + for (OIndex index : database.getMetadata().getIndexManager().getIndexes()) + indexes.put(index.getName(), index); final Runnable callback = new Runnable() { @Override public void run() { final ODocument indexEntries = getIndexChanges(); if (indexEntries != null) { + final Map> indexesToCommit = new HashMap>(); + + for (Entry indexEntry : indexEntries) { + final OIndexInternal index = indexes.get(indexEntry.getKey()).getInternal(); + indexesToCommit.put(index.getName(), index.getInternal()); + } + + for (OIndexInternal indexInternal : indexesToCommit.values()) + indexInternal.preCommit(); + for (Entry indexEntry : indexEntries) { - final OIndex index = indexes.get(indexEntry.getKey().toLowerCase()); + final OIndexInternal index = indexesToCommit.get(indexEntry.getKey()).getInternal(); if (index == null) { OLogManager.instance().error(this, "Index with name " + indexEntry.getKey() + " was not found."); throw new OIndexException("Index with name " + indexEntry.getKey() + " was not found."); } else - index.commit((ODocument) indexEntry.getValue()); + index.addTxOperation((ODocument) indexEntry.getValue()); + } + + try { + for (OIndexInternal indexInternal : indexesToCommit.values()) + indexInternal.commit(); + } finally { + for (OIndexInternal indexInternal : indexesToCommit.values()) + indexInternal.postCommit(); } } } diff --git a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionRealAbstract.java b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionRealAbstract.java index 631245bdca7..e157e94c371 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionRealAbstract.java +++ b/core/src/main/java/com/orientechnologies/orient/core/tx/OTransactionRealAbstract.java @@ -224,9 +224,6 @@ public ODocument getIndexChanges() { final List entries = new ArrayList(); indexDoc.field("entries", entries, OType.EMBEDDEDLIST); - if (indexEntry.getValue().changesCrossKey != null) - serializeIndexChangeEntry(indexEntry.getValue().changesCrossKey, indexDoc, entries); - // STORE INDEX ENTRIES for (OTransactionIndexChangesPerKey entry : indexEntry.getValue().changesPerKey.values()) serializeIndexChangeEntry(entry, indexDoc, entries); @@ -250,7 +247,7 @@ public OTransactionIndexChanges getIndexChanges(final String iIndexName) { * Bufferizes index changes to be flushed at commit time. */ public void addIndexEntry(final OIndex delegate, final String iIndexName, final OTransactionIndexChanges.OPERATION iOperation, - final Object iKey, final OIdentifiable iValue) { + final Object key, final OIdentifiable iValue) { OTransactionIndexChanges indexEntry = indexEntries.get(iIndexName); if (indexEntry == null) { indexEntry = new OTransactionIndexChanges(); @@ -269,16 +266,9 @@ public void addIndexEntry(final OIndex delegate, final String iIndexName, fin changes.entries.remove(i); break; } - - OTransactionIndexChangesPerKey changes = indexEntry.getChangesCrossKey(); - for (int i = 0; i < changes.entries.size(); ++i) - if (changes.entries.get(i).value.equals(iValue)) { - changes.entries.remove(i); - break; - } } - OTransactionIndexChangesPerKey changes = iKey != null ? indexEntry.getChangesPerKey(iKey) : indexEntry.getChangesCrossKey(); + OTransactionIndexChangesPerKey changes = indexEntry.getChangesPerKey(key); changes.add(iValue, iOperation); @@ -292,7 +282,7 @@ public void addIndexEntry(final OIndex delegate, final String iIndexName, fin recordIndexOperations.put(iValue.getIdentity().copy(), transactionIndexOperations); } - transactionIndexOperations.add(new OTransactionRecordIndexOperation(iIndexName, iKey, iOperation)); + transactionIndexOperations.add(new OTransactionRecordIndexOperation(iIndexName, key, iOperation)); } } @@ -324,12 +314,7 @@ public void updateIdentityAfterCommit(final ORID oldRid, final ORID newRid) { if (indexEntryChanges == null) continue; - final OTransactionIndexChangesPerKey changesPerKey; - if (indexOperation.key != null) - changesPerKey = indexEntryChanges.getChangesPerKey(indexOperation.key); - else - changesPerKey = indexEntryChanges.changesCrossKey; - + final OTransactionIndexChangesPerKey changesPerKey = indexEntryChanges.getChangesPerKey(indexOperation.key); updateChangesIdentity(oldRid, newRid, changesPerKey); } } diff --git a/core/src/main/resources/META-INF/services/com.orientechnologies.orient.core.collate.OCollateFactory b/core/src/main/resources/META-INF/services/com.orientechnologies.orient.core.collate.OCollateFactory new file mode 100644 index 00000000000..cf348283930 --- /dev/null +++ b/core/src/main/resources/META-INF/services/com.orientechnologies.orient.core.collate.OCollateFactory @@ -0,0 +1 @@ +com.orientechnologies.orient.core.collate.ODefaultCollateFactory diff --git a/core/src/test/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeIndexRIDContainerSerializationPerformanceTest.java b/core/src/test/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeIndexRIDContainerSerializationPerformanceTest.java new file mode 100644 index 00000000000..fc6616a707b --- /dev/null +++ b/core/src/test/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeIndexRIDContainerSerializationPerformanceTest.java @@ -0,0 +1,63 @@ +package com.orientechnologies.orient.core.db.record.ridset.sbtree; + +import java.util.HashSet; +import java.util.Set; + +import com.orientechnologies.common.directmemory.ODirectMemoryPointer; +import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; +import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; +import com.orientechnologies.orient.core.db.record.OIdentifiable; +import com.orientechnologies.orient.core.id.ORecordId; +import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerSBTreeIndexRIDContainer; + +/** + * @author Artem Orobets + */ +public class OSBTreeIndexRIDContainerSerializationPerformanceTest { + + public static final int CYCLE_COUNT = 20000; + private static final int WARMUP_CYCLE_COUNT = 30000; + public static final ODirectMemoryPointer POINTER = new ODirectMemoryPointer(2048l); + + public static void main(String[] args) throws InterruptedException { + + ODatabaseDocumentTx db = new ODatabaseDocumentTx("plocal:target/testdb/OSBTreeRIDSetTest"); + if (db.exists()) { + db.open("admin", "admin"); + db.drop(); + } + + db.create(); + ODatabaseRecordThreadLocal.INSTANCE.set(db); + + Set data = new HashSet(8); + + data.add(new ORecordId("#77:12")); + data.add(new ORecordId("#77:13")); + data.add(new ORecordId("#77:14")); + data.add(new ORecordId("#77:15")); + data.add(new ORecordId("#77:16")); + + for (int i = 0; i < WARMUP_CYCLE_COUNT; i++) { + cycle(data); + } + + System.gc(); + Thread.sleep(1000); + + long time = System.currentTimeMillis(); + for (int i = 0; i < CYCLE_COUNT; i++) { + cycle(data); + } + time = System.currentTimeMillis() - time; + + System.out.println("Time: " + time + "ms."); + System.out.println("Throughput: " + (((double) CYCLE_COUNT) * 1000 / time) + " rec/sec."); + } + + private static void cycle(Set data) { + final OIndexRIDContainer valueContainer = new OIndexRIDContainer("ValueContainerPerformanceTest"); + valueContainer.addAll(data); + OStreamSerializerSBTreeIndexRIDContainer.INSTANCE.serializeInDirectMemory(valueContainer, POINTER, 0l); + } +} diff --git a/core/src/test/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSetTest.java b/core/src/test/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSetTest.java index 086d7fa1ba4..ca7b035dac8 100755 --- a/core/src/test/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSetTest.java +++ b/core/src/test/java/com/orientechnologies/orient/core/db/record/ridset/sbtree/OSBTreeRIDSetTest.java @@ -71,7 +71,6 @@ public void tearDown() throws Exception { public void testInitialization() throws Exception { OSBTreeRIDSet set = new OSBTreeRIDSet(doc); - assertNotNull(set.getFileName()); assertNotNull(set.getRootPointer()); assertTrue(set.isEmpty()); } diff --git a/distributed/pom.xml b/distributed/pom.xml index ac664f45955..dc344120487 100644 --- a/distributed/pom.xml +++ b/distributed/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 orientdb-distributed diff --git a/distributed/src/main/java/com/orientechnologies/orient/server/hazelcast/OHazelcastPlugin.java b/distributed/src/main/java/com/orientechnologies/orient/server/hazelcast/OHazelcastPlugin.java index 92c8435aff2..6b159c43cd2 100755 --- a/distributed/src/main/java/com/orientechnologies/orient/server/hazelcast/OHazelcastPlugin.java +++ b/distributed/src/main/java/com/orientechnologies/orient/server/hazelcast/OHazelcastPlugin.java @@ -220,7 +220,13 @@ public void shutdown() { hazelcastInstance.getCluster().removeMembershipListener(membershipListenerRegistration); } - hazelcastInstance.shutdown(); + try { + hazelcastInstance.shutdown(); + } catch (Exception e) { + OLogManager.instance().error(this, "Error on shutting down Hazelcast instance", e); + } finally { + hazelcastInstance = null; + } setStatus(STATUS.OFFLINE); diff --git a/distribution/pom.xml b/distribution/pom.xml index 32c851ee6eb..2f7896b2006 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 ../ diff --git a/distribution/src/main/assembly/bin.xml b/distribution/src/main/assembly/bin.xml index 3753255d541..3b0e651d2e1 100644 --- a/distribution/src/main/assembly/bin.xml +++ b/distribution/src/main/assembly/bin.xml @@ -6,7 +6,6 @@ dir tar.gz - tar.bz2 zip @@ -20,6 +19,7 @@ *.sh + 644 true @@ -41,6 +41,7 @@ *.bat + 644 true @@ -62,6 +63,7 @@ *.bat + 644 true @@ -83,6 +85,7 @@ *.bat + 644 true @@ -104,6 +107,7 @@ *.bat + 644 true @@ -122,18 +126,22 @@ ${basedir}/../server/config config + 400 ${basedir}/../tools/config config + 400 ${basedir}/../distributed/config config + 400 ${basedir}/../graphdb/config config + 400 - ${basedir}/../server/config + ${basedir}/../graphdb/target/databases databases - - * - @@ -181,15 +186,15 @@ ${basedir}/../license.txt - 644 + 444 ${basedir}/../history.txt - 644 + 444 ${basedir}/../readme.txt - 644 + 444 @@ -198,9 +203,16 @@ --> + lib + + *:jar:* + - *:pom + *:ant:* + *:ant-launcher:* + *:antlr:* + *:ivy:* diff --git a/enterprise/pom.xml b/enterprise/pom.xml index 55a5a56cabd..e37229bb3d7 100644 --- a/enterprise/pom.xml +++ b/enterprise/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 orientdb-enterprise diff --git a/graphdb/lib/antlr-2.7.7.jar b/graphdb/lib/antlr-2.7.7.jar deleted file mode 100644 index 5e5f14b3558..00000000000 Binary files a/graphdb/lib/antlr-2.7.7.jar and /dev/null differ diff --git a/graphdb/pom.xml b/graphdb/pom.xml index 6820c9bc381..e1c557ceaac 100644 --- a/graphdb/pom.xml +++ b/graphdb/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 ../ diff --git a/graphdb/script/console.sh b/graphdb/script/console.sh index 6bcc328f5c1..52d71f02b0d 100644 --- a/graphdb/script/console.sh +++ b/graphdb/script/console.sh @@ -4,7 +4,7 @@ # #set current working directory -cd "$(dirname "$0")" +cd `dirname $0` # resolve links - $0 may be a softlink PRG="$0" diff --git a/graphdb/script/gremlin.sh b/graphdb/script/gremlin.sh index 09f30c4d9ff..fa74862a220 100644 --- a/graphdb/script/gremlin.sh +++ b/graphdb/script/gremlin.sh @@ -1,7 +1,7 @@ #!/bin/bash #set current working directory -cd "$(dirname "$0")" +cd `dirname $0` case `uname` in CYGWIN*) diff --git a/graphdb/src/test/java/com/orientechnologies/orient/graph/blueprints/TestLoadGraph.java b/graphdb/src/test/java/com/orientechnologies/orient/graph/blueprints/TestLoadGraph.java index 2cdebf42372..d899475c47a 100755 --- a/graphdb/src/test/java/com/orientechnologies/orient/graph/blueprints/TestLoadGraph.java +++ b/graphdb/src/test/java/com/orientechnologies/orient/graph/blueprints/TestLoadGraph.java @@ -4,6 +4,8 @@ import java.io.FileNotFoundException; import java.io.IOException; +import org.testng.annotations.Test; + import com.orientechnologies.orient.client.db.ODatabaseHelper; import com.orientechnologies.orient.core.config.OGlobalConfiguration; import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; @@ -31,7 +33,7 @@ public TestLoadGraph(final String[] args) { dbURL = args.length > 1 ? args[1] : DBURL; } - // @Test + @Test public void testImport() throws IOException, FileNotFoundException { OGlobalConfiguration.STORAGE_KEEP_OPEN.setValue(false); diff --git a/graphdb/src/test/resources/com/orientechnologies/orient/graph/gremlin/graphdb-test.xml b/graphdb/src/test/resources/com/orientechnologies/orient/graph/gremlin/graphdb-test.xml index b2d222fa67a..1371a65e041 100644 --- a/graphdb/src/test/resources/com/orientechnologies/orient/graph/gremlin/graphdb-test.xml +++ b/graphdb/src/test/resources/com/orientechnologies/orient/graph/gremlin/graphdb-test.xml @@ -1,11 +1,12 @@ - - - + + - - + + \ No newline at end of file diff --git a/history.txt b/history.txt index 9b6d7628a43..e80cfc8205f 100644 --- a/history.txt +++ b/history.txt @@ -25,6 +25,14 @@ *************************************************************************************************** This document contains the last changes to the OrientDB project. +--------------------------------------------------------------------------------------------------- +VERSION 1.6.2 - (December, 9th 2013) +--------------------------------------------------------------------------------------------------- +- Support for COLLATE to case insensitive compare fields +- Bug fixing + +Full list: https://github.com/orientechnologies/orientdb/issues?milestone=11&page=1&state=closed + --------------------------------------------------------------------------------------------------- VERSION 1.6.1 - (November, 20th 2013) --------------------------------------------------------------------------------------------------- diff --git a/nativeos/pom.xml b/nativeos/pom.xml index def8551b980..c3d517f3a90 100644 --- a/nativeos/pom.xml +++ b/nativeos/pom.xml @@ -20,7 +20,7 @@ orientdb-parent com.orientechnologies - 1.6.1 + 1.6.2 ../ 4.0.0 diff --git a/object/pom.xml b/object/pom.xml index 2c8ccfdacb0..55eaf180f7d 100644 --- a/object/pom.xml +++ b/object/pom.xml @@ -22,7 +22,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 orientdb-object diff --git a/pom.xml b/pom.xml index 653b77ab8a4..9b07695a99c 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 pom OrientDB @@ -68,24 +68,26 @@ +2 - molino.luca - Luca Molino - molino.luca@gmail.com + lomakin.andrey + Andrey Lomakin + a.lomakin@orientechnologies.com + Orientechnologies + http://www.orientechnologies.com architect developer - +1 + +2 - lomakin.andrey - Andrey Lomakin - lomakin.andrey@gmail.com + molino.luca + Luca Molino + molino.luca@gmail.com architect developer - +2 + +1 @@ -108,7 +110,7 @@ tests distributed graphdb - + distribution diff --git a/server/plugins/studio-1.6.1.zip b/server/plugins/studio-1.6.2.zip similarity index 92% rename from server/plugins/studio-1.6.1.zip rename to server/plugins/studio-1.6.2.zip index 8ad740c87e6..efc0ee7ae0a 100644 Binary files a/server/plugins/studio-1.6.1.zip and b/server/plugins/studio-1.6.2.zip differ diff --git a/server/pom.xml b/server/pom.xml index f04ba3e853f..5d870efe329 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 orientdb-server diff --git a/server/script/server.sh b/server/script/server.sh index e13b73a107b..174d1a21fea 100644 --- a/server/script/server.sh +++ b/server/script/server.sh @@ -28,7 +28,7 @@ echo " \`\` \`. echo " \`\` www.orientdb.org " echo " \` " -cd "$(dirname "$0")" +cd `dirname $0` # resolve links - $0 may be a softlink PRG="$0" diff --git a/server/script/shutdown.sh b/server/script/shutdown.sh index e5da105a7ca..3257f3bbe71 100644 --- a/server/script/shutdown.sh +++ b/server/script/shutdown.sh @@ -7,13 +7,13 @@ # resolve links - $0 may be a softlink PRG="$0" -while [ $# -gt 0 ]; do +if [ $# -gt 0 ]; then case "$1" in -w|--wait) wait="yes" shift 1 ;; esac -done +fi while [ -h "$PRG" ]; do ls=`ls -ld "$PRG"` diff --git a/server/src/main/java/com/orientechnologies/orient/server/OServer.java b/server/src/main/java/com/orientechnologies/orient/server/OServer.java index 3213cd9840a..568a41f8774 100755 --- a/server/src/main/java/com/orientechnologies/orient/server/OServer.java +++ b/server/src/main/java/com/orientechnologies/orient/server/OServer.java @@ -224,6 +224,13 @@ public OServer activate() throws ClassNotFoundException, InstantiationException, for (OServerLifecycleListener l : lifecycleListeners) l.onAfterActivate(); + try { + loadStorages(); + loadUsers(); + } catch (IOException e) { + OLogManager.instance().error(this, "Error on reading server configuration.", OConfigurationException.class, e); + } + OLogManager.instance().info(this, "OrientDB Server v" + OConstants.ORIENT_VERSION + " is active."); startupLatch.countDown(); @@ -497,22 +504,15 @@ public OServer setVariable(final String iName, final Object iValue) { } protected void loadConfiguration(final OServerConfiguration iConfiguration) { - try { - configuration = iConfiguration; - - // FILL THE CONTEXT CONFIGURATION WITH SERVER'S PARAMETERS - contextConfiguration = new OContextConfiguration(); - if (iConfiguration.properties != null) - for (OServerEntryConfiguration prop : iConfiguration.properties) - contextConfiguration.setValue(prop.name, prop.value); + configuration = iConfiguration; - loadStorages(); - loadUsers(); - hookManager = new OConfigurableHooksManager(iConfiguration); + // FILL THE CONTEXT CONFIGURATION WITH SERVER'S PARAMETERS + contextConfiguration = new OContextConfiguration(); + if (iConfiguration.properties != null) + for (OServerEntryConfiguration prop : iConfiguration.properties) + contextConfiguration.setValue(prop.name, prop.value); - } catch (IOException e) { - OLogManager.instance().error(this, "Error on reading server configuration.", OConfigurationException.class, e); - } + hookManager = new OConfigurableHooksManager(iConfiguration); } protected OServerConfiguration loadConfigurationFromFile(final File iFile) { diff --git a/server/src/main/java/com/orientechnologies/orient/server/config/OServerConfigurationLoaderXml.java b/server/src/main/java/com/orientechnologies/orient/server/config/OServerConfigurationLoaderXml.java index 5d23e6dbaf1..6ae4863d111 100644 --- a/server/src/main/java/com/orientechnologies/orient/server/config/OServerConfigurationLoaderXml.java +++ b/server/src/main/java/com/orientechnologies/orient/server/config/OServerConfigurationLoaderXml.java @@ -66,8 +66,10 @@ public OServerConfiguration load() throws IOException { if (file != null) { if (file.exists()) obj = rootClass.cast(unmarshaller.unmarshal(file)); - else + else { + OLogManager.instance().error(this, "File not found: %s", file); return rootClass.getConstructor(OServerConfigurationLoaderXml.class).newInstance(this); + } obj.location = file.getAbsolutePath(); } else { obj = rootClass.cast(unmarshaller.unmarshal(inputStream)); diff --git a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/OHttpResponse.java b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/OHttpResponse.java index 8d17ce872bc..d1908c7f27a 100644 --- a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/OHttpResponse.java +++ b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/OHttpResponse.java @@ -333,7 +333,7 @@ public byte[] compress(String jsonStr) { try { byte[] incoming = jsonStr.getBytes("UTF-8"); baos = new ByteArrayOutputStream(); - gout = new GZIPOutputStream(baos); + gout = new GZIPOutputStream(baos, 16384); // 16KB gout.write(incoming); gout.finish(); return baos.toByteArray(); diff --git a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/ONetworkProtocolHttpAbstract.java b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/ONetworkProtocolHttpAbstract.java index 9fb7c889c77..a0efb303312 100755 --- a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/ONetworkProtocolHttpAbstract.java +++ b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/ONetworkProtocolHttpAbstract.java @@ -538,7 +538,7 @@ protected String deCompress(byte[] zipBytes) { ByteArrayOutputStream baos = null; try { in = new ByteArrayInputStream(zipBytes); - gzip = new GZIPInputStream(in); + gzip = new GZIPInputStream(in, 16384); // 16KB byte[] buffer = new byte[1024]; baos = new ByteArrayOutputStream(); int len = -1; diff --git a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetDatabase.java b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetDatabase.java index d8b090f9263..f233651d928 100755 --- a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetDatabase.java +++ b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetDatabase.java @@ -285,6 +285,7 @@ public static void exportClass(final ODatabaseDocumentTx db, final OJSONWriter j json.writeAttribute("notNull", prop.isNotNull()); json.writeAttribute("min", prop.getMin()); json.writeAttribute("max", prop.getMax()); + json.writeAttribute("collate", prop.getCollate() != null ? prop.getCollate().getName() : "default"); if (prop instanceof OPropertyImpl) { final Map custom = ((OPropertyImpl) prop).getCustomInternal(); diff --git a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetExportDatabase.java b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetExportDatabase.java index 7c50904465d..b37737306cc 100644 --- a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetExportDatabase.java +++ b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/command/get/OServerCommandGetExportDatabase.java @@ -52,7 +52,7 @@ protected void exportStandard(final OHttpRequest iRequest, final OHttpResponse i iResponse.writeLine("Content-Disposition: attachment; filename=" + database.getName() + ".gz"); iResponse.writeLine("Date: " + new Date()); iResponse.writeLine(null); - final ODatabaseExport export = new ODatabaseExport(database, new GZIPOutputStream(iResponse.getOutputStream()), this); + final ODatabaseExport export = new ODatabaseExport(database, new GZIPOutputStream(iResponse.getOutputStream(), 16384), this); export.exportDatabase(); try { diff --git a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/multipart/OHttpMultipartDatabaseImportContentParser.java b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/multipart/OHttpMultipartDatabaseImportContentParser.java index 4ac47f66174..95195d743ed 100644 --- a/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/multipart/OHttpMultipartDatabaseImportContentParser.java +++ b/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/multipart/OHttpMultipartDatabaseImportContentParser.java @@ -36,7 +36,7 @@ public InputStream parse(final OHttpRequest iRequest, final Map final String fileName = headers.get(OHttpUtils.MULTIPART_CONTENT_FILENAME); if (fileName.endsWith(".gz") || fileName.endsWith(".gzip")) - return new GZIPInputStream(in); + return new GZIPInputStream(in, 16384); // 16KB return in; } diff --git a/server/src/main/java/com/orientechnologies/orient/server/tx/OTransactionOptimisticProxy.java b/server/src/main/java/com/orientechnologies/orient/server/tx/OTransactionOptimisticProxy.java index a12d2993f3a..4cdb6ed4b58 100644 --- a/server/src/main/java/com/orientechnologies/orient/server/tx/OTransactionOptimisticProxy.java +++ b/server/src/main/java/com/orientechnologies/orient/server/tx/OTransactionOptimisticProxy.java @@ -210,10 +210,7 @@ else if (Boolean.TRUE.equals(keyContainer.field("binary"))) { final OTransactionIndexChanges.OPERATION indexOperation = OTransactionIndexChanges.OPERATION.values()[operation]; final OIdentifiable value = op.field("v", OType.LINK); - if (key != null) - transactionIndexChanges.getChangesPerKey(key).add(value, indexOperation); - else - transactionIndexChanges.getChangesCrossKey().add(value, indexOperation); + transactionIndexChanges.getChangesPerKey(key).add(value, indexOperation); if (value == null) continue; diff --git a/tests/pom.xml b/tests/pom.xml index ba6c550e2f2..b8b62aec9c5 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -24,7 +24,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 ../ diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDDocumentPhysicalTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDDocumentPhysicalTest.java index 2cdfdad646e..9707e3b50b3 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDDocumentPhysicalTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDDocumentPhysicalTest.java @@ -798,6 +798,7 @@ public void asynchInsertion() { database.save(record, OPERATION_MODE.ASYNCHRONOUS, false, new ORecordCallback() { + @Override public void call(ORecordId iRID, OClusterPosition iParameter) { callBackCalled.incrementAndGet(); } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTest.java index da14937d809..ba0c4125b2c 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTest.java @@ -173,6 +173,7 @@ public void testSimpleTypes() { loadedJavaObj.setEnumeration(EnumTest.ENUM2); loadedJavaObj.setTestAnonymous(new JavaTestInterface() { + @Override public int getNumber() { return 0; } @@ -216,9 +217,9 @@ public void testSimpleArrayTypes() { for (int i = 0; i < 10; i++) { textArray[i] = i + ""; intArray[i] = i; - longArray[i] = (long) i; - doubleArray[i] = (double) i; - floatArray[i] = (float) i; + longArray[i] = i; + doubleArray[i] = i; + floatArray[i] = i; byteArray[i] = (byte) i; booleanArray[i] = (i % 2 == 0); enumerationArray[i] = (i % 2 == 0) ? EnumTest.ENUM2 : ((i % 3 == 0) ? EnumTest.ENUM3 : EnumTest.ENUM1); @@ -276,7 +277,7 @@ public void testSimpleArrayTypes() { for (int i = 0; i < 10; i++) { Assert.assertEquals(loadedJavaObj.getText()[i], i + ""); Assert.assertEquals(loadedJavaObj.getNumberSimple()[i], i); - Assert.assertEquals(loadedJavaObj.getLongSimple()[i], (long) i); + Assert.assertEquals(loadedJavaObj.getLongSimple()[i], i); Assert.assertEquals(loadedJavaObj.getDoubleSimple()[i], (double) i); Assert.assertEquals(loadedJavaObj.getFloatSimple()[i], (float) i); Assert.assertEquals(loadedJavaObj.getByteSimple()[i], (byte) i); @@ -291,9 +292,9 @@ public void testSimpleArrayTypes() { int j = i + 10; textArray[i] = j + ""; intArray[i] = j; - longArray[i] = (long) j; - doubleArray[i] = (double) j; - floatArray[i] = (float) j; + longArray[i] = j; + doubleArray[i] = j; + floatArray[i] = j; byteArray[i] = (byte) j; booleanArray[i] = (j % 2 == 0); enumerationArray[i] = (j % 2 == 0) ? EnumTest.ENUM2 : ((j % 3 == 0) ? EnumTest.ENUM3 : EnumTest.ENUM1); @@ -351,7 +352,7 @@ public void testSimpleArrayTypes() { int j = i + 10; Assert.assertEquals(loadedJavaObj.getText()[i], j + ""); Assert.assertEquals(loadedJavaObj.getNumberSimple()[i], j); - Assert.assertEquals(loadedJavaObj.getLongSimple()[i], (long) j); + Assert.assertEquals(loadedJavaObj.getLongSimple()[i], j); Assert.assertEquals(loadedJavaObj.getDoubleSimple()[i], (double) j); Assert.assertEquals(loadedJavaObj.getFloatSimple()[i], (float) j); Assert.assertEquals(loadedJavaObj.getByteSimple()[i], (byte) j); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTestSchemaFull.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTestSchemaFull.java index 1d43908a067..15c57f1b2f8 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTestSchemaFull.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CRUDObjectPhysicalTestSchemaFull.java @@ -149,6 +149,7 @@ public void testSimpleTypes() { loadedJavaObj.setEnumeration(EnumTest.ENUM2); loadedJavaObj.setTestAnonymous(new JavaTestInterface() { + @Override public int getNumber() { return 0; } @@ -192,9 +193,9 @@ public void testSimpleArrayTypes() { for (int i = 0; i < 10; i++) { textArray[i] = i + ""; intArray[i] = i; - longArray[i] = (long) i; - doubleArray[i] = (double) i; - floatArray[i] = (float) i; + longArray[i] = i; + doubleArray[i] = i; + floatArray[i] = i; byteArray[i] = (byte) i; booleanArray[i] = (i % 2 == 0); enumerationArray[i] = (i % 2 == 0) ? EnumTest.ENUM2 : ((i % 3 == 0) ? EnumTest.ENUM3 : EnumTest.ENUM1); @@ -252,7 +253,7 @@ public void testSimpleArrayTypes() { for (int i = 0; i < 10; i++) { Assert.assertEquals(loadedJavaObj.getText()[i], i + ""); Assert.assertEquals(loadedJavaObj.getNumberSimple()[i], i); - Assert.assertEquals(loadedJavaObj.getLongSimple()[i], (long) i); + Assert.assertEquals(loadedJavaObj.getLongSimple()[i], i); Assert.assertEquals(loadedJavaObj.getDoubleSimple()[i], (double) i); Assert.assertEquals(loadedJavaObj.getFloatSimple()[i], (float) i); Assert.assertEquals(loadedJavaObj.getByteSimple()[i], (byte) i); @@ -267,9 +268,9 @@ public void testSimpleArrayTypes() { int j = i + 10; textArray[i] = j + ""; intArray[i] = j; - longArray[i] = (long) j; - doubleArray[i] = (double) j; - floatArray[i] = (float) j; + longArray[i] = j; + doubleArray[i] = j; + floatArray[i] = j; byteArray[i] = (byte) j; booleanArray[i] = (j % 2 == 0); enumerationArray[i] = (j % 2 == 0) ? EnumTest.ENUM2 : ((j % 3 == 0) ? EnumTest.ENUM3 : EnumTest.ENUM1); @@ -327,7 +328,7 @@ public void testSimpleArrayTypes() { int j = i + 10; Assert.assertEquals(loadedJavaObj.getText()[i], j + ""); Assert.assertEquals(loadedJavaObj.getNumberSimple()[i], j); - Assert.assertEquals(loadedJavaObj.getLongSimple()[i], (long) j); + Assert.assertEquals(loadedJavaObj.getLongSimple()[i], j); Assert.assertEquals(loadedJavaObj.getDoubleSimple()[i], (double) j); Assert.assertEquals(loadedJavaObj.getFloatSimple()[i], (float) j); Assert.assertEquals(loadedJavaObj.getByteSimple()[i], (byte) j); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ClassIndexTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ClassIndexTest.java index 56a0e34d312..f94fc2583e1 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ClassIndexTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ClassIndexTest.java @@ -149,14 +149,17 @@ public void createCompositeIndexTestWithoutListener() { public void createCompositeIndexTestWithListener() { final AtomicInteger atomicInteger = new AtomicInteger(0); final OProgressListener progressListener = new OProgressListener() { + @Override public void onBegin(final Object iTask, final long iTotal) { atomicInteger.incrementAndGet(); } + @Override public boolean onProgress(final Object iTask, final long iCounter, final float iPercent) { return true; } + @Override public void onCompletition(final Object iTask, final boolean iSucceed) { atomicInteger.incrementAndGet(); } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CollateTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CollateTest.java new file mode 100644 index 00000000000..d92d968c5c1 --- /dev/null +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/CollateTest.java @@ -0,0 +1,46 @@ +package com.orientechnologies.orient.test.database.auto; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.orientechnologies.orient.core.db.document.ODatabaseDocument; +import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; +import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery; + +@Test +public class CollateTest { + + private ODatabaseDocument database; + + @BeforeMethod + public void beforeMethod() { + database.open("admin", "admin"); + } + + @AfterMethod + public void afterMethod() { + database.close(); + } + + @Parameters(value = "url") + public CollateTest(String iURL) { + database = new ODatabaseDocumentTx(iURL); + } + + @Test + public void testCaseInsensitiveQuery() { + assertEquals(database.query(new OSQLSynchQuery("select from ouser where name = 'AdMiN'")).size(), 1); + assertEquals(database.query(new OSQLSynchQuery("select from ouser where name = 'admin'")).size(), 1); + assertEquals(database.query(new OSQLSynchQuery("select from ouser where name like 'admin'")).size(), 1); + assertEquals(database.query(new OSQLSynchQuery("select from ouser where name like 'AdMIN'")).size(), 1); + assertEquals(database.query(new OSQLSynchQuery("select from ouser where name like '%dm%'")).size(), 1); + assertEquals(database.query(new OSQLSynchQuery("select from ouser where name like '%MI%'")).size(), 1); + assertEquals(database.query(new OSQLSynchQuery("select from ouser where any() like '%dM%'")).size(), 1); + assertEquals(database.query(new OSQLSynchQuery("select from ouser where all() like '%MI%'")).size(), 0); + } + +} diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentQueriesTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentQueriesTest.java index cc91a3cc70b..792df3f0a63 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentQueriesTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentQueriesTest.java @@ -50,6 +50,7 @@ public CommandExecutor(String url, String iThreadName) { threadName = iThreadName; } + @Override public void run() { try { for (int i = 0; i < CYCLES; i++) { diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentUpdatesTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentUpdatesTest.java index 2f4754dbf6b..e0335106f74 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentUpdatesTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ConcurrentUpdatesTest.java @@ -58,6 +58,7 @@ public UpdateField(ODatabaseDocumentTx iDb, ORID iRid1, ORID iRid2, String iThre threadName = iThreadName; } + @Override public void run() { try { for (int i = 0; i < CYCLES; i++) { diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DatabaseThreadFactoryTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DatabaseThreadFactoryTest.java index 80753780291..84f3ca8bfac 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DatabaseThreadFactoryTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DatabaseThreadFactoryTest.java @@ -62,6 +62,7 @@ public void testNoFactory() { public void testFactory() { Orient.instance().registerThreadDatabaseFactory(new ODatabaseThreadLocalFactory() { + @Override public ODatabaseRecord getThreadDatabase() { return ODatabaseDocumentPool.global().acquire(url, "admin", "admin"); } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCheckTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCheckTest.java index d9923bf8630..eaa8e1bd765 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCheckTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCheckTest.java @@ -46,6 +46,7 @@ public void checkDatabaseIntegrity() throws IOException { database.close(); } + @Override @Test(enabled = false) public void onMessage(final String iText) { System.out.print(iText); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCompareTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCompareTest.java index 4a7687efba8..1e1c08c7611 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCompareTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbCompareTest.java @@ -49,6 +49,7 @@ public void testCompareDatabases() throws IOException { Assert.assertTrue(databaseCompare.compare()); } + @Override @Test(enabled = false) public void onMessage(final String iText) { System.out.print(iText); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbImportExportTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbImportExportTest.java index 912ee3e3b74..be92c2ec330 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbImportExportTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbImportExportTest.java @@ -92,6 +92,7 @@ public void testDbImport() throws IOException { database.close(); } + @Override @Test(enabled = false) public void onMessage(final String iText) { System.out.print(iText); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbListenerTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbListenerTest.java index 101574406e0..bd1b7d2c81c 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbListenerTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/DbListenerTest.java @@ -57,42 +57,52 @@ public class DbListenerTest { protected int onAvailableDatabaseChange = 0; public class DbListener implements ODatabaseListener { + @Override public void onAfterTxCommit(ODatabase iDatabase) { onAfterTxCommit++; } + @Override public void onAfterTxRollback(ODatabase iDatabase) { onAfterTxRollback++; } + @Override public void onBeforeTxBegin(ODatabase iDatabase) { onBeforeTxBegin++; } + @Override public void onBeforeTxCommit(ODatabase iDatabase) { onBeforeTxCommit++; } + @Override public void onBeforeTxRollback(ODatabase iDatabase) { onBeforeTxRollback++; } + @Override public void onClose(ODatabase iDatabase) { onClose++; } + @Override public void onCreate(ODatabase iDatabase) { onCreate++; } + @Override public void onDelete(ODatabase iDatabase) { onDelete++; } + @Override public void onOpen(ODatabase iDatabase) { onOpen++; } + @Override public boolean onCorruptionRepairDatabase(ODatabase iDatabase, final String iReason, String iWhatWillbeFixed) { onCorruption++; return true; @@ -186,6 +196,7 @@ public void testAsynchEventListeners() throws IOException { ((OStorageRemoteThread) database.getStorage()).setRemoteServerEventListener(new ORemoteServerEventListener() { + @Override public void onRequest(byte iRequestCode, Object iObject) { switch (iRequestCode) { case OChannelBinaryProtocol.REQUEST_PUSH_RECORD: diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/GraphDatabaseTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/GraphDatabaseTest.java index 581161900b8..d8a19fa9473 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/GraphDatabaseTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/GraphDatabaseTest.java @@ -88,9 +88,9 @@ public void populate() { database.createVertexType("GraphCar", vehicleClass); database.createVertexType("GraphMotocycle", "GraphVehicle"); - ODocument carNode = (ODocument) database.createVertex("GraphCar").field("brand", "Hyundai").field("model", "Coupe") + ODocument carNode = database.createVertex("GraphCar").field("brand", "Hyundai").field("model", "Coupe") .field("year", 2003).save(); - ODocument motoNode = (ODocument) database.createVertex("GraphMotocycle").field("brand", "Yamaha").field("model", "X-City 250") + ODocument motoNode = database.createVertex("GraphMotocycle").field("brand", "Yamaha").field("model", "X-City 250") .field("year", 2009).save(); database.createEdge(carNode, motoNode).save(); @@ -131,10 +131,10 @@ public void populate() { @Test(dependsOnMethods = "populate") public void testSQLAgainstGraph() { - ODocument tom = (ODocument) database.createVertex().field("name", "Tom").save(); - ODocument ferrari = (ODocument) database.createVertex("GraphCar").field("brand", "Ferrari").save(); - ODocument maserati = (ODocument) database.createVertex("GraphCar").field("brand", "Maserati").save(); - ODocument porsche = (ODocument) database.createVertex("GraphCar").field("brand", "Porsche").save(); + ODocument tom = database.createVertex().field("name", "Tom").save(); + ODocument ferrari = database.createVertex("GraphCar").field("brand", "Ferrari").save(); + ODocument maserati = database.createVertex("GraphCar").field("brand", "Maserati").save(); + ODocument porsche = database.createVertex("GraphCar").field("brand", "Porsche").save(); database.createEdge(tom, ferrari).field("label", "drives").save(); database.createEdge(tom, maserati).field("label", "drives").save(); database.createEdge(tom, porsche).field("label", "owns").save(); @@ -253,10 +253,10 @@ public void testEdgesIterationInTX() { database.createVertexType("vertexBB"); database.createEdgeType("edgeAB"); - ODocument vertexA = (ODocument) database.createVertex("vertexAA").field("address", "testing").save(); + ODocument vertexA = database.createVertex("vertexAA").field("address", "testing").save(); for (int i = 0; i < 18; ++i) { - ODocument vertexB = (ODocument) database.createVertex("vertexBB").field("address", "test" + i).save(); + ODocument vertexB = database.createVertex("vertexBB").field("address", "test" + i).save(); database.begin(OTransaction.TXTYPE.OPTIMISTIC); database.createEdge(vertexB.getIdentity(), vertexA.getIdentity(), "edgeAB").save(); database.commit(); @@ -280,7 +280,7 @@ public void testTxField() { // Step 1 // create a public cert with some field set - ODocument publicCert = (ODocument) database.createVertex("PublicCert").field("address", "drevil@myco.mn.us").save(); + ODocument publicCert = database.createVertex("PublicCert").field("address", "drevil@myco.mn.us").save(); // Step 2 // update the public cert field in transaction diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTest.java index fd997173333..2631f99f42f 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTest.java @@ -24,7 +24,6 @@ import com.orientechnologies.orient.core.hook.ORecordHook; import com.orientechnologies.orient.core.hook.ORecordHookAbstract; -import com.orientechnologies.orient.core.hook.ORecordHook.DISTRIBUTED_EXECUTION_MODE; import com.orientechnologies.orient.core.record.ORecord; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery; @@ -41,6 +40,7 @@ public class HookTest extends ORecordHookAbstract { public HookTest(String iURL) { database = new OObjectDatabaseTx(iURL); } + @Override public DISTRIBUTED_EXECUTION_MODE getDistributedExecutionMode() { return DISTRIBUTED_EXECUTION_MODE.TARGET_NODE; } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTxTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTxTest.java index f3b3cd71ea8..4fe9f144beb 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTxTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/HookTxTest.java @@ -50,6 +50,7 @@ public HookTxTest(String iURL) { database = new OObjectDatabaseTx(iURL); } + @Override public DISTRIBUTED_EXECUTION_MODE getDistributedExecutionMode() { return DISTRIBUTED_EXECUTION_MODE.TARGET_NODE; } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexClusterTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexClusterTest.java index ba25837d7d1..7816dbe4f9c 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexClusterTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexClusterTest.java @@ -1,5 +1,12 @@ package com.orientechnologies.orient.test.database.auto; +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + import com.orientechnologies.orient.core.db.document.ODatabaseDocument; import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; import com.orientechnologies.orient.core.metadata.schema.OClass; @@ -9,13 +16,6 @@ import com.orientechnologies.orient.core.sql.OCommandSQL; import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery; import com.orientechnologies.orient.core.storage.OStorage; -import com.orientechnologies.orient.object.db.OObjectDatabaseTx; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Parameters; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; @Test(groups = { "index" }) public class IndexClusterTest { diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexConcurrentCommitTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexConcurrentCommitTest.java index 81f9b2ef201..5623aaf0489 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexConcurrentCommitTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexConcurrentCommitTest.java @@ -11,10 +11,6 @@ import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.sql.OCommandSQL; -/** - * @author Andrey Lomakin Andrey Lomakin - * @since 11/18/13 - */ @Test public class IndexConcurrentCommitTest { public void testConcurrentUpdate() { diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexCustomKeyTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexCustomKeyTest.java index ec3f8f886f0..0915061be89 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexCustomKeyTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexCustomKeyTest.java @@ -49,6 +49,7 @@ public ComparableBinary(byte[] buffer) { value = buffer; } + @Override public int compareTo(ComparableBinary o) { final int size = value.length; @@ -65,10 +66,12 @@ public byte[] toByteArray() { return value; } + @Override public byte[] toStream() throws OSerializationException { return value; } + @Override public OSerializableStream fromStream(byte[] iStream) throws OSerializationException { this.value = iStream; return this; @@ -85,36 +88,44 @@ public int getObjectSize(final int length) { return length; } + @Override public int getObjectSize(final ComparableBinary object, Object... hints) { return object.toByteArray().length; } + @Override public void serialize(final ComparableBinary object, final byte[] stream, final int startPosition, Object... hints) { final byte[] buffer = object.toByteArray(); System.arraycopy(buffer, 0, stream, startPosition, buffer.length); } + @Override public ComparableBinary deserialize(final byte[] stream, final int startPosition) { final byte[] buffer = Arrays.copyOfRange(stream, startPosition, startPosition + LENGTH); return new ComparableBinary(buffer); } + @Override public int getObjectSize(byte[] stream, int startPosition) { return LENGTH; } + @Override public byte getId() { return ID; } + @Override public int getObjectSizeNative(byte[] stream, int startPosition) { return LENGTH; } + @Override public void serializeNative(ComparableBinary object, byte[] stream, int startPosition, Object... hints) { serialize(object, stream, startPosition); } + @Override public ComparableBinary deserializeNative(byte[] stream, int startPosition) { return deserialize(stream, startPosition); } @@ -135,10 +146,12 @@ public int getObjectSizeInDirectMemory(ODirectMemoryPointer pointer, long offset return LENGTH; } + @Override public boolean isFixedLength() { return true; } + @Override public int getFixedLength() { return LENGTH; } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexManagerTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexManagerTest.java index a05706fa4b5..2c5d81ca5f7 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexManagerTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexManagerTest.java @@ -155,14 +155,17 @@ public void createCompositeIndexTestWithoutListener() { public void createCompositeIndexTestWithListener() { final AtomicInteger atomicInteger = new AtomicInteger(0); final OProgressListener progressListener = new OProgressListener() { + @Override public void onBegin(final Object iTask, final long iTotal) { atomicInteger.incrementAndGet(); } + @Override public boolean onProgress(final Object iTask, final long iCounter, final float iPercent) { return true; } + @Override public void onCompletition(final Object iTask, final boolean iSucceed) { atomicInteger.incrementAndGet(); } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexTest.java index 36c0f39e7b7..edef29d7ef5 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/IndexTest.java @@ -32,6 +32,7 @@ import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.id.OClusterPosition; import com.orientechnologies.orient.core.id.OClusterPositionFactory; +import com.orientechnologies.orient.core.id.ORID; import com.orientechnologies.orient.core.id.ORecordId; import com.orientechnologies.orient.core.index.OIndex; import com.orientechnologies.orient.core.index.OIndexException; @@ -1341,8 +1342,8 @@ public void createInheritanceIndex() { anotherChildClassDocument.field("testParentProperty", 11L); anotherChildClassDocument.save(); - Assert.assertFalse(new ORecordId(-1, ORecordId.CLUSTER_POS_INVALID).equals(childClassDocument.getIdentity())); - Assert.assertFalse(new ORecordId(-1, ORecordId.CLUSTER_POS_INVALID).equals(anotherChildClassDocument.getIdentity())); + Assert.assertFalse(new ORecordId(-1, ORID.CLUSTER_POS_INVALID).equals(childClassDocument.getIdentity())); + Assert.assertFalse(new ORecordId(-1, ORID.CLUSTER_POS_INVALID).equals(anotherChildClassDocument.getIdentity())); } finally { db.close(); } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/LockManagerTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/LockManagerTest.java index 14eb85bec50..f414fb65261 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/LockManagerTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/LockManagerTest.java @@ -51,6 +51,7 @@ public class LockManagerTest { public static class ResourceRead implements Callable { AtomicInteger countRead = new AtomicInteger(0); + @Override public Void call() throws Exception { lockMgr.acquireLock(Thread.currentThread(), this, LOCK.SHARED); try { @@ -72,6 +73,7 @@ public Void call() throws Exception { public static class ResourceWrite implements Callable { AtomicInteger countWrite = new AtomicInteger(0); + @Override public Void call() throws Exception { lockMgr.acquireLock(Thread.currentThread(), this, LOCK.EXCLUSIVE); try { @@ -97,6 +99,7 @@ public static class ResourceReadWrite implements Callable { AtomicInteger countWrite = new AtomicInteger(0); volatile boolean lastWasRead; + @Override public Void call() throws Exception { if (lastWasRead) { write(); @@ -150,6 +153,7 @@ public static class ResourceReantrance implements Callable { AtomicInteger countWrite = new AtomicInteger(0); AtomicInteger countReentrantWrite = new AtomicInteger(0); + @Override public Void call() throws Exception { write(); return null; @@ -226,6 +230,7 @@ void reentrantWrite() { public class Process implements Runnable { + @Override public void run() { try { for (int i = 0; i < cyclesByProcess; i++) { diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/MultipleDBTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/MultipleDBTest.java index 5740083739c..0faaab969af 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/MultipleDBTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/MultipleDBTest.java @@ -66,6 +66,7 @@ public void testObjectMultipleDBsThreaded() throws Exception { Callable t = new Callable() { + @Override public Void call() throws InterruptedException, IOException { OObjectDatabaseTx tx = new OObjectDatabaseTx(dbUrl); @@ -158,6 +159,7 @@ public void testDocumentMultipleDBsThreaded() throws Exception { Callable t = new Callable() { + @Override public Void call() throws InterruptedException, IOException { ODatabaseDocumentTx tx = new ODatabaseDocumentTx(dbUrl); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTest.java index 18caf06136c..eeafcda7135 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTest.java @@ -852,11 +852,13 @@ public void testCustomTypes() { OObjectSerializerContext serializerContext = new OObjectSerializerContext(); serializerContext.bind(new OObjectSerializer() { + @Override public Long serializeFieldValue(Class itype, CustomType iFieldValue) { serialized++; return iFieldValue.value; } + @Override public CustomType unserializeFieldValue(Class itype, Long iFieldValue) { unserialized++; return new CustomType(iFieldValue); @@ -974,10 +976,12 @@ public void testEnumListWithCustomTypes() { OObjectSerializerContext serializerContext = new OObjectSerializerContext(); serializerContext.bind(new OObjectSerializer() { + @Override public Object serializeFieldValue(Class type, SecurityRole role) { return role.name(); } + @Override public Object unserializeFieldValue(Class type, String str) { return SecurityRole.getByName(str); } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTestSchemaFull.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTestSchemaFull.java index c4547409b06..93eb6c82994 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTestSchemaFull.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/ObjectTreeTestSchemaFull.java @@ -837,11 +837,13 @@ public void testCustomTypes() { OObjectSerializerContext serializerContext = new OObjectSerializerContext(); serializerContext.bind(new OObjectSerializer() { + @Override public Long serializeFieldValue(Class itype, CustomType iFieldValue) { serialized++; return iFieldValue.value; } + @Override public CustomType unserializeFieldValue(Class itype, Long iFieldValue) { unserialized++; return new CustomType(iFieldValue); @@ -959,10 +961,12 @@ public void testEnumListWithCustomTypes() { OObjectSerializerContext serializerContext = new OObjectSerializerContext(); serializerContext.bind(new OObjectSerializer() { + @Override public Object serializeFieldValue(Class type, SecurityRole role) { return role.name(); } + @Override public Object unserializeFieldValue(Class type, String str) { return SecurityRole.getByName(str); } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/PoolTester2.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/PoolTester2.java index f326541fcd8..34b605b1889 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/PoolTester2.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/PoolTester2.java @@ -5,7 +5,6 @@ import java.util.concurrent.Executors; import com.orientechnologies.common.exception.OException; -import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; import com.orientechnologies.orient.core.db.graph.OGraphDatabase; import com.orientechnologies.orient.core.db.graph.OGraphDatabasePool; import com.orientechnologies.orient.core.record.impl.ODocument; diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLFunctionsTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLFunctionsTest.java index ba3a94151a5..2c87152e56f 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLFunctionsTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLFunctionsTest.java @@ -326,10 +326,12 @@ public void queryUndefinedFunction() { @Test public void queryCustomFunction() { OSQLEngine.getInstance().registerFunction("bigger", new OSQLFunctionAbstract("bigger", 2, 2) { + @Override public String getSyntax() { return "bigger(, )"; } + @Override public Object execute(OIdentifiable iCurrentRecord, Object iCurrentResult, final Object[] iParameters, OCommandContext iContext) { if (iParameters[0] == null || iParameters[1] == null) diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLIndexWithoutSchemaTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLIndexWithoutSchemaTest.java index fb202f17196..0f1397d21d8 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLIndexWithoutSchemaTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLIndexWithoutSchemaTest.java @@ -35,6 +35,7 @@ public SQLIndexWithoutSchemaTest(final String iURL) { super(iURL); } + @Override @BeforeClass public void setUp() throws Exception { super.setUp(); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectByLinkedPropertyIndexReuseTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectByLinkedPropertyIndexReuseTest.java index a0803a3abc6..608ffcbc239 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectByLinkedPropertyIndexReuseTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectByLinkedPropertyIndexReuseTest.java @@ -92,9 +92,10 @@ public void testNotUniqueUniqueUniqueEqualsUsing() throws Exception { } List result = database.query(new OSQLSynchQuery( - "select from lpirtStudent where group.curator.salary = 2000")); - assertEquals(result.size(), 1); - assertEquals(containsDocumentWithFieldValue(result, "name", "John Smith"), 1); + "select from lpirtStudent where group.curator.salary = 600")); + assertEquals(result.size(), 2); + assertEquals(containsDocumentWithFieldValue(result, "name", "James Bell"), 1); + assertEquals(containsDocumentWithFieldValue(result, "name", "Roger Connor"), 1); assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 3); } @@ -110,7 +111,7 @@ public void testNotUniqueUniqueNotUniqueEqualsLimitUsing() throws Exception { List result = database.query(new OSQLSynchQuery( "select from lpirtStudent where group.curator.name = 'Someone else' limit 1")); assertEquals(result.size(), 1); - assertTrue(Arrays.asList("Jane Smith", "James Bell", "Roger Connor").contains((String) result.get(0).field("name"))); + assertTrue(Arrays.asList("Jane Smith", "James Bell", "Roger Connor").contains(result.get(0).field("name"))); assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 3); } @@ -147,7 +148,7 @@ public void testNotUniqueUniqueUniqueMinorLimitUsing() throws Exception { final List expectedNames = Arrays.asList("Jane Smith", "James Bell", "Roger Connor"); for (ODocument aResult : result) { - assertTrue(expectedNames.contains((String) aResult.field("name"))); + assertTrue(expectedNames.contains(aResult.field("name"))); } assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 3); @@ -180,7 +181,7 @@ public void testUniqueNotUniqueMinorEqualsLimitUsing() throws Exception { List result = database .query(new OSQLSynchQuery("select from lpirtStudent where diploma.GPA <= 4 limit 1")); assertEquals(result.size(), 1); - assertTrue(Arrays.asList("John Smith", "James Bell").contains((String) result.get(0).field("name"))); + assertTrue(Arrays.asList("John Smith", "James Bell").contains(result.get(0).field("name"))); assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 2); } @@ -214,7 +215,7 @@ public void testNotUniqueUniqueUniqueMajorLimitUsing() throws Exception { assertEquals(result.size(), 1); final List expectedNames = Arrays.asList("John Smith", "James Bell", "Roger Connor"); for (ODocument aResult : result) { - assertTrue(expectedNames.contains((String) aResult.field("name"))); + assertTrue(expectedNames.contains(aResult.field("name"))); } assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 3); @@ -251,7 +252,7 @@ public void testUniqueUniqueBetweenLimitUsing() throws Exception { final List expectedNames = Arrays.asList("PZ-08-2", "PZ-08-3"); for (ODocument aResult : result) { - assertTrue(expectedNames.contains((String) aResult.field("name"))); + assertTrue(expectedNames.contains(aResult.field("name"))); } assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 2); @@ -288,7 +289,7 @@ public void testUniqueUniqueInLimitUsing() throws Exception { final List expectedNames = Arrays.asList("PZ-08-2", "PZ-08-3"); for (ODocument aResult : result) { - assertTrue(expectedNames.contains((String) aResult.field("name"))); + assertTrue(expectedNames.contains(aResult.field("name"))); } assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 2); @@ -324,7 +325,7 @@ public void testUniqueFulltextContainsTextLimitUsing() throws Exception { assertEquals(result.size(), 1); final List expectedNames = Arrays.asList("John Smith", "James Bell"); for (ODocument aResult : result) { - assertTrue(expectedNames.contains((String) aResult.field("name"))); + assertTrue(expectedNames.contains(aResult.field("name"))); } assertEquals(profiler.getCounter("db.demo.query.indexUsed"), oldIndexUsage + 2); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectTest.java index 7e15efac8f2..a720afcb537 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SQLSelectTest.java @@ -1339,8 +1339,8 @@ public void subQueryNoFrom() { .execute(); Assert.assertTrue(result2.size() != 0); - Assert.assertTrue(((ODocument) result2.get(0)).field("$names") instanceof Collection); - Assert.assertFalse(((Collection) ((ODocument) result2.get(0)).field("$names")).isEmpty()); + Assert.assertTrue(result2.get(0).field("$names") instanceof Collection); + Assert.assertFalse(((Collection) result2.get(0).field("$names")).isEmpty()); } @Test diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SchemaTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SchemaTest.java index 45c681a069a..6f2789698fd 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SchemaTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/SchemaTest.java @@ -198,6 +198,7 @@ public void testMultiThreadSchemaCreation() throws InterruptedException { Thread thread = new Thread(new Runnable() { + @Override public void run() { ODatabaseRecordThreadLocal.INSTANCE.set(database); ODocument doc = new ODocument("NewClass"); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/StorageTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/StorageTest.java index 07df907863a..eb0e86b770b 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/StorageTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/StorageTest.java @@ -65,6 +65,7 @@ public void testCreateDataSegment() throws IOException { database.setDataSegmentStrategy(new ODataSegmentStrategy() { + @Override public int assignDataSegmentId(ODatabase iDatabase, ORecord iRecord) { return 1; } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionAtomicTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionAtomicTest.java index 4e843446334..3ed50769a51 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionAtomicTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionAtomicTest.java @@ -104,34 +104,44 @@ public void testTransactionPreListenerRollback() throws IOException { db.registerListener(new ODatabaseListener() { + @Override public void onAfterTxCommit(ODatabase iDatabase) { } + @Override public void onAfterTxRollback(ODatabase iDatabase) { } + @Override public void onBeforeTxBegin(ODatabase iDatabase) { } + @Override public void onBeforeTxCommit(ODatabase iDatabase) { throw new RuntimeException("Rollback test"); } + @Override public void onBeforeTxRollback(ODatabase iDatabase) { } + @Override public void onClose(ODatabase iDatabase) { } + @Override public void onCreate(ODatabase iDatabase) { } + @Override public void onDelete(ODatabase iDatabase) { } + @Override public void onOpen(ODatabase iDatabase) { } + @Override public boolean onCorruptionRepairDatabase(ODatabase iDatabase, final String iReason, String iWhatWillbeFixed) { return true; } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionConsistencyTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionConsistencyTest.java index 2209c706c84..cab8882b41f 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionConsistencyTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TransactionConsistencyTest.java @@ -552,11 +552,11 @@ public void deletesWithinTransactionArentWorking() throws IOException { // Commenting out the transaction will result in the test succeeding. db.begin(TXTYPE.OPTIMISTIC); - ODocument foo = (ODocument) db.createVertex("Foo").field("prop", "test1").save(); + ODocument foo = db.createVertex("Foo").field("prop", "test1").save(); // Comment out these two lines and the test will succeed. The issue appears to be related to an edge // connecting a deleted vertex during a transaction - ODocument bar = (ODocument) db.createVertex("Bar").field("prop", "test1").save(); + ODocument bar = db.createVertex("Bar").field("prop", "test1").save(); ODocument sees = db.createEdge(foo, bar, "Sees"); db.commit(); diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TraverseTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TraverseTest.java index acbea823058..78d341f28bd 100644 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TraverseTest.java +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/TraverseTest.java @@ -233,6 +233,7 @@ public void traverseSQLIterating() { public void traverseAPIIterating() { int cycles = 0; for (OIdentifiable id : new OTraverse().target(database.browseClass("Movie").iterator()).predicate(new OCommandPredicate() { + @Override public Object evaluate(ORecord iRecord, ODocument iCurrentResult, OCommandContext iContext) { return ((Integer) iContext.getVariable("depth")) <= 2; } diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/local-test-db-from-scratch.xml b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/local-test-db-from-scratch.xml index 1bbbf95928d..102274128f0 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/local-test-db-from-scratch.xml +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/local-test-db-from-scratch.xml @@ -168,6 +168,7 @@ + diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/memory-test-db-from-scratch.xml b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/memory-test-db-from-scratch.xml index 94a9556c269..b39dcda2765 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/memory-test-db-from-scratch.xml +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/memory-test-db-from-scratch.xml @@ -159,6 +159,7 @@ + diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/paginated-local-test-db-from-scratch.xml b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/paginated-local-test-db-from-scratch.xml index 0478134ccfa..6b6156b49cb 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/paginated-local-test-db-from-scratch.xml +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/paginated-local-test-db-from-scratch.xml @@ -168,6 +168,7 @@ + diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/remote-test-db-from-scratch.xml b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/remote-test-db-from-scratch.xml index 8a88ef27e25..360eecf2681 100755 --- a/tests/src/test/java/com/orientechnologies/orient/test/database/auto/remote-test-db-from-scratch.xml +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/auto/remote-test-db-from-scratch.xml @@ -149,6 +149,7 @@ + diff --git a/tests/src/test/java/com/orientechnologies/orient/test/database/speed/ODocumentSerializationSpeedTest.java b/tests/src/test/java/com/orientechnologies/orient/test/database/speed/ODocumentSerializationSpeedTest.java new file mode 100644 index 00000000000..79738bdb6a6 --- /dev/null +++ b/tests/src/test/java/com/orientechnologies/orient/test/database/speed/ODocumentSerializationSpeedTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2012 Luca Garulli (l.garulli--at--orientechnologies.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.orientechnologies.orient.test.database.speed; + +import org.testng.annotations.Test; + +import com.orientechnologies.orient.core.record.impl.ODocument; +import com.orientechnologies.orient.test.database.base.OrientMonoThreadTest; + +@Test(enabled = false) +public class ODocumentSerializationSpeedTest extends OrientMonoThreadTest { + private ODocument record; + + public static void main(String[] iArgs) throws InstantiationException, IllegalAccessException { + ODocumentSerializationSpeedTest test = new ODocumentSerializationSpeedTest(); + test.data.go(test); + } + + public ODocumentSerializationSpeedTest() throws InstantiationException, IllegalAccessException { + super(1000000); + + record = new ODocument(); + } + + @Override + public void cycle() { + record.reset(); + record.field("id", data.getCyclesDone()); + record.field("name", "Luca"); + record.field("surname", "Garulli"); + record.field("salary", 3000f); + final byte[] buffer = record.toStream(); + + record.reset(); + record.fromStream(buffer); + record.toString(); + } + + @Override + public void deinit() { + super.deinit(); + } +} diff --git a/tools/pom.xml b/tools/pom.xml index e9c2c6b25cf..129c3bcd468 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -22,7 +22,7 @@ com.orientechnologies orientdb-parent - 1.6.1 + 1.6.2 ../ diff --git a/tools/src/main/java/com/orientechnologies/orient/console/OConsoleDatabaseApp.java b/tools/src/main/java/com/orientechnologies/orient/console/OConsoleDatabaseApp.java index fba37e69c32..004831cd668 100755 --- a/tools/src/main/java/com/orientechnologies/orient/console/OConsoleDatabaseApp.java +++ b/tools/src/main/java/com/orientechnologies/orient/console/OConsoleDatabaseApp.java @@ -1099,19 +1099,19 @@ public void infoClass(@ConsoleParameter(name = "class-name", description = "The if (cls.properties().size() > 0) { message("\nProperties:"); - message("\n-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+"); - message("\n NAME | TYPE | LINKED TYPE/CLASS | MANDATORY | READONLY | NOT NULL | MIN | MAX |"); - message("\n-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+"); + message("\n-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+"); + message("\n NAME | TYPE | LINKED TYPE/CLASS | MANDATORY | READONLY | NOT NULL | MIN | MAX | COLLATE |"); + message("\n-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+"); for (final OProperty p : cls.properties()) { try { - message("\n %-30s| %-12s| %-30s| %-10s| %-9s| %-9s| %-10s| %-10s|", p.getName(), p.getType(), + message("\n %-30s| %-12s| %-30s| %-10s| %-9s| %-9s| %-10s| %-10s| %-9s|", p.getName(), p.getType(), p.getLinkedClass() != null ? p.getLinkedClass() : p.getLinkedType(), p.isMandatory(), p.isReadonly(), p.isNotNull(), - p.getMin() != null ? p.getMin() : "", p.getMax() != null ? p.getMax() : ""); + p.getMin() != null ? p.getMin() : "", p.getMax() != null ? p.getMax() : "", p.getCollate() != null ? p.getCollate().getName() : ""); } catch (Exception e) { } } - message("\n-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+"); + message("\n-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+"); } final Set> indexes = cls.getClassIndexes(); diff --git a/tools/src/main/java/com/orientechnologies/orient/console/OTableFormatter.java b/tools/src/main/java/com/orientechnologies/orient/console/OTableFormatter.java index 2a4652a04e0..5082c24e0b6 100644 --- a/tools/src/main/java/com/orientechnologies/orient/console/OTableFormatter.java +++ b/tools/src/main/java/com/orientechnologies/orient/console/OTableFormatter.java @@ -16,8 +16,18 @@ package com.orientechnologies.orient.console; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import com.orientechnologies.common.collection.OMultiCollectionIterator; import com.orientechnologies.common.console.OConsoleApplication; @@ -179,7 +189,7 @@ private void printHeader(final Map iColumns) { } private void printHeaderLine(final Map iColumns) { - final StringBuilder buffer = new StringBuilder(); + final StringBuilder buffer = new StringBuilder("\n"); if (iColumns.size() > 0) { int i = 0;