Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add a special RubyArray subclass for LOADED_FEATURES, to speed up sea…

…rches during Kernel#require.
  • Loading branch information...
commit 21565774f8800b3df6f839505365d340b573f253 1 parent c70879d
@headius headius authored
View
2  src/org/jruby/RubyArray.java
@@ -303,7 +303,7 @@ private RubyArray(Ruby runtime, RubyClass metaClass, IRubyObject[] vals, int beg
this.isShared = true;
}
- private RubyArray(Ruby runtime, int length) {
+ protected RubyArray(Ruby runtime, int length) {
super(runtime, runtime.getArray());
values = new IRubyObject[length];
}
View
70 src/org/jruby/runtime/load/LoadService.java
@@ -33,13 +33,13 @@
***** END LICENSE BLOCK *****/
package org.jruby.runtime.load;
+import org.jruby.util.collections.StringArraySet;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -54,7 +54,6 @@
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyFile;
-import org.jruby.RubyFixnum;
import org.jruby.RubyHash;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyString;
@@ -62,6 +61,7 @@
import org.jruby.exceptions.MainExitException;
import org.jruby.exceptions.RaiseException;
import org.jruby.platform.Platform;
+import org.jruby.runtime.Block;
import org.jruby.runtime.Constants;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.JRubyFile;
@@ -156,8 +156,7 @@
protected static final Pattern extensionPattern = Pattern.compile("\\.(?:so|o|dll|bundle|jar)$");
protected RubyArray loadPath;
- protected RubyArray loadedFeatures;
- protected List loadedFeaturesInternal;
+ protected StringArraySet loadedFeatures;
protected final Map<String, Library> builtinLibraries = new HashMap<String, Library>();
protected final Map<String, JarFile> jarFiles = new HashMap<String, JarFile>();
@@ -179,8 +178,23 @@ public LoadService(Ruby runtime) {
public void init(List additionalDirectories) {
loadPath = RubyArray.newArray(runtime);
- loadedFeatures = RubyArray.newArray(runtime);
- loadedFeaturesInternal = Collections.synchronizedList(loadedFeatures);
+
+ String jrubyHome = runtime.getJRubyHome();
+ if (jrubyHome != null) {
+ String lowerCaseJRubyHome = jrubyHome.toLowerCase();
+ String upperCaseJRubyHome = lowerCaseJRubyHome.toUpperCase();
+
+ try {
+ String canonNormal = new File(jrubyHome).getCanonicalPath();
+ String canonLower = new File(lowerCaseJRubyHome).getCanonicalPath();
+ String canonUpper = new File(upperCaseJRubyHome).getCanonicalPath();
+ if (canonNormal.equals(canonLower) && canonLower.equals(canonUpper)) {
+ caseInsensitiveFS = true;
+ }
+ } catch (Exception e) {}
+ }
+
+ loadedFeatures = new StringArraySet(runtime, caseInsensitiveFS);
// add all startup load paths to the list first
for (Iterator iter = additionalDirectories.iterator(); iter.hasNext();) {
@@ -200,7 +214,6 @@ public void init(List additionalDirectories) {
// wrap in try/catch for security exceptions in an applet
try {
- String jrubyHome = runtime.getJRubyHome();
if (jrubyHome != null) {
char sep = '/';
String rubyDir = jrubyHome + sep + "lib" + sep + "ruby" + sep;
@@ -217,18 +230,6 @@ public void init(List additionalDirectories) {
addPath(rubyDir + "site_ruby" + sep + "shared");
addPath(rubyDir + Constants.RUBY_MAJOR_VERSION);
}
-
- String lowerCaseJRubyHome = jrubyHome.toLowerCase();
- String upperCaseJRubyHome = lowerCaseJRubyHome.toUpperCase();
-
- try {
- String canonNormal = new File(jrubyHome).getCanonicalPath();
- String canonLower = new File(lowerCaseJRubyHome).getCanonicalPath();
- String canonUpper = new File(upperCaseJRubyHome).getCanonicalPath();
- if (canonNormal.equals(canonLower) && canonLower.equals(canonUpper)) {
- caseInsensitiveFS = true;
- }
- } catch (Exception e) {}
}
} catch(SecurityException ignore) {}
@@ -240,7 +241,7 @@ public void init(List additionalDirectories) {
}
protected void addLoadedFeature(RubyString loadNameRubyString) {
- loadedFeaturesInternal.add(loadNameRubyString);
+ loadedFeatures.append(loadNameRubyString);
}
protected void addPath(String path) {
@@ -489,35 +490,12 @@ public void removeBuiltinLibrary(String name) {
}
public void removeInternalLoadedFeature(String name) {
- if (caseInsensitiveFS) {
- // on a case-insensitive filesystem, we need to search case-insensitively
- // to remove the loaded feature
- RubyString nameRubyString = runtime.newString(name);
- for (int i = 0; i < loadedFeatures.size(); i++) {
- RubyString feature = loadedFeatures.eltInternal(i).convertToString();
- if (((RubyFixnum)feature.casecmp(runtime.getCurrentContext(), nameRubyString)).getLongValue() == 0) {
- loadedFeatures.remove(i);
- }
- }
- } else {
- loadedFeaturesInternal.remove(name);
- }
+ RubyString nameRubyString = runtime.newString(name);
+ loadedFeatures.delete(runtime.getCurrentContext(), nameRubyString, Block.NULL_BLOCK);
}
protected boolean featureAlreadyLoaded(RubyString loadNameRubyString) {
- if (caseInsensitiveFS) {
- // on a case-insensitive filesystem, we need to search case-insensitively
- // to find the loaded feature
- for (int i = 0; i < loadedFeatures.size(); i++) {
- RubyString feature = loadedFeatures.eltInternal(i).convertToString();
- if (((RubyFixnum)feature.casecmp(runtime.getCurrentContext(), loadNameRubyString)).getLongValue() == 0) {
- return true;
- }
- }
- return false;
- } else {
- return loadedFeaturesInternal.contains(loadNameRubyString);
- }
+ return loadedFeatures.include_p(runtime.getCurrentContext(), loadNameRubyString).isTrue();
}
protected boolean isJarfileLibrary(SearchState state, final String file) {
View
367 src/org/jruby/util/collections/StringArraySet.java
@@ -0,0 +1,367 @@
+/*
+ ***** BEGIN LICENSE BLOCK *****
+ * Version: CPL 1.0/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Common Public
+ * License Version 1.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.eclipse.org/legal/cpl-v10.html
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Copyright (C) 2011 Charles O Nutter <headius@headius.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the CPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the CPL, the GPL or the LGPL.
+ ***** END LICENSE BLOCK *****/
+package org.jruby.util.collections;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.jruby.Ruby;
+import org.jruby.RubyArray;
+import org.jruby.RubyBoolean;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+/**
+ * An optionally case-insensitive RubyArray that maintains an O(1) Set for fast
+ * include? operations.
+ */
+public class StringArraySet extends RubyArray {
+ private final Set<String> set = new HashSet<String>();
+ private final boolean caseInsensitive;
+
+ public StringArraySet(Ruby runtime, boolean caseInsensitive) {
+ super(runtime, 4);
+ this.caseInsensitive = caseInsensitive;
+ }
+
+ @Override
+ public synchronized RubyArray append(IRubyObject item) {
+ String string = getStringFromItem(item);
+ RubyArray result = super.append(item);
+ set.add(string);
+ return result;
+ }
+
+ @Override
+ public synchronized void clear() {
+ super.clear();
+ set.clear();
+ }
+
+ @Override
+ public synchronized IRubyObject delete(ThreadContext context, IRubyObject item, Block block) {
+ String string = getStringFromItem(item);
+ IRubyObject result = super.delete(context, item, block);
+ set.remove(string);
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject delete_if(ThreadContext context, Block block) {
+ IRubyObject result = super.delete_if(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized RubyBoolean include_p(ThreadContext context, IRubyObject item) {
+ return context.runtime.newBoolean(set.contains(getStringFromItem(item)));
+ }
+
+ @Override
+ public synchronized IRubyObject replace(IRubyObject orig) {
+ IRubyObject result = super.replace(orig);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject unshift(IRubyObject item) {
+ String string = getStringFromItem(item);
+ IRubyObject result = super.unshift(item);
+ set.add(string);
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject unshift(IRubyObject[] items) {
+ IRubyObject result = super.unshift(items);
+ putAll(toJavaArray());
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject aset(IRubyObject arg0, IRubyObject arg1) {
+ IRubyObject result = super.aset(arg0, arg1);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject aset(IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
+ IRubyObject result = super.aset(arg0, arg1, arg2);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject aset19(IRubyObject arg0, IRubyObject arg1) {
+ IRubyObject result = super.aset19(arg0, arg1);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized RubyArray collectBang(ThreadContext context, Block block) {
+ RubyArray result = super.collectBang(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject collect_bang(ThreadContext context, Block block) {
+ IRubyObject result = super.collect_bang(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject compact() {
+ IRubyObject result = super.compact();
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject drop(ThreadContext context, IRubyObject n) {
+ IRubyObject result = super.drop(context, n);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject drop_while(ThreadContext context, Block block) {
+ IRubyObject result = super.drop_while(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject flatten_bang(ThreadContext context) {
+ IRubyObject result = super.flatten_bang(context);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject flatten_bang(ThreadContext context, IRubyObject arg) {
+ IRubyObject result = super.flatten_bang(context, arg);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject flatten_bang19(ThreadContext context) {
+ IRubyObject result = super.flatten_bang19(context);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject flatten_bang19(ThreadContext context, IRubyObject arg) {
+ IRubyObject result = super.flatten_bang19(context, arg);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject insert() {
+ IRubyObject result = super.insert();
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject insert(IRubyObject arg) {
+ IRubyObject result = super.insert(arg);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject insert(IRubyObject arg1, IRubyObject arg2) {
+ IRubyObject result = super.insert(arg1, arg2);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject insert(IRubyObject[] args) {
+ IRubyObject result = super.insert(args);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject insert19(IRubyObject arg) {
+ IRubyObject result = super.insert19(arg);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject insert19(IRubyObject arg1, IRubyObject arg2) {
+ IRubyObject result = super.insert19(arg1, arg2);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject insert19(IRubyObject[] args) {
+ IRubyObject result = super.insert19(args);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject map_bang(ThreadContext context, Block block) {
+ IRubyObject result = super.map_bang(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject pop(ThreadContext context) {
+ IRubyObject result = super.pop(context);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject pop(ThreadContext context, IRubyObject num) {
+ IRubyObject result = super.pop(context, num);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized RubyArray push_m(IRubyObject[] items) {
+ RubyArray result = super.push_m(items);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized RubyArray push_m19(IRubyObject[] items) {
+ RubyArray result = super.push_m19(items);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject rejectBang(ThreadContext context, Block block) {
+ IRubyObject result = super.rejectBang(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject reject_bang(ThreadContext context, Block block) {
+ IRubyObject result = super.reject_bang(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject select_bang(ThreadContext context, Block block) {
+ IRubyObject result = super.select_bang(context, block);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject shift(ThreadContext context) {
+ IRubyObject result = super.shift(context);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject shift(ThreadContext context, IRubyObject num) {
+ IRubyObject result = super.shift(context, num);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject slice_bang(IRubyObject arg0) {
+ IRubyObject result = super.slice_bang(arg0);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject slice_bang(IRubyObject arg0, IRubyObject arg1) {
+ IRubyObject result = super.slice_bang(arg0, arg1);
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject unshift() {
+ IRubyObject result = super.unshift();
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject unshift19() {
+ IRubyObject result = super.unshift19();
+ rehash();
+ return result;
+ }
+
+ @Override
+ public synchronized IRubyObject unshift19(IRubyObject item) {
+ IRubyObject result = super.unshift19(item);
+ rehash();
+ return result;
+ }
+
+ private String getStringFromItem(IRubyObject item) {
+ String string = item.convertToString().asJavaString();
+ if (caseInsensitive) {
+ string = string.toLowerCase();
+ }
+ return string;
+ }
+
+ private void rehash() {
+ set.clear();
+ putAll(toJavaArray());
+ }
+
+ private void putAll(IRubyObject[] items) {
+ for (IRubyObject item : items) {
+ String string = getStringFromItem(item);
+ set.add(string);
+ }
+ }
+
+}
Please sign in to comment.
Something went wrong with that request. Please try again.