Index: solr/core/src/test-files/solr/solr.xml
===================================================================
--- solr/core/src/test-files/solr/solr.xml	(revision 1485406)
+++ solr/core/src/test-files/solr/solr.xml	(working copy)
@@ -30,6 +30,7 @@
   -->
   <cores adminPath="/admin/cores" defaultCoreName="collection1" host="127.0.0.1" hostPort="${hostPort:8983}" 
          hostContext="${hostContext:solr}" zkClientTimeout="${solr.zkclienttimeout:30000}" numShards="${numShards:3}" shareSchema="${shareSchema:false}" 
+         genericCoreNodeNames="${genericCoreNodeNames:true}"
          distribUpdateConnTimeout="${distribUpdateConnTimeout:15000}" distribUpdateSoTimeout="${distribUpdateSoTimeout:120000}">
     <core name="collection1" instanceDir="collection1" shard="${shard:}" collection="${collection:collection1}" config="${solrconfig:solrconfig.xml}" schema="${schema:schema.xml}"
           coreNodeName="${coreNodeName:}"/>
Index: solr/core/src/test-files/solr/solr-no-core.xml
===================================================================
--- solr/core/src/test-files/solr/solr-no-core.xml	(revision 1485406)
+++ solr/core/src/test-files/solr/solr-no-core.xml	(working copy)
@@ -25,6 +25,7 @@
     <str name="hostContext">${hostContext:solr}</str>
     <int name="hostPort">${hostPort:8983}</int>
     <int name="zkClientTimeout">${solr.zkclienttimeout:30000}</int>
+    <bool nae="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
     <int name="distribUpdateConnTimeout">${distribUpdateConnTimeout:15000}</int>
     <int name="distribUpdateSoTimeout">${distribUpdateSoTimeout:120000}</int>
   </solrcloud>
Index: solr/core/src/java/org/apache/solr/cloud/Assign.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/Assign.java	(working copy)
+++ solr/core/src/java/org/apache/solr/cloud/Assign.java	(working copy)
@@ -23,12 +23,35 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
 
-public class AssignShard {
+public class Assign {
+  private static Pattern COUNT = Pattern.compile("core_node(\\d+)");
 
+  public static String assignNode(String collection, ClusterState state) {
+    Map<String, Slice> sliceMap = state.getSlicesMap(collection);
+    if (sliceMap == null) {
+      return "core_node1";
+    }
+
+    int max = 0;
+    for (Slice slice : sliceMap.values()) {
+      for (Replica replica : slice.getReplicas()) {
+        Matcher m = COUNT.matcher(replica.getName());
+        if (m.matches()) {
+          max = Math.max(max, Integer.parseInt(m.group(1)));
+        }
+      }
+    }
+
+    return "core_node" + (max + 1);
+  }
+  
   /**
    * Assign a new unique id up to slices count - then add replicas evenly.
    * 
@@ -39,7 +62,7 @@
       numShards = 1;
     }
     String returnShardId = null;
-    Map<String, Slice> sliceMap = state.getSlicesMap(collection);
+    Map<String, Slice> sliceMap = state.getActiveSlicesMap(collection);
 
 
     // TODO: now that we create shards ahead of time, is this code needed?  Esp since hash ranges aren't assigned when creating via this method?
Index: solr/core/src/java/org/apache/solr/cloud/SyncStrategy.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/SyncStrategy.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/cloud/SyncStrategy.java	(working copy)
@@ -160,8 +160,7 @@
   private boolean syncWithReplicas(ZkController zkController, SolrCore core,
       ZkNodeProps props, String collection, String shardId) {
     List<ZkCoreNodeProps> nodes = zkController.getZkStateReader()
-        .getReplicaProps(collection, shardId,
-            zkController.getCoreNodeName(core.getCoreDescriptor()),
+        .getReplicaProps(collection, shardId,core.getCoreDescriptor().getCloudDescriptor().getCoreNodeName(),
             props.getStr(ZkStateReader.CORE_NAME_PROP));
     
     if (nodes == null) {
@@ -189,7 +188,7 @@
     List<ZkCoreNodeProps> nodes = zkController
         .getZkStateReader()
         .getReplicaProps(collection, shardId,
-            zkController.getCoreNodeName(cd),
+            cd.getCloudDescriptor().getCoreNodeName(),
             leaderProps.getStr(ZkStateReader.CORE_NAME_PROP));
     if (nodes == null) {
       log.info(ZkCoreNodeProps.getCoreUrl(leaderProps) + " has no replicas");
Index: solr/core/src/java/org/apache/solr/cloud/ZkController.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/ZkController.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/cloud/ZkController.java	(working copy)
@@ -132,6 +132,8 @@
   protected volatile Overseer overseer;
 
   private String leaderVoteWait;
+  
+  private boolean genericCoreNodeNames;
 
   private int clientTimeout;
 
@@ -140,11 +142,11 @@
   private UpdateShardHandler updateShardHandler;
 
   public ZkController(final CoreContainer cc, String zkServerAddress, int zkClientTimeout, int zkClientConnectTimeout, String localHost, String locaHostPort,
-      String localHostContext, String leaderVoteWait, int distribUpdateConnTimeout, int distribUpdateSoTimeout, final CurrentCoreDescriptorProvider registerOnReconnect) throws InterruptedException,
+      String localHostContext, String leaderVoteWait, boolean genericCoreNodeNames, int distribUpdateConnTimeout, int distribUpdateSoTimeout, final CurrentCoreDescriptorProvider registerOnReconnect) throws InterruptedException,
       TimeoutException, IOException {
     if (cc == null) throw new IllegalArgumentException("CoreContainer cannot be null.");
     this.cc = cc;
-
+    this.genericCoreNodeNames = genericCoreNodeNames;
     // be forgiving and strip this off leading/trailing slashes
     // this allows us to support users specifying hostContext="/" in 
     // solr.xml to indicate the root context, instead of hostContext="" 
@@ -254,9 +256,9 @@
       // before registering as live, make sure everyone is in a
       // down state
       for (CoreDescriptor descriptor : descriptors) {
-        final String coreZkNodeName = getCoreNodeName(descriptor);
+        final String coreZkNodeName = descriptor.getCloudDescriptor().getCoreNodeName();
         try {
-          descriptor.getCloudDescriptor().isLeader = false;
+          descriptor.getCloudDescriptor().setLeader(false);
           publish(descriptor, ZkStateReader.DOWN, updateLastPublished);
         } catch (Exception e) {
           if (isClosed) {
@@ -323,7 +325,7 @@
         .getCurrentDescriptors();
     if (descriptors != null) {
       for (CoreDescriptor descriptor : descriptors) {
-        descriptor.getCloudDescriptor().isLeader = false;
+        descriptor.getCloudDescriptor().setLeader(false);
       }
     }
   }
@@ -544,7 +546,6 @@
           if (replica.getNodeName().equals(getNodeName())
               && !(replica.getStr(ZkStateReader.STATE_PROP)
                   .equals(ZkStateReader.DOWN))) {
-            assert replica.getStr(ZkStateReader.SHARD_ID_PROP) != null;
             ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, "state",
                 ZkStateReader.STATE_PROP, ZkStateReader.DOWN,
                 ZkStateReader.BASE_URL_PROP, getBaseUrl(),
@@ -555,8 +556,7 @@
                 ZkStateReader.NODE_NAME_PROP, getNodeName(),
                 ZkStateReader.SHARD_ID_PROP,
                 replica.getStr(ZkStateReader.SHARD_ID_PROP),
-                ZkStateReader.COLLECTION_PROP,
-                replica.getStr(ZkStateReader.COLLECTION_PROP),
+                ZkStateReader.COLLECTION_PROP, collectionName,
                 ZkStateReader.CORE_NODE_NAME_PROP, replica.getName());
             updatedNodes.add(replica.getStr(ZkStateReader.CORE_NAME_PROP));
             overseerJobQueue.offer(ZkStateReader.toJSON(m));
@@ -735,7 +735,8 @@
     final CloudDescriptor cloudDesc = desc.getCloudDescriptor();
     final String collection = cloudDesc.getCollectionName();
 
-    final String coreZkNodeName = getCoreNodeName(desc);
+    final String coreZkNodeName = desc.getCloudDescriptor().getCoreNodeName();
+    assert coreZkNodeName != null : "we should have a coreNodeName by now";
     
     String shardId = cloudDesc.getShardId();
 
@@ -923,16 +924,16 @@
     props.put(ZkStateReader.CORE_NAME_PROP, cd.getName());
     props.put(ZkStateReader.NODE_NAME_PROP, getNodeName());
     
-    final String coreZkNodeName = getCoreNodeName(cd);
+    final String coreNodeName = cd.getCloudDescriptor().getCoreNodeName();
     ZkNodeProps ourProps = new ZkNodeProps(props);
     String collection = cd.getCloudDescriptor()
         .getCollectionName();
     
     ElectionContext context = new ShardLeaderElectionContext(leaderElector, shardId,
-        collection, coreZkNodeName, ourProps, this, cc);
+        collection, coreNodeName, ourProps, this, cc);
 
     leaderElector.setup(context);
-    electionContexts.put(coreZkNodeName, context);
+    electionContexts.put(coreNodeName, context);
     leaderElector.joinElection(context, false);
   }
 
@@ -1017,7 +1018,7 @@
 
     final CloudDescriptor cloudDesc = desc.getCloudDescriptor();
     
-    final String shardId = state.getShardId(coreNodeName);
+    final String shardId = state.getShardId(getBaseUrl(), desc.getName());
 
     if (shardId != null) {
       cloudDesc.setShardId(shardId);
@@ -1028,16 +1029,21 @@
 
   public void unregister(String coreName, CoreDescriptor cd)
       throws InterruptedException, KeeperException {
-    final String zkNodeName = getCoreNodeName(cd);
-    ElectionContext context = electionContexts.remove(zkNodeName);
+    final String coreNodeName = cd.getCloudDescriptor().getCoreNodeName();
+    ElectionContext context = electionContexts.remove(coreNodeName);
+    
+    assert context != null : coreNodeName;
+    
     if (context != null) {
       context.cancelElection();
     }
+    CloudDescriptor cloudDescriptor = cd.getCloudDescriptor();
     
     ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION,
-        "deletecore", ZkStateReader.CORE_NAME_PROP, coreName,
+        Overseer.DELETECORE, ZkStateReader.CORE_NAME_PROP, coreName,
         ZkStateReader.NODE_NAME_PROP, getNodeName(),
-        ZkStateReader.COLLECTION_PROP, cd.getCloudDescriptor().getCollectionName());
+        ZkStateReader.COLLECTION_PROP, cloudDescriptor.getCollectionName(),
+        ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName);
     overseerJobQueue.offer(ZkStateReader.toJSON(m));
   }
   
@@ -1206,13 +1212,61 @@
     return zkStateReader;
   }
 
-  private String doGetShardIdProcess(String coreName, CoreDescriptor descriptor) {
-    final String coreNodeName = getCoreNodeName(descriptor);
+  private void doGetShardIdAndNodeNameProcess(CoreDescriptor cd) {
+    final String coreNodeName = cd.getCloudDescriptor().getCoreNodeName();
+
+    if (coreNodeName != null) {
+      waitForShardId(cd);
+    } else {
+      // if no explicit coreNodeName, we want to match by base url and core name
+      waitForCoreNodeName(cd, coreNodeName);
+      waitForShardId(cd);
+    }
+  }
+
+  private void waitForCoreNodeName(CoreDescriptor descriptor,
+      final String coreNodeName) {
+    int retryCount = 320;
+    log.info("look for our core node name");
+    while (retryCount-- > 0) {
+      Map<String,Slice> slicesMap = zkStateReader.getClusterState()
+          .getSlicesMap(descriptor.getCloudDescriptor().getCollectionName());
+      if (slicesMap != null) {
+        
+        for (Slice slice : slicesMap.values()) {
+          for (Replica replica : slice.getReplicas()) {
+            // TODO: for really large clusters, we could 'index' on this
+            
+            String baseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+            String core = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+            
+            String msgBaseUrl = getBaseUrl();
+            String msgCore = descriptor.getName();
+
+            if (baseUrl.equals(msgBaseUrl) && core.equals(msgCore)) {
+              descriptor.getCloudDescriptor()
+                  .setCoreNodeName(replica.getName());
+              return;
+            }
+          }
+        }
+      }
+      try {
+        Thread.sleep(1000);
+      } catch (InterruptedException e) {
+        Thread.currentThread().interrupt();
+      }
+    }
+  }
+
+  private void waitForShardId(CoreDescriptor cd) {
+    log.info("waiting to find shard id in clusterstate for " + cd.getName());
     int retryCount = 320;
     while (retryCount-- > 0) {
-      final String shardId = zkStateReader.getClusterState().getShardId(coreNodeName);
+      final String shardId = zkStateReader.getClusterState().getShardId(getBaseUrl(), cd.getName());
       if (shardId != null) {
-        return shardId;
+        cd.getCloudDescriptor().setShardId(shardId);
+        return;
       }
       try {
         Thread.sleep(1000);
@@ -1222,7 +1276,7 @@
     }
     
     throw new SolrException(ErrorCode.SERVER_ERROR,
-        "Could not get shard_id for core: " + coreName + " coreNodeName:" + coreNodeName);
+        "Could not get shard id for core: " + cd.getName());
   }
   
   public static void uploadToZK(SolrZkClient zkClient, File dir, String zkPath) throws IOException, KeeperException, InterruptedException {
@@ -1259,9 +1313,9 @@
   }
   
   
-  public String getCoreNodeName(CoreDescriptor descriptor){
+  private String getCoreNodeName(CoreDescriptor descriptor){
     String coreNodeName = descriptor.getCloudDescriptor().getCoreNodeName();
-    if (coreNodeName == null) {
+    if (coreNodeName == null && !genericCoreNodeNames) {
       // it's the default
       return getNodeName() + "_" + descriptor.getName();
     }
@@ -1279,32 +1333,33 @@
 
   public void preRegister(SolrCore core) throws KeeperException, InterruptedException {
     CoreDescriptor cd = core.getCoreDescriptor();
+    String coreNodeName = getCoreNodeName(cd);
+    
+    // make sure the node name is set on the descriptor
+    if (cd.getCloudDescriptor().getCoreNodeName() == null) {
+      cd.getCloudDescriptor().setCoreNodeName(coreNodeName);
+    }
+    
     if (Slice.CONSTRUCTION.equals(cd.getCloudDescriptor().getShardState())) {
       // set update log to buffer before publishing the core
       core.getUpdateHandler().getUpdateLog().bufferUpdates();
     }
+    
     // before becoming available, make sure we are not live and active
     // this also gets us our assigned shard id if it was not specified
     publish(cd, ZkStateReader.DOWN, false);
+
     // shardState and shardRange are for one-time use only, thereafter the actual values in the Slice should be used
     if (Slice.CONSTRUCTION.equals(cd.getCloudDescriptor().getShardState())) {
       cd.getCloudDescriptor().setShardState(null);
       cd.getCloudDescriptor().setShardRange(null);
     }
-    String coreNodeName = getCoreNodeName(cd);
-    
-    // make sure the node name is set on the descriptor
-    if (cd.getCloudDescriptor().getCoreNodeName() == null) {
-      cd.getCloudDescriptor().setCoreNodeName(coreNodeName);
-    }
     
     if (cd.getCloudDescriptor().getShardId() == null && needsToBeAssignedShardId(cd, zkStateReader.getClusterState(), coreNodeName)) {
-      String shardId;
-      shardId = doGetShardIdProcess(cd.getName(), cd);
-      cd.getCloudDescriptor().setShardId(shardId);
+      doGetShardIdAndNodeNameProcess(cd);
     } else {
       // still wait till we see us in local state
-      doGetShardIdProcess(cd.getName(), cd);
+      doGetShardIdAndNodeNameProcess(cd);
     }
 
   }
@@ -1449,7 +1504,6 @@
       String rawName = PropertiesUtil.substituteProperty(cfg.getProperty(coreName, "name", null), new Properties());
       String instanceDir = cfg.getProperty(coreName, "instanceDir", null);
       File idir = new File(instanceDir);
-      System.out.println("idir:" + idir);
       if (!idir.isAbsolute()) {
         idir = new File(solrHome, instanceDir);
       }
@@ -1501,7 +1555,7 @@
   }
   
   /**
-   * utilitiy method fro trimming and leading and/or trailing slashes from 
+   * Utility method for trimming and leading and/or trailing slashes from 
    * it's input.  May return the empty string.  May return null if and only 
    * if the input is null.
    */
Index: solr/core/src/java/org/apache/solr/cloud/CloudDescriptor.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/CloudDescriptor.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/cloud/CloudDescriptor.java	(working copy)
@@ -33,8 +33,8 @@
    * Use the values from {@link Slice} instead */
   volatile String shardRange = null;
   volatile String shardState = Slice.ACTIVE;
-
-  volatile boolean isLeader = false;
+  
+  private volatile boolean isLeader = false;
   volatile String lastPublished = ZkStateReader.ACTIVE;
   
   public String getLastPublished() {
@@ -44,6 +44,10 @@
   public boolean isLeader() {
     return isLeader;
   }
+  
+  public void setLeader(boolean isLeader) {
+    this.isLeader = isLeader;
+  }
 
   public void setShardId(String shardId) {
     this.shardId = shardId;
Index: solr/core/src/java/org/apache/solr/cloud/Overseer.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/Overseer.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/cloud/Overseer.java	(working copy)
@@ -50,15 +50,15 @@
  */
 public class Overseer {
   public static final String QUEUE_OPERATION = "operation";
+  public static final String DELETECORE = "deletecore";
   public static final String REMOVECOLLECTION = "removecollection";
-  
+
   private static final int STATE_UPDATE_DELAY = 1500;  // delay between cloud state updates
 
   private static Logger log = LoggerFactory.getLogger(Overseer.class);
   
   private class ClusterStateUpdater implements Runnable, ClosableThread {
     
-    private static final String DELETECORE = "deletecore";
     private final ZkStateReader reader;
     private final SolrZkClient zkClient;
     private final String myId;
@@ -267,8 +267,14 @@
         final String collection = message.getStr(ZkStateReader.COLLECTION_PROP);
         String coreNodeName = message.getStr(ZkStateReader.CORE_NODE_NAME_PROP);
         if (coreNodeName == null) {
-          // it must be the default then
-          coreNodeName = message.getStr(ZkStateReader.NODE_NAME_PROP) + "_" + message.getStr(ZkStateReader.CORE_NAME_PROP);
+          coreNodeName = getAssignedCoreNodeName(state, message);
+          if (coreNodeName != null) {
+            log.info("node=" + coreNodeName + " is already registered");
+          } else {
+            // if coreNodeName is null, auto assign one
+            coreNodeName = Assign.assignNode(collection, state);
+          }
+          message.getProperties().put(ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName);
         }
         Integer numShards = message.getStr(ZkStateReader.NUM_SHARDS_PROP)!=null?Integer.parseInt(message.getStr(ZkStateReader.NUM_SHARDS_PROP)):null;
         log.info("Update state numShards={} message={}", numShards, message);
@@ -281,7 +287,6 @@
         // use the provided non null shardId
         String sliceName = message.getStr(ZkStateReader.SHARD_ID_PROP);
         if (sliceName == null) {
-          //String nodeName = message.getStr(ZkStateReader.NODE_NAME_PROP);
           //get shardId from ClusterState
           sliceName = getAssignedId(state, coreNodeName, message);
           if (sliceName != null) {
@@ -295,12 +300,11 @@
             numShards = state.getCollectionStates().get(collection).getSlices().size();
             log.info("Collection already exists with " + ZkStateReader.NUM_SHARDS_PROP + "=" + numShards);
           }
-          sliceName = AssignShard.assignShard(collection, state, numShards);
-          log.info("Assigning new node to shard=" + sliceName);
+          sliceName = Assign.assignShard(collection, state, numShards);
+          log.info("Assigning new node to shard shard=" + sliceName);
         }
 
         Slice slice = state.getSlice(collection, sliceName);
-        
         Map<String,Object> replicaProps = new LinkedHashMap<String,Object>();
 
         replicaProps.putAll(message.getProperties());
@@ -320,8 +324,11 @@
           }
         }
 
-        // we don't put num_shards in the clusterstate
+        // we don't put these in the clusterstate
           replicaProps.remove(ZkStateReader.NUM_SHARDS_PROP);
+          replicaProps.remove(ZkStateReader.CORE_NODE_NAME_PROP);
+          replicaProps.remove(ZkStateReader.SHARD_ID_PROP);
+          replicaProps.remove(ZkStateReader.COLLECTION_PROP);
           replicaProps.remove(QUEUE_OPERATION);
           
           // remove any props with null values
@@ -335,12 +342,11 @@
           for (String removeKey : removeKeys) {
             replicaProps.remove(removeKey);
           }
-          replicaProps.remove(ZkStateReader.CORE_NODE_NAME_PROP);
+          
           // remove shard specific properties
           String shardRange = (String) replicaProps.remove(ZkStateReader.SHARD_RANGE_PROP);
           String shardState = (String) replicaProps.remove(ZkStateReader.SHARD_STATE_PROP);
 
-
           Replica replica = new Replica(coreNodeName, replicaProps);
 
          // TODO: where do we get slice properties in this message?  or should there be a separate create-slice message if we want that?
@@ -353,9 +359,6 @@
             replicas = slice.getReplicasCopy();
           } else {
             replicas = new HashMap<String, Replica>(1);
-            sliceProps = new HashMap<String, Object>();
-            sliceProps.put(Slice.RANGE, shardRange);
-            sliceProps.put(Slice.STATE, shardState);
           }
 
           replicas.put(replica.getName(), replica);
@@ -417,6 +420,26 @@
         return null;
       }
       
+      private String getAssignedCoreNodeName(ClusterState state, ZkNodeProps message) {
+        Collection<Slice> slices = state.getSlices(message.getStr(ZkStateReader.COLLECTION_PROP));
+        if (slices != null) {
+          for (Slice slice : slices) {
+            for (Replica replica : slice.getReplicas()) {
+              String baseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+              String core = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+              
+              String msgBaseUrl = message.getStr(ZkStateReader.BASE_URL_PROP);
+              String msgCore = message.getStr(ZkStateReader.CORE_NAME_PROP);
+              
+              if (baseUrl.equals(msgBaseUrl) && core.equals(msgCore)) {
+                return replica.getName();
+              }
+            }
+          }
+        }
+        return null;
+      }
+      
       private ClusterState updateSlice(ClusterState state, String collectionName, Slice slice) {
         // System.out.println("###!!!### OLD CLUSTERSTATE: " + JSONUtil.toJSON(state.getCollectionStates()));
         // System.out.println("Updating slice:" + slice);
@@ -526,10 +549,6 @@
       private ClusterState removeCore(final ClusterState clusterState, ZkNodeProps message) {
         
         String cnn = message.getStr(ZkStateReader.CORE_NODE_NAME_PROP);
-        if (cnn == null) {
-          // it must be the default then
-          cnn = message.getStr(ZkStateReader.NODE_NAME_PROP) + "_" + message.getStr(ZkStateReader.CORE_NAME_PROP);
-        }
 
         final String collection = message.getStr(ZkStateReader.COLLECTION_PROP);
 
Index: solr/core/src/java/org/apache/solr/cloud/ElectionContext.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/ElectionContext.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/cloud/ElectionContext.java	(working copy)
@@ -47,9 +47,9 @@
   String leaderSeqPath;
   private SolrZkClient zkClient;
   
-  public ElectionContext(final String shardZkNodeName,
+  public ElectionContext(final String coreNodeName,
       final String electionPath, final String leaderPath, final ZkNodeProps leaderProps, final SolrZkClient zkClient) {
-    this.id = shardZkNodeName;
+    this.id = coreNodeName;
     this.electionPath = electionPath;
     this.leaderPath = leaderPath;
     this.leaderProps = leaderProps;
@@ -78,8 +78,8 @@
   protected LeaderElector leaderElector;
 
   public ShardLeaderElectionContextBase(LeaderElector leaderElector, final String shardId,
-      final String collection, final String shardZkNodeName, ZkNodeProps props, ZkStateReader zkStateReader) {
-    super(shardZkNodeName, ZkStateReader.COLLECTIONS_ZKNODE + "/" + collection + "/leader_elect/"
+      final String collection, final String coreNodeName, ZkNodeProps props, ZkStateReader zkStateReader) {
+    super(coreNodeName, ZkStateReader.COLLECTIONS_ZKNODE + "/" + collection + "/leader_elect/"
         + shardId, ZkStateReader.getShardLeadersPath(collection, shardId),
         props, zkStateReader.getZkClient());
     this.leaderElector = leaderElector;
@@ -95,7 +95,7 @@
     zkClient.makePath(leaderPath, ZkStateReader.toJSON(leaderProps),
         CreateMode.EPHEMERAL, true);
     assert shardId != null;
-    ZkNodeProps m = ZkNodeProps.fromKeyVals(Overseer.QUEUE_OPERATION, "leader",
+    ZkNodeProps m = ZkNodeProps.fromKeyVals(Overseer.QUEUE_OPERATION, ZkStateReader.LEADER_PROP,
         ZkStateReader.SHARD_ID_PROP, shardId, ZkStateReader.COLLECTION_PROP,
         collection, ZkStateReader.BASE_URL_PROP, leaderProps.getProperties()
             .get(ZkStateReader.BASE_URL_PROP), ZkStateReader.CORE_NAME_PROP,
@@ -119,8 +119,8 @@
   
   public ShardLeaderElectionContext(LeaderElector leaderElector, 
       final String shardId, final String collection,
-      final String shardZkNodeName, ZkNodeProps props, ZkController zkController, CoreContainer cc) {
-    super(leaderElector, shardId, collection, shardZkNodeName, props,
+      final String coreNodeName, ZkNodeProps props, ZkController zkController, CoreContainer cc) {
+    super(leaderElector, shardId, collection, coreNodeName, props,
         zkController.getZkStateReader());
     this.zkController = zkController;
     this.cc = cc;
@@ -138,12 +138,12 @@
   @Override
   void runLeaderProcess(boolean weAreReplacement) throws KeeperException,
       InterruptedException, IOException {
-    log.info("Running the leader process.");
+    log.info("Running the leader process for shard " + shardId);
     
     String coreName = leaderProps.getStr(ZkStateReader.CORE_NAME_PROP);
     
     // clear the leader in clusterstate
-    ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, "leader",
+    ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, ZkStateReader.LEADER_PROP,
         ZkStateReader.SHARD_ID_PROP, shardId, ZkStateReader.COLLECTION_PROP,
         collection);
     Overseer.getInQueue(zkClient).offer(ZkStateReader.toJSON(m));
@@ -243,8 +243,8 @@
       }
 
       log.info("I am the new leader: "
-          + ZkCoreNodeProps.getCoreUrl(leaderProps));
-      core.getCoreDescriptor().getCloudDescriptor().isLeader = true;
+          + ZkCoreNodeProps.getCoreUrl(leaderProps) + " " + shardId);
+      core.getCoreDescriptor().getCloudDescriptor().setLeader(true);
     } finally {
       if (core != null) {
         core.close();
@@ -254,16 +254,17 @@
     try {
       super.runLeaderProcess(weAreReplacement);
     } catch (Throwable t) {
+      SolrException.log(log, "There was a problem trying to register as the leader", t);
+      cancelElection();
       try {
         core = cc.getCore(coreName);
         if (core == null) {
-          cancelElection();
           throw new SolrException(ErrorCode.SERVER_ERROR,
               "Fatal Error, SolrCore not found:" + coreName + " in "
                   + cc.getCoreNames());
         }
         
-        core.getCoreDescriptor().getCloudDescriptor().isLeader = false;
+        core.getCoreDescriptor().getCloudDescriptor().setLeader(false);
         
         // we could not publish ourselves as leader - rejoin election
         rejoinLeaderElection(leaderSeqPath, core);
@@ -332,7 +333,7 @@
           return;
         } else {
           if (cnt % 40 == 0) {
-            log.info("Waiting until we see more replicas up: total="
+            log.info("Waiting until we see more replicas up for shard " + shardId + ": total="
               + slices.getReplicasMap().size() + " found=" + found
               + " timeoutin=" + (timeoutAt - System.currentTimeMillis()));
           }
Index: solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java	(working copy)
@@ -366,6 +366,8 @@
               params.set(CoreAdminParams.ACTION, CoreAdminAction.UNLOAD.toString());
               params.set(CoreAdminParams.CORE, core);
               params.set(CoreAdminParams.DELETE_INDEX, "true");
+              params.set(CoreAdminParams.DELETE_DATA_DIR, "true");
+              params.set(CoreAdminParams.DELETE_INSTANCE_DIR, "true");
               sendShardRequest(replica.getNodeName(), params);
             }
           }
@@ -398,12 +400,13 @@
 
         sendShardRequest(nodeName, params);
 
+        String coreNodeName = waitForCoreNodeName(collection.getName(), zkStateReader.getZkClient().getBaseUrlForNodeName(nodeName), subShardName);
         // wait for parent leader to acknowledge the sub-shard core
         log.info("Asking parent leader to wait for: " + subShardName + " to be alive on: " + nodeName);
         CoreAdminRequest.WaitForState cmd = new CoreAdminRequest.WaitForState();
         cmd.setCoreName(subShardName);
         cmd.setNodeName(nodeName);
-        cmd.setCoreNodeName(nodeName + "_" + subShardName);
+        cmd.setCoreNodeName(coreNodeName);
         cmd.setState(ZkStateReader.ACTIVE);
         cmd.setCheckLive(true);
         cmd.setOnlyIfLeader(true);
@@ -506,12 +509,13 @@
 
           sendShardRequest(subShardNodeName, params);
 
+          String coreNodeName = waitForCoreNodeName(collection.getName(), zkStateReader.getZkClient().getBaseUrlForNodeName(subShardNodeName), shardName);
           // wait for the replicas to be seen as active on sub shard leader
           log.info("Asking sub shard leader to wait for: " + shardName + " to be alive on: " + subShardNodeName);
           CoreAdminRequest.WaitForState cmd = new CoreAdminRequest.WaitForState();
           cmd.setCoreName(subShardNames.get(i-1));
           cmd.setNodeName(subShardNodeName);
-          cmd.setCoreNodeName(subShardNodeName + "_" + shardName);
+          cmd.setCoreNodeName(coreNodeName);
           cmd.setState(ZkStateReader.ACTIVE);
           cmd.setCheckLive(true);
           cmd.setOnlyIfLeader(true);
@@ -545,6 +549,35 @@
       throw new SolrException(ErrorCode.SERVER_ERROR, null, e);
     }
   }
+  
+  private String waitForCoreNodeName(String collection, String baseUrl, String coreName) {
+    int retryCount = 320;
+    while (retryCount-- > 0) {
+      Map<String,Slice> slicesMap = zkStateReader.getClusterState()
+          .getSlicesMap(collection);
+      if (slicesMap != null) {
+        
+        for (Slice slice : slicesMap.values()) {
+          for (Replica replica : slice.getReplicas()) {
+            // TODO: for really large clusters, we could 'index' on this
+            
+            String replicaBaseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+            String replicaCoreName = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+            
+            if (replicaBaseUrl.equals(baseUrl) && replicaCoreName.equals(coreName)) {
+              return replica.getName();
+            }
+          }
+        }
+      }
+      try {
+        Thread.sleep(1000);
+      } catch (InterruptedException e) {
+        Thread.currentThread().interrupt();
+      }
+    }
+    throw new SolrException(ErrorCode.SERVER_ERROR, "Could not find coreNodeName");
+  }
 
   private void collectShardResponses(NamedList results, boolean abortOnError, String msgOnError) {
     ShardResponse srsp;
Index: solr/core/src/java/org/apache/solr/cloud/RecoveryStrategy.java
===================================================================
--- solr/core/src/java/org/apache/solr/cloud/RecoveryStrategy.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/cloud/RecoveryStrategy.java	(working copy)
@@ -91,7 +91,7 @@
     zkController = cc.getZkController();
     zkStateReader = zkController.getZkStateReader();
     baseUrl = zkController.getBaseUrl();
-    coreZkNodeName = zkController.getCoreNodeName(cd);
+    coreZkNodeName = cd.getCloudDescriptor().getCoreNodeName();
   }
 
   public void setRecoveringAfterStartup(boolean recoveringAfterStartup) {
@@ -329,10 +329,10 @@
         String ourUrl = ZkCoreNodeProps.getCoreUrl(baseUrl, coreName);
 
         boolean isLeader = leaderUrl.equals(ourUrl);
-        if (isLeader && !cloudDesc.isLeader) {
+        if (isLeader && !cloudDesc.isLeader()) {
           throw new SolrException(ErrorCode.SERVER_ERROR, "Cloud state still says we are leader.");
         }
-        if (cloudDesc.isLeader) {
+        if (cloudDesc.isLeader()) {
           // we are now the leader - no one else must have been suitable
           log.warn("We have not yet recovered - but we are now the leader! core=" + coreName);
           log.info("Finished recovery process. core=" + coreName);
Index: solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
===================================================================
--- solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java	(working copy)
@@ -222,9 +222,9 @@
         // Replica leader = slice.getLeader();
         Replica leaderReplica = zkController.getZkStateReader().getLeaderRetry(
             collection, shardId);
-        ZkCoreNodeProps leaderProps = new ZkCoreNodeProps(leaderReplica);
-        String coreNodeName = zkController.getCoreNodeName(req.getCore().getCoreDescriptor());
-        isLeader = coreNodeName.equals(leaderReplica.getName());
+        isLeader = leaderReplica.getName().equals(
+            req.getCore().getCoreDescriptor().getCloudDescriptor()
+                .getCoreNodeName());
 
         DistribPhase phase =
             DistribPhase.parseParam(req.getParams().get(DISTRIB_UPDATE_PARAM));
@@ -240,7 +240,7 @@
           // so get the replicas...
           forwardToLeader = false;
           List<ZkCoreNodeProps> replicaProps = zkController.getZkStateReader()
-              .getReplicaProps(collection, shardId, coreNodeName,
+              .getReplicaProps(collection, shardId, leaderReplica.getName(),
                   coreName, null, ZkStateReader.DOWN);
 
           nodes = addSubShardLeaders(coll, shardId, id, doc, nodes);
@@ -273,7 +273,7 @@
         } else {
           // I need to forward onto the leader...
           nodes = new ArrayList<Node>(1);
-          nodes.add(new RetryNode(leaderProps, zkController.getZkStateReader(), collection, shardId));
+          nodes.add(new RetryNode(new ZkCoreNodeProps(leaderReplica), zkController.getZkStateReader(), collection, shardId));
           forwardToLeader = true;
         }
 
@@ -335,15 +335,17 @@
           throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE,
               "Request says it is coming from parent shard leader but parent hash range is not superset of my range");
         }
-      } else {
+      } else  {
         log.error("Request says it is coming from leader, but we are the leader: " + req.getParamString());
         throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "Request says it is coming from leader, but we are the leader");
       }
     }
-
+    
     if (isLeader && !localIsLeader) {
       log.error("ClusterState says we are the leader, but locally we don't think so");
-      throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "ClusterState says we are the leader, but locally we don't think so");
+      throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE,
+          "ClusterState says we are the leader (" + zkController.getBaseUrl()
+              + "/" + req.getCore().getName() + "), but locally we don't think so. Request came from " + from);
     }
   }
 
@@ -358,7 +360,7 @@
           collection, shardId);
       String leaderCoreNodeName = leaderReplica.getName();
 
-      String coreNodeName = zkController.getCoreNodeName(req.getCore().getCoreDescriptor());
+      String coreNodeName = req.getCore().getCoreDescriptor().getCloudDescriptor().getCoreNodeName();
       isLeader = coreNodeName.equals(leaderCoreNodeName);
 
       // TODO: what if we are no longer the leader?
@@ -869,7 +871,7 @@
         // Am I the leader for this slice?
         ZkCoreNodeProps coreLeaderProps = new ZkCoreNodeProps(leader);
         String leaderCoreNodeName = leader.getName();
-        String coreNodeName = zkController.getCoreNodeName(req.getCore().getCoreDescriptor());
+        String coreNodeName = req.getCore().getCoreDescriptor().getCloudDescriptor().getCoreNodeName();
         isLeader = coreNodeName.equals(leaderCoreNodeName);
 
         if (isLeader) {
@@ -1129,7 +1131,7 @@
       if (!req.getParams().getBool(COMMIT_END_POINT, false)) {
         params.set(COMMIT_END_POINT, true);
 
-        String coreNodeName = zkController.getCoreNodeName(req.getCore().getCoreDescriptor());
+        String coreNodeName = req.getCore().getCoreDescriptor().getCloudDescriptor().getCoreNodeName();
         List<Node> nodes = getCollectionUrls(req, req.getCore().getCoreDescriptor()
             .getCloudDescriptor().getCollectionName(), coreNodeName);
 
Index: solr/core/src/java/org/apache/solr/util/SolrLogLayout.java
===================================================================
--- solr/core/src/java/org/apache/solr/util/SolrLogLayout.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/util/SolrLogLayout.java	(working copy)
@@ -229,7 +229,7 @@
 
   private Map<String,Object> getReplicaProps(ZkController zkController, SolrCore core) {
     final String collection = core.getCoreDescriptor().getCloudDescriptor().getCollectionName();
-    Replica replica = zkController.getClusterState().getReplica(collection, zkController.getCoreNodeName(core.getCoreDescriptor()));
+    Replica replica = zkController.getClusterState().getReplica(collection, core.getCoreDescriptor().getCloudDescriptor().getCoreNodeName());
     if(replica!=null) {
       return replica.getProperties();
     }
Index: solr/core/src/java/org/apache/solr/SolrLogFormatter.java
===================================================================
--- solr/core/src/java/org/apache/solr/SolrLogFormatter.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/SolrLogFormatter.java	(working copy)
@@ -17,21 +17,25 @@
  * limitations under the License.
  */
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.Replica;
-import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestInfo;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.logging.*;
-
 public class SolrLogFormatter extends Formatter {
 
   /** Add this interface to a thread group and the string returned by
@@ -259,7 +263,7 @@
 
   private Map<String,Object> getReplicaProps(ZkController zkController, SolrCore core) {
     final String collection = core.getCoreDescriptor().getCloudDescriptor().getCollectionName();
-    Replica replica = zkController.getClusterState().getReplica(collection, zkController.getCoreNodeName(core.getCoreDescriptor()));
+    Replica replica = zkController.getClusterState().getReplica(collection, core.getCoreDescriptor().getCloudDescriptor().getCoreNodeName());
     if(replica!=null) {
       return replica.getProperties();
     }
Index: solr/core/src/java/org/apache/solr/core/CoreContainer.java
===================================================================
--- solr/core/src/java/org/apache/solr/core/CoreContainer.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/core/CoreContainer.java	(working copy)
@@ -179,9 +179,6 @@
       log.info("looking for solr config file: " + fconf.getAbsolutePath());
       cores = new CoreContainer(solrHome);
 
-      // first we find zkhost, then we check for solr.xml in zk
-      // 1. look for zkhost from sys prop 2. look for zkhost in {solr.home}/solr.properties
-      
       // Either we have a config file or not.
       
       if (fconf.exists()) {
@@ -310,6 +307,8 @@
     
     String leaderVoteWait = cfg.get(ConfigSolr.CfgProp.SOLR_LEADERVOTEWAIT, LEADER_VOTE_WAIT);
 
+    Boolean genericCoreNodeNames = cfg.getBool(ConfigSolr.CfgProp.SOLR_GENERICCORENODENAMES, false);
+
     adminHandler = cfg.get(ConfigSolr.CfgProp.SOLR_ADMINHANDLER, null);
     managementPath = cfg.get(ConfigSolr.CfgProp.SOLR_MANAGEMENTPATH, null);
 
@@ -321,7 +320,7 @@
 
     zkClientTimeout = Integer.parseInt(System.getProperty("zkClientTimeout",
         Integer.toString(zkClientTimeout)));
-    zkSys.initZooKeeper(this, solrHome, zkHost, zkClientTimeout, hostPort, hostContext, host, leaderVoteWait, distribUpdateConnTimeout, distribUpdateSoTimeout);
+    zkSys.initZooKeeper(this, solrHome, zkHost, zkClientTimeout, hostPort, hostContext, host, leaderVoteWait, genericCoreNodeNames, distribUpdateConnTimeout, distribUpdateSoTimeout);
     
     if (isZooKeeperAware() && coreLoadThreads <= 1) {
       throw new SolrException(ErrorCode.SERVER_ERROR,
@@ -1123,6 +1122,8 @@
         zkSys.getHostContext(), null);
     addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_LEADERVOTEWAIT, "leaderVoteWait",
         zkSys.getLeaderVoteWait(), LEADER_VOTE_WAIT);
+    addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_GENERICCORENODENAMES, "genericCoreNodeNames",
+        Boolean.toString(zkSys.getGenericCoreNodeNames()), "true");
     addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_CORELOADTHREADS, "coreLoadThreads",
         Integer.toString(this.coreLoadThreads), Integer.toString(CORE_LOAD_THREADS));
     if (transientCacheSize != Integer.MAX_VALUE) { // This test
Index: solr/core/src/java/org/apache/solr/core/ConfigSolr.java
===================================================================
--- solr/core/src/java/org/apache/solr/core/ConfigSolr.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/core/ConfigSolr.java	(working copy)
@@ -65,6 +65,7 @@
     SOLR_TRANSIENTCACHESIZE,
     SOLR_ZKCLIENTTIMEOUT,
     SOLR_ZKHOST,
+    SOLR_GENERICCORENODENAMES,
 
     //TODO: Remove all of these elements for 5.0
     SOLR_PERSISTENT,
Index: solr/core/src/java/org/apache/solr/core/ZkContainer.java
===================================================================
--- solr/core/src/java/org/apache/solr/core/ZkContainer.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/core/ZkContainer.java	(working copy)
@@ -50,8 +50,16 @@
   private String hostContext;
   private String host;
   private String leaderVoteWait;
+  private Boolean genericCoreNodeNames;
   private int distribUpdateConnTimeout;
+  private int distribUpdateSoTimeout;
+
 
+  
+  public ZkContainer() {
+    
+  }
+  
   public SolrZkServer getZkServer() {
     return zkServer;
   }
@@ -76,6 +84,10 @@
     return leaderVoteWait;
   }
 
+  public Boolean getGenericCoreNodeNames() {
+    return genericCoreNodeNames;
+  }
+  
   public int getDistribUpdateConnTimeout() {
     return distribUpdateConnTimeout;
   }
@@ -83,14 +95,8 @@
   public int getDistribUpdateSoTimeout() {
     return distribUpdateSoTimeout;
   }
-
-  private int distribUpdateSoTimeout;
   
-  public ZkContainer() {
-    
-  }
-  
-  public void initZooKeeper(final CoreContainer cc, String solrHome, String zkHost, int zkClientTimeout, String hostPort, String hostContext, String host, String leaderVoteWait, int distribUpdateConnTimeout, int distribUpdateSoTimeout) {
+  public void initZooKeeper(final CoreContainer cc, String solrHome, String zkHost, int zkClientTimeout, String hostPort, String hostContext, String host, String leaderVoteWait, Boolean genericCoreNodeNames, int distribUpdateConnTimeout, int distribUpdateSoTimeout) {
     ZkController zkController = null;
     
     // if zkHost sys property is not set, we are not using ZooKeeper
@@ -108,6 +114,7 @@
     this.hostContext = hostContext;
     this.host = host;
     this.leaderVoteWait = leaderVoteWait;
+    this.genericCoreNodeNames = genericCoreNodeNames;
     this.distribUpdateConnTimeout = distribUpdateConnTimeout;
     this.distribUpdateSoTimeout = distribUpdateSoTimeout;
     
@@ -163,7 +170,7 @@
         }
         zkController = new ZkController(cc, zookeeperHost, zkClientTimeout,
             zkClientConnectTimeout, host, hostPort, hostContext,
-            leaderVoteWait, distribUpdateConnTimeout, distribUpdateSoTimeout,
+            leaderVoteWait, genericCoreNodeNames, distribUpdateConnTimeout, distribUpdateSoTimeout,
             new CurrentCoreDescriptorProvider() {
 
               @Override
Index: solr/core/src/java/org/apache/solr/core/ConfigSolrXmlOld.java
===================================================================
--- solr/core/src/java/org/apache/solr/core/ConfigSolrXmlOld.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/core/ConfigSolrXmlOld.java	(working copy)
@@ -125,6 +125,8 @@
         config.getVal("solr/cores/@hostPort", false));
     propMap.put(CfgProp.SOLR_LEADERVOTEWAIT,
         config.getVal("solr/cores/@leaderVoteWait", false));
+    propMap.put(CfgProp.SOLR_GENERICCORENODENAMES,
+        config.getVal("solr/cores/@genericCoreNodeNames", false));
     propMap.put(CfgProp.SOLR_MANAGEMENTPATH,
         config.getVal("solr/cores/@managementPath", false));
     propMap.put(CfgProp.SOLR_SHARESCHEMA,
Index: solr/core/src/java/org/apache/solr/core/ConfigSolrXml.java
===================================================================
--- solr/core/src/java/org/apache/solr/core/ConfigSolrXml.java	(revision 1485406)
+++ solr/core/src/java/org/apache/solr/core/ConfigSolrXml.java	(working copy)
@@ -118,6 +118,7 @@
     propMap.put(CfgProp.SOLR_HOSTCONTEXT, doSub("solr/solrcloud/str[@name='hostContext']"));
     propMap.put(CfgProp.SOLR_HOSTPORT, doSub("solr/solrcloud/int[@name='hostPort']"));
     propMap.put(CfgProp.SOLR_LEADERVOTEWAIT, doSub("solr/solrcloud/int[@name='leaderVoteWait']"));
+    propMap.put(CfgProp.SOLR_GENERICCORENODENAMES, doSub("solr/solrcloud/int[@name='genericCoreNodeNames']"));
     propMap.put(CfgProp.SOLR_MANAGEMENTPATH, doSub("solr/str[@name='managementPath']"));
     propMap.put(CfgProp.SOLR_SHAREDLIB, doSub("solr/str[@name='sharedLib']"));
     propMap.put(CfgProp.SOLR_SHARESCHEMA, doSub("solr/str[@name='shareSchema']"));
Index: solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java
===================================================================
--- solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java	(revision 1485406)
+++ solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java	(working copy)
@@ -71,11 +71,13 @@
   @BeforeClass
   public static void beforeClass() {
     System.setProperty("solrcloud.skip.autorecovery", "true");
+    System.setProperty("genericCoreNodeNames", "false");
   }
   
   @AfterClass
   public static void afterClass() throws InterruptedException {
     System.clearProperty("solrcloud.skip.autorecovery");
+    System.clearProperty("genericCoreNodeNames");
   }
 
   @Override
Index: solr/core/src/test/org/apache/solr/cloud/AssignTest.java
===================================================================
--- solr/core/src/test/org/apache/solr/cloud/AssignTest.java	(revision 0)
+++ solr/core/src/test/org/apache/solr/cloud/AssignTest.java	(working copy)
@@ -0,0 +1,95 @@
+package org.apache.solr.cloud;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.DocRouter;
+import org.apache.solr.common.cloud.ImplicitDocRouter;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.ZkNodeProps;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AssignTest extends SolrTestCaseJ4 {
+  protected static Logger log = LoggerFactory.getLogger(AssignTest.class);
+
+  
+  @Override
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+
+  }
+  
+  @Override
+  @After
+  public void tearDown() throws Exception {
+    super.tearDown();
+  }
+  
+  @Test
+  public void testAssignNode() throws Exception {
+    String cname = "collection1";
+    
+    Map<String,DocCollection> collectionStates = new HashMap<String,DocCollection>();
+    
+    Map<String,Slice> slices = new HashMap<String,Slice>();
+    
+    Map<String,Replica> replicas = new HashMap<String,Replica>();
+    
+    ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, "state", 
+        ZkStateReader.STATE_PROP, "ACTIVE", 
+        ZkStateReader.BASE_URL_PROP, "0.0.0.0", 
+        ZkStateReader.CORE_NAME_PROP, "core1",
+        ZkStateReader.ROLES_PROP, null,
+        ZkStateReader.NODE_NAME_PROP, "0_0_0_0",
+        ZkStateReader.SHARD_ID_PROP, "shard1",
+        ZkStateReader.COLLECTION_PROP, cname,
+        ZkStateReader.NUM_SHARDS_PROP, "1",
+        ZkStateReader.CORE_NODE_NAME_PROP, "node1");
+    Replica replica = new Replica("core_node1" , m.getProperties());
+    replicas.put("core_node1", replica);
+    
+    Slice slice = new Slice("slice1", replicas , new HashMap<String,Object>(0));
+    slices.put("slice1", slice);
+    
+    DocRouter router = new ImplicitDocRouter();
+    DocCollection docCollection = new DocCollection(cname, slices, new HashMap<String,Object>(0), router);
+
+    collectionStates.put(cname, docCollection);
+    
+    Set<String> liveNodes = new HashSet<String>();
+    ClusterState state = new ClusterState(liveNodes, collectionStates);
+    String nodeName = Assign.assignNode("collection1", state);
+    
+    assertEquals("core_node2", nodeName);
+  }
+  
+}
Index: solr/core/src/test/org/apache/solr/cloud/AssignTest.java
===================================================================
--- solr/core/src/test/org/apache/solr/cloud/AssignTest.java	(revision 0)
+++ solr/core/src/test/org/apache/solr/cloud/AssignTest.java	(working copy)

Property changes on: solr/core/src/test/org/apache/solr/cloud/AssignTest.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
===================================================================
--- solr/core/src/test/org/apache/solr/cloud/OverseerTest.java	(revision 1485406)
+++ solr/core/src/test/org/apache/solr/cloud/OverseerTest.java	(working copy)
@@ -36,6 +36,7 @@
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkNodeProps;
@@ -98,7 +99,7 @@
       zkClient.close();
     }
     
-    public String publishState(String coreName, String stateName, int numShards)
+    public String publishState(String coreName, String coreNodeName, String stateName, int numShards)
         throws KeeperException, InterruptedException, IOException {
       if (stateName == null) {
         ElectionContext ec = electionContext.remove(coreName);
@@ -108,6 +109,7 @@
         ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, "deletecore",
             ZkStateReader.NODE_NAME_PROP, nodeName,
             ZkStateReader.CORE_NAME_PROP, coreName,
+            ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName,
             ZkStateReader.COLLECTION_PROP, collection);
             DistributedQueue q = Overseer.getInQueue(zkClient);
             q.offer(ZkStateReader.toJSON(m));
@@ -117,6 +119,7 @@
         ZkStateReader.STATE_PROP, stateName,
         ZkStateReader.NODE_NAME_PROP, nodeName,
         ZkStateReader.CORE_NAME_PROP, coreName,
+        ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName,
         ZkStateReader.COLLECTION_PROP, collection,
         ZkStateReader.NUM_SHARDS_PROP, Integer.toString(numShards),
         ZkStateReader.BASE_URL_PROP, "http://" + nodeName
@@ -126,7 +129,8 @@
       }
       
       for (int i = 0; i < 120; i++) {
-        String shardId = getShardId(coreName);
+        String shardId = getShardId("http://" + nodeName
+            + "/solr/", coreName);
         if (shardId != null) {
           try {
             zkClient.makePath("/collections/" + collection + "/leader_elect/"
@@ -136,7 +140,8 @@
               "http://" + nodeName + "/solr/", ZkStateReader.NODE_NAME_PROP,
               nodeName, ZkStateReader.CORE_NAME_PROP, coreName,
               ZkStateReader.SHARD_ID_PROP, shardId,
-              ZkStateReader.COLLECTION_PROP, collection);
+              ZkStateReader.COLLECTION_PROP, collection,
+              ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName);
           ShardLeaderElectionContextBase ctx = new ShardLeaderElectionContextBase(
               elector, shardId, collection, nodeName + "_" + coreName, props,
               zkStateReader);
@@ -148,13 +153,18 @@
       return null;
     }
     
-    private String getShardId(final String coreName) {
+    private String getShardId(final String baseUrl, final String coreName) {
       Map<String,Slice> slices = zkStateReader.getClusterState().getSlicesMap(
           collection);
       if (slices != null) {
         for (Slice slice : slices.values()) {
-          if (slice.getReplicasMap().containsKey(nodeName + "_" + coreName)) {
-            return slice.getName();
+          for (Replica replica : slice.getReplicas()) {
+            // TODO: for really large clusters, we could 'index' on this
+            String rbaseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+            String rcore = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+            if (baseUrl.equals(rbaseUrl) && coreName.equals(rcore)) {
+              return slice.getName();
+            }
           }
         }
       }
@@ -202,7 +212,7 @@
       final int numShards=6;
       
       for (int i = 0; i < numShards; i++) {
-        assertNotNull("shard got no id?", zkController.publishState("core" + (i+1), ZkStateReader.ACTIVE, 3));
+        assertNotNull("shard got no id?", zkController.publishState("core" + (i+1), "node" + (i+1), ZkStateReader.ACTIVE, 3));
       }
 
       assertEquals(2, reader.getClusterState().getSlice("collection1", "shard1").getReplicasMap().size());
@@ -277,7 +287,7 @@
             final String coreName = "core" + slot;
             
             try {
-              ids[slot]=controllers[slot % nodeCount].publishState(coreName, ZkStateReader.ACTIVE, sliceCount);
+              ids[slot]=controllers[slot % nodeCount].publishState(coreName, "node" + slot, ZkStateReader.ACTIVE, sliceCount);
             } catch (Throwable e) {
               e.printStackTrace();
               fail("register threw exception:" + e.getClass());
@@ -440,7 +450,7 @@
 
       assertEquals(reader.getClusterState().toString(), ZkStateReader.RECOVERING,
           reader.getClusterState().getSlice("collection1", "shard1").getReplicasMap()
-              .get("node1_core1").getStr(ZkStateReader.STATE_PROP));
+              .get("core_node1").getStr(ZkStateReader.STATE_PROP));
 
       //publish node state (active)
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, "state",
@@ -471,7 +481,7 @@
     while(maxIterations-->0) {
       Slice slice = reader.getClusterState().getSlice("collection1", "shard1");
       if(slice!=null) {
-        coreState = slice.getReplicasMap().get("node1_core1").getStr(ZkStateReader.STATE_PROP);
+        coreState = slice.getReplicasMap().get("core_node1").getStr(ZkStateReader.STATE_PROP);
         if(coreState.equals(expectedState)) {
           return;
         }
@@ -523,14 +533,14 @@
       overseerClient = electNewOverseer(server.getZkAddress());
 
       Thread.sleep(1000);
-      mockController.publishState("core1", ZkStateReader.RECOVERING, 1);
+      mockController.publishState("core1", "core_node1", ZkStateReader.RECOVERING, 1);
 
       waitForCollections(reader, "collection1");
       verifyStatus(reader, ZkStateReader.RECOVERING);
 
       int version = getClusterStateVersion(controllerClient);
       
-      mockController.publishState("core1", ZkStateReader.ACTIVE, 1);
+      mockController.publishState("core1", "core_node1", ZkStateReader.ACTIVE, 1);
       
       while(version == getClusterStateVersion(controllerClient));
 
@@ -539,7 +549,7 @@
       overseerClient.close();
       Thread.sleep(1000); //wait for overseer to get killed
 
-      mockController.publishState("core1", ZkStateReader.RECOVERING, 1);
+      mockController.publishState("core1",  "core_node1", ZkStateReader.RECOVERING, 1);
       version = getClusterStateVersion(controllerClient);
       
       overseerClient = electNewOverseer(server.getZkAddress());
@@ -553,7 +563,7 @@
       assertEquals("Shard count does not match", 1, reader.getClusterState()
           .getSlice("collection1", "shard1").getReplicasMap().size());
       version = getClusterStateVersion(controllerClient);
-      mockController.publishState("core1", null,1);
+      mockController.publishState("core1", "core_node1", null,1);
       while(version == getClusterStateVersion(controllerClient));
       Thread.sleep(500);
       assertFalse("collection1 should be gone after publishing the null state", reader.getClusterState().getCollections().contains("collection1"));
@@ -641,16 +651,16 @@
       for (int i = 0; i < atLeast(4); i++) {
         killCounter.incrementAndGet(); //for each round allow 1 kill
         mockController = new MockZKController(server.getZkAddress(), "node1", "collection1");
-        mockController.publishState("core1", "state1",1);
+        mockController.publishState("core1", "core_node1", "state1",1);
         if(mockController2!=null) {
           mockController2.close();
           mockController2 = null;
         }
-        mockController.publishState("core1", "state2",1);
+        mockController.publishState("core1", "core_node1","state2",1);
         mockController2 = new MockZKController(server.getZkAddress(), "node2", "collection1");
-        mockController.publishState("core1", "state1",1);
+        mockController.publishState("core1", "core_node1", "state1",1);
         verifyShardLeader(reader, "collection1", "shard1", "core1");
-        mockController2.publishState("core4", "state2" ,1);
+        mockController2.publishState("core4", "core_node2", "state2" ,1);
         mockController.close();
         mockController = null;
         verifyShardLeader(reader, "collection1", "shard1", "core4");
@@ -697,7 +707,7 @@
       
       overseerClient = electNewOverseer(server.getZkAddress());
 
-      mockController.publishState("core1", ZkStateReader.RECOVERING, 1);
+      mockController.publishState("core1", "core_node1", ZkStateReader.RECOVERING, 1);
 
       waitForCollections(reader, "collection1");
       
@@ -708,7 +718,7 @@
       int version = getClusterStateVersion(controllerClient);
       
       mockController = new MockZKController(server.getZkAddress(), "node1", "collection1");
-      mockController.publishState("core1", ZkStateReader.RECOVERING, 1);
+      mockController.publishState("core1", "core_node1", ZkStateReader.RECOVERING, 1);
 
       while (version == getClusterStateVersion(controllerClient));
       
@@ -718,7 +728,7 @@
       int numFound = 0;
       for (DocCollection collection : state.getCollectionStates().values()) {
         for (Slice slice : collection.getSlices()) {
-          if (slice.getReplicasMap().get("node1_core1") != null) {
+          if (slice.getReplicasMap().get("core_node1") != null) {
             numFound++;
           }
         }
@@ -761,7 +771,7 @@
       
       overseerClient = electNewOverseer(server.getZkAddress());
 
-      mockController.publishState("core1", ZkStateReader.RECOVERING, 12);
+      mockController.publishState("core1", "core_node1", ZkStateReader.RECOVERING, 12);
 
       waitForCollections(reader, "collection1");
       
Index: solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java
===================================================================
--- solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java	(revision 1485406)
+++ solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java	(working copy)
@@ -163,7 +163,7 @@
       cc = getCoreContainer();
       
       ZkController zkController = new ZkController(cc, server.getZkAddress(), TIMEOUT, 10000,
-          "127.0.0.1", "8983", "solr", "0", 10000, 10000, new CurrentCoreDescriptorProvider() {
+          "127.0.0.1", "8983", "solr", "0", true, 10000, 10000, new CurrentCoreDescriptorProvider() {
             
             @Override
             public List<CoreDescriptor> getCurrentDescriptors() {
@@ -203,7 +203,7 @@
       cc = getCoreContainer();
       
       zkController = new ZkController(cc, server.getZkAddress(),
-          TIMEOUT, 10000, "127.0.0.1", "8983", "solr", "0", 10000, 10000, new CurrentCoreDescriptorProvider() {
+          TIMEOUT, 10000, "127.0.0.1", "8983", "solr", "0", true, 10000, 10000, new CurrentCoreDescriptorProvider() {
             
             @Override
             public List<CoreDescriptor> getCurrentDescriptors() {
Index: solr/example/solr/solr.xml
===================================================================
--- solr/example/solr/solr.xml	(revision 1485406)
+++ solr/example/solr/solr.xml	(working copy)
@@ -33,6 +33,7 @@
     <int name="hostPort">${jetty.port:8983}</int>
     <str name="hostContext">${hostContext:solr}</str>
     <int name="zkClientTimeout">${zkClientTimeout:15000}</int>
+    <bool nam="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
   </solrcloud>
 
   <shardHandlerFactory name="shardHandlerFactory"
Index: solr/test-framework/src/java/org/apache/solr/util/TestHarness.java
===================================================================
--- solr/test-framework/src/java/org/apache/solr/util/TestHarness.java	(revision 1485406)
+++ solr/test-framework/src/java/org/apache/solr/util/TestHarness.java	(working copy)
@@ -187,7 +187,7 @@
             String hostContext = System.getProperty("hostContext", "solr");
             defaultCoreName = CoreContainer.DEFAULT_DEFAULT_CORE_NAME;
             initShardHandler();
-            zkSys.initZooKeeper(this, solrHome, System.getProperty("zkHost"), 30000, hostPort, hostContext, null, "30000", 30000, 30000);
+            zkSys.initZooKeeper(this, solrHome, System.getProperty("zkHost"), 30000, hostPort, hostContext, null, "30000", true, 30000, 30000);
             ByteArrayInputStream is = new ByteArrayInputStream(ConfigSolrXmlOld.DEF_SOLR_XML.getBytes("UTF-8"));
             Config config = new Config(loader, null, new InputSource(is), null, false);
             cfg = new ConfigSolrXmlOld(config, this);
Index: solr/test-framework/src/java/org/apache/solr/cloud/AbstractDistribZkTestBase.java
===================================================================
--- solr/test-framework/src/java/org/apache/solr/cloud/AbstractDistribZkTestBase.java	(revision 1485406)
+++ solr/test-framework/src/java/org/apache/solr/cloud/AbstractDistribZkTestBase.java	(working copy)
@@ -151,8 +151,7 @@
           if (verbose) System.out.println("rstate:"
               + shard.getValue().getStr(ZkStateReader.STATE_PROP)
               + " live:"
-              + clusterState.liveNodesContain(shard.getValue().getStr(
-              ZkStateReader.NODE_NAME_PROP)));
+              + clusterState.liveNodesContain(shard.getValue().getNodeName()));
           String state = shard.getValue().getStr(ZkStateReader.STATE_PROP);
           if ((state.equals(ZkStateReader.RECOVERING) || state
               .equals(ZkStateReader.SYNC) || state.equals(ZkStateReader.DOWN))
Index: solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
===================================================================
--- solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java	(revision 1485406)
+++ solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java	(working copy)
@@ -197,6 +197,7 @@
   @AfterClass
   public static void afterClass() {
     System.clearProperty("solrcloud.update.delay");
+    System.clearProperty("genericCoreNodeNames");
   }
   
   public AbstractFullDistribZkTestBase() {
@@ -209,6 +210,9 @@
     stress = 0;
     
     useExplicitNodeNames = random().nextBoolean();
+    if (random().nextBoolean()) {
+      System.setProperty("genericCoreNodeNames", "false");
+    }
   }
   
   protected void initCloud() throws Exception {
@@ -483,7 +487,7 @@
             cjr.jetty = jetty;
             cjr.info = replica;
             cjr.nodeName = replica.getStr(ZkStateReader.NODE_NAME_PROP);
-            cjr.coreNodeName = replica.getName();
+            cjr.coreNodeName = replica.getNodeName();
             cjr.url = replica.getStr(ZkStateReader.BASE_URL_PROP) + "/" + replica.getStr(ZkStateReader.CORE_NAME_PROP);
             cjr.client = findClientByPort(port, theClients);
             list.add(cjr);
@@ -1464,7 +1468,7 @@
       for (String sliceName : slices.keySet()) {
         for (Replica replica : slices.get(sliceName).getReplicas()) {
           if (nodesAllowedToRunShards != null && !nodesAllowedToRunShards.contains(replica.getStr(ZkStateReader.NODE_NAME_PROP))) {
-            return "Shard " + replica.getName() + " created on node " + replica.getStr(ZkStateReader.NODE_NAME_PROP) + " not allowed to run shards for the created collection " + collectionName;
+            return "Shard " + replica.getName() + " created on node " + replica.getNodeName() + " not allowed to run shards for the created collection " + collectionName;
           }
         }
         totalShards += slices.get(sliceName).getReplicas().size();
Index: solr/solrj/src/test-files/solrj/solr/solr.xml
===================================================================
--- solr/solrj/src/test-files/solrj/solr/solr.xml	(revision 1485406)
+++ solr/solrj/src/test-files/solrj/solr/solr.xml	(working copy)
@@ -28,7 +28,8 @@
   adminPath: RequestHandler path to manage cores.  
     If 'null' (or absent), cores will not be manageable via request handler
   -->
-  <cores adminPath="/admin/cores" defaultCoreName="collection1" host="127.0.0.1" hostPort="${hostPort:8983}" hostContext="${hostContext:solr}" zkClientTimeout="8000" numShards="${numShards:3}">
+  <cores adminPath="/admin/cores" defaultCoreName="collection1" host="127.0.0.1" hostPort="${hostPort:8983}" hostContext="${hostContext:solr}"
+        zkClientTimeout="8000" genericCoreNodeNames="${genericCoreNodeNames:true}">
     <core name="collection1" instanceDir="collection1" shard="${shard:}" collection="${collection:collection1}" config="${solrconfig:solrconfig.xml}" schema="${schema:schema.xml}"/>
   </cores>
 </solr>
Index: solr/solrj/src/test-files/solrj/solr/shared/solr.xml
===================================================================
--- solr/solrj/src/test-files/solrj/solr/shared/solr.xml	(revision 1485406)
+++ solr/solrj/src/test-files/solrj/solr/shared/solr.xml	(working copy)
@@ -30,7 +30,7 @@
   adminPath: RequestHandler path to manage cores.  
     If 'null' (or absent), cores will not be manageable via REST
   -->
-  <cores adminPath="/admin/cores" defaultCoreName="core0" host="127.0.0.1" hostPort="${hostPort:8983}" hostContext="${hostContext:solr}" zkClientTimeout="8000">
+  <cores adminPath="/admin/cores" defaultCoreName="core0" host="127.0.0.1" hostPort="${hostPort:8983}" hostContext="${hostContext:solr}" zkClientTimeout="8000" genericCoreNodeNames="${genericCoreNodeNames:true}">
     <core name="collection1" instanceDir="." />
     <core name="core0" instanceDir="${theInstanceDir:./}" dataDir="${dataDir1}" collection="${collection:acollection}">
       <property name="version" value="3.5"/>
Index: solr/solrj/src/java/org/apache/solr/common/cloud/ClusterState.java
===================================================================
--- solr/solrj/src/java/org/apache/solr/common/cloud/ClusterState.java	(revision 1485406)
+++ solr/solrj/src/java/org/apache/solr/common/cloud/ClusterState.java	(working copy)
@@ -165,15 +165,18 @@
     return Collections.unmodifiableSet(liveNodes);
   }
 
-  /**
-   * Get the slice/shardId for a core.
-   * @param coreNodeName in the form of nodeName_coreName (the name of the replica)
-   */
-  public String getShardId(String coreNodeName) {
-    //  System.out.println("###### getShardId("+coreNodeName+") in " + collectionStates);
+  public String getShardId(String baseUrl, String coreName) {
+    // System.out.println("###### getShardId(" + baseUrl + "," + coreName + ") in " + collectionStates);
     for (DocCollection coll : collectionStates.values()) {
       for (Slice slice : coll.getSlices()) {
-        if (slice.getReplicasMap().containsKey(coreNodeName)) return slice.getName();
+        for (Replica replica : slice.getReplicas()) {
+          // TODO: for really large clusters, we could 'index' on this
+          String rbaseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+          String rcore = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+          if (baseUrl.equals(rbaseUrl) && coreName.equals(rcore)) {
+            return slice.getName();
+          }
+        }
       }
     }
     return null;
Index: solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
===================================================================
--- solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java	(revision 1485406)
+++ solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java	(working copy)
@@ -508,6 +508,7 @@
   
   public List<ZkCoreNodeProps> getReplicaProps(String collection,
       String shardId, String thisCoreNodeName, String coreName, String mustMatchStateFilter, String mustNotMatchStateFilter) {
+    assert thisCoreNodeName != null;
     ClusterState clusterState = this.clusterState;
     if (clusterState == null) {
       return null;
@@ -540,7 +541,7 @@
       }
     }
     if (nodes.size() == 0) {
-      // no replicas - go local
+      // no replicas
       return null;
     }
 
Index: solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java
===================================================================
--- solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java	(revision 1485406)
+++ solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java	(working copy)
@@ -196,6 +196,8 @@
                  exists("/solr/cores[@zkClientTimeout='8000']", document));
       assertTrue("\"/solr/cores[@hostContext='${hostContext:solr}']\" doesn't match in:\n" + solrPersistXml,
                  exists("/solr/cores[@hostContext='${hostContext:solr}']", document));
+      assertTrue("\"/solr/cores[@genericCoreNodeNames='${genericCoreNodeNames:true}']\" doesn't match in:\n" + solrPersistXml,
+          exists("/solr/cores[@genericCoreNodeNames='${genericCoreNodeNames:true}']", document));
       
     } finally {
       fis.close();

