@Override
 public synchronized int registerTextEditorHighlightingPass(
     @NotNull TextEditorHighlightingPassFactory factory,
     @Nullable int[] runAfterCompletionOf,
     @Nullable int[] runAfterOfStartingOf,
     boolean runIntentionsPassAfter,
     int forcedPassId) {
   assert !checkedForCycles;
   PassConfig info =
       new PassConfig(
           factory,
           runAfterCompletionOf == null || runAfterCompletionOf.length == 0
               ? ArrayUtil.EMPTY_INT_ARRAY
               : runAfterCompletionOf,
           runAfterOfStartingOf == null || runAfterOfStartingOf.length == 0
               ? ArrayUtil.EMPTY_INT_ARRAY
               : runAfterOfStartingOf);
   int passId = forcedPassId == -1 ? nextAvailableId++ : forcedPassId;
   PassConfig registered = myRegisteredPassFactories.get(passId);
   assert registered == null
       : "Pass id " + passId + " has already been registered in: " + registered.passFactory;
   myRegisteredPassFactories.put(passId, info);
   if (factory instanceof DirtyScopeTrackingHighlightingPassFactory) {
     myDirtyScopeTrackingFactories.add((DirtyScopeTrackingHighlightingPassFactory) factory);
   }
   return passId;
 }
    public void merge(final Binding b, final boolean removeObject) {
      for (final PsiTypeVariable var : b.getBoundVariables()) {
        final int index = var.getIndex();

        if (myBindings.get(index) != null) {
          LOG.error("Oops... Binding conflict...");
        } else {
          final PsiType type = b.apply(var);
          final PsiClassType javaLangObject =
              PsiType.getJavaLangObject(
                  PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject));

          if (removeObject && javaLangObject.equals(type)) {
            final HashSet<PsiTypeVariable> cluster = myFactory.getClusterOf(var.getIndex());

            if (cluster != null) {
              for (final PsiTypeVariable war : cluster) {
                final PsiType wtype = b.apply(war);

                if (!javaLangObject.equals(wtype)) {
                  myBindings.put(index, type);
                  break;
                }
              }
            }
          } else {
            myBindings.put(index, type);
          }
        }
      }
    }
 /**
  * Merge equal IntegerVariable into a unique one.
  *
  * @param k number of unique variables
  * @param nbIntVars number of integer variable within the model
  * @param color array of indice of unique variables
  * @param domainByColor domain of unique variables
  */
 @Override
 protected void apply(
     final int k,
     final int nbIntVars,
     final int[] color,
     final TIntObjectHashMap<IntegerVariableMerger> domainByColor) {
   IntegerVariable vtmp;
   IntegerVariableMerger dtmp;
   final IntegerVariable[] var = new IntegerVariable[k + 1];
   for (int i = 0; i < nbIntVars; i++) {
     final int col = color[i];
     if (col != -1) {
       final IntegerVariable v = model.getIntVar(i);
       if (var[col] == null) {
         dtmp = domainByColor.get(col);
         if (dtmp.values != null) {
           vtmp = new IntegerVariable(StringUtils.randomName(), dtmp.values);
         } else {
           vtmp = new IntegerVariable(StringUtils.randomName(), dtmp.low, dtmp.upp);
         }
         vtmp.addOptions(dtmp.optionsSet);
         var[col] = vtmp;
         add(vtmp);
       }
       replaceBy(v, var[col]);
       delete(v);
     }
   }
 }
 @Override
 protected synchronized void onError() {
   super.onError();
   for (int each : myDataMap.keys()) {
     myDataMap.get(each).remoteId = -1;
   }
 }
    public Binding reduceRecursive() {
      final BindingImpl binding = (BindingImpl) create();

      for (final PsiTypeVariable var : myBoundVariables) {
        final int index = var.getIndex();
        final PsiType type = myBindings.get(index);

        if (type != null) {
          class Verifier extends PsiExtendedTypeVisitor<Void> {
            boolean myFlag = false;

            @Override
            public Void visitTypeVariable(final PsiTypeVariable var) {
              if (var.getIndex() == index) {
                myFlag = true;
              }

              return null;
            }
          }

          final Verifier verifier = new Verifier();

          type.accept(verifier);

          if (verifier.myFlag) {
            myBindings.put(index, Bottom.BOTTOM);
            binding.myBindings.put(index, Bottom.BOTTOM);
          } else {
            binding.myBindings.put(index, type);
          }
        } else {
          binding.myBindings.put(index, type);
        }
      }

      for (final PsiTypeVariable var : myBoundVariables) {
        final int index = var.getIndex();
        final PsiType type = myBindings.get(index);

        if (type != null) {
          myBindings.put(index, binding.apply(type));
        }
      }

      return this;
    }
 @Override
 public String getPath(int pathId) {
   String path = myAlternativePaths.get(pathId);
   if (path != null) {
     return path;
   }
   return myWrapee.getPath(pathId);
 }
示例#7
0
  public TIntIntHashMap rollItems(int wrapperItemId, int playerLevel, ItemRace race) {
    TIntIntHashMap itemCountMap = new TIntIntHashMap();

    final WrapperItem wrapperItem = wrappedItemData.get(wrapperItemId);
    if (wrapperItem == null) return itemCountMap;

    return wrapperItem.rollItems(playerLevel, race);
  }
 private void setDirtyScope(int passId, RangeMarker scope) {
   RangeMarker marker = dirtyScopes.get(passId);
   if (marker != scope) {
     if (marker != null) {
       marker.dispose();
     }
     dirtyScopes.put(passId, scope);
   }
 }
示例#9
0
  @Nullable
  private VirtualFileSystemEntry findFileById(
      int id, boolean cachedOnly, TIntArrayList visited, int mask) {
    VirtualFileSystemEntry cached = myIdToDirCache.get(id);
    if (cached != null) return cached;

    if (visited != null
        && (visited.size() >= DEPTH_LIMIT || (mask & id) == id && visited.contains(id))) {
      @NonNls
      String sb =
          "Dead loop detected in persistent FS (id=" + id + " cached-only=" + cachedOnly + "):";
      for (int i = 0; i < visited.size(); i++) {
        int _id = visited.get(i);
        sb +=
            "\n  "
                + _id
                + " '"
                + getName(_id)
                + "' "
                + String.format("%02x", getFileAttributes(_id))
                + ' '
                + myIdToDirCache.containsKey(_id);
      }
      LOG.error(sb);
      return null;
    }

    int parentId = getParent(id);
    if (parentId >= id) {
      if (visited == null) visited = new TIntArrayList(DEPTH_LIMIT);
    }
    if (visited != null) visited.add(id);

    VirtualFileSystemEntry result;
    if (parentId == 0) {
      myRootsLock.readLock().lock();
      try {
        result = myRootsById.get(id);
      } finally {
        myRootsLock.readLock().unlock();
      }
    } else {
      VirtualFileSystemEntry parentFile = findFileById(parentId, cachedOnly, visited, mask | id);
      if (parentFile instanceof VirtualDirectoryImpl) {
        result = ((VirtualDirectoryImpl) parentFile).findChildById(id, cachedOnly);
      } else {
        result = null;
      }
    }

    if (result != null && result.isDirectory()) {
      VirtualFileSystemEntry old = myIdToDirCache.put(id, result);
      if (old != null) result = old;
    }
    return result;
  }
示例#10
0
 private void addToMap(int id, int index) {
   id = unwrap(myFactory.getValue(id)).getID();
   int[] classes = myIdToEqClassesIndices.get(id);
   if (classes == null) {
     classes = new int[] {index};
     myIdToEqClassesIndices.put(id, classes);
   } else {
     classes = ArrayUtil.append(classes, index);
     myIdToEqClassesIndices.put(id, classes);
   }
 }
示例#11
0
 private void removeFromMap(int id, int index) {
   id = unwrap(myFactory.getValue(id)).getID();
   int[] classes = myIdToEqClassesIndices.get(id);
   if (classes != null) {
     int i = ArrayUtil.indexOf(classes, index);
     if (i != -1) {
       classes = ArrayUtil.remove(classes, i);
       myIdToEqClassesIndices.put(id, classes);
     }
   }
 }
  private synchronized int getRemoteId(int localId)
      throws RemoteException, MavenServerIndexerException {
    IndexData result = myDataMap.get(localId);
    MavenLog.LOG.assertTrue(result != null, "index " + localId + " not found");

    if (result.remoteId == -1) {
      result.remoteId =
          getOrCreateWrappee()
              .createIndex(
                  result.indexId, result.repositoryId, result.file, result.url, result.indexDir);
    }
    return result.remoteId;
  }
示例#13
0
  private int getEqClassIndex(@NotNull final DfaValue dfaValue) {
    final int id = unwrap(dfaValue).getID();
    int[] classes = myIdToEqClassesIndices.get(id);

    int result = -1;
    if (classes != null) {
      for (int index : classes) {
        EqClass aClass = myEqClasses.get(index);
        if (!aClass.contains(dfaValue.getID())) continue;
        if (!canBeReused(dfaValue) && aClass.size() > 1) break;
        result = index;
        break;
      }
    }
    return result;
  }
示例#14
0
    public PsiType apply(final PsiType type) {
      if (type instanceof PsiTypeVariable) {
        final PsiType t = myBindings.get(((PsiTypeVariable) type).getIndex());
        return t == null ? type : t;
      } else if (type instanceof PsiArrayType) {
        return apply(((PsiArrayType) type).getComponentType()).createArrayType();
      } else if (type instanceof PsiClassType) {
        final PsiClassType.ClassResolveResult result = Util.resolveType(type);
        final PsiClass theClass = result.getElement();
        final PsiSubstitutor aSubst = result.getSubstitutor();

        PsiSubstitutor theSubst = PsiSubstitutor.EMPTY;

        if (theClass != null) {
          for (final PsiTypeParameter aParm : aSubst.getSubstitutionMap().keySet()) {
            final PsiType aType = aSubst.substitute(aParm);

            theSubst = theSubst.put(aParm, apply(aType));
          }

          return JavaPsiFacade.getInstance(theClass.getProject())
              .getElementFactory()
              .createType(theClass, theSubst);
        } else {
          return type;
        }
      } else if (type instanceof PsiWildcardType) {
        final PsiWildcardType wcType = (PsiWildcardType) type;
        final PsiType bound = wcType.getBound();

        if (bound != null) {
          final PsiType abound = apply(bound);

          if (abound instanceof PsiWildcardType) {
            return null;
          }

          return wcType.isExtends()
              ? PsiWildcardType.createExtends(PsiManager.getInstance(myProject), abound)
              : PsiWildcardType.createSuper(PsiManager.getInstance(myProject), abound);
        }

        return type;
      } else {
        return type;
      }
    }
  public void notifyTestResult(ObjectReader reader) {
    final TestProxy testProxy = reader.readObject();

    if (testProxy.getParent() == null) { // model.getRoot() == testProxy
      getDynamicParent(myModel, testProxy).insertNextRunningChild(testProxy);
    }

    final int state = reader.readInt();
    final StateChanger stateChanger = STATE_CLASSES.get(state);
    stateChanger.changeStateOf(testProxy, reader);
    synchronized (myCurrentTests) {
      if (stateChanger instanceof RunningStateSetter) {
        myCurrentTests.add(testProxy);
      } else {
        myCurrentTests.remove(testProxy);
      }
    }
  }
示例#16
0
    public String toString() {
      final StringBuffer buffer = new StringBuffer();

      for (PsiTypeVariable boundVariable : myBoundVariables) {
        final int i = boundVariable.getIndex();
        final PsiType binding = myBindings.get(i);

        if (binding != null) {
          buffer
              .append("#")
              .append(i)
              .append(" -> ")
              .append(binding.getPresentableText())
              .append("; ");
        }
      }

      return buffer.toString();
    }
  /** returns the postings suitable to be written into the block direct index */
  @Override
  public int[][] getPostings() {
    final int termCount = occurrences.size();
    final int[] termids = new int[termCount];
    final int[] tfs = new int[termCount];
    final int[] fields = null;
    final int[] blockfreqs = new int[termCount];
    final TIntObjectHashMap<int[]> term2blockids = new TIntObjectHashMap<int[]>();
    int blockTotal = 0; // TODO we already have blockTotal as this.blockCount, so no need to count?
    class PostingVisitor implements TObjectIntProcedure<String> {
      int i = 0;
      int blockTotal = 0;

      public boolean execute(final String a, final int b) {
        termids[i] = getTermId(a);
        tfs[i] = b;
        final TIntHashSet ids = term_blocks.get(a);
        blockfreqs[i] = ids.size();
        blockTotal += ids.size();
        final int[] bids = ids.toArray();
        Arrays.sort(bids);
        term2blockids.put(termids[i], bids);
        // System.err.println(a+": tid="+termids[i]+" tf="+tfs[i]+" bf="+blockfreqs[i] +"
        // blocks="+Arrays.toString(bids));
        i++;
        return true;
      }
    }
    PostingVisitor proc = new PostingVisitor();
    occurrences.forEachEntry(proc);
    blockTotal = proc.blockTotal;
    HeapSortInt.ascendingHeapSort(termids, tfs, blockfreqs);
    final int[] blockids = new int[blockTotal];
    int offset = 0;
    for (int termid : termids) {
      final int[] src = term2blockids.get(termid);
      final int src_l = src.length;
      System.arraycopy(src, 0, blockids, offset, src_l);
      offset += src_l;
    }
    return new int[][] {termids, tfs, fields, blockfreqs, blockids};
  }
示例#18
0
  private void updateCustomClientData(Player[] players, int id) {

    int blockId = itemBlock.get(id);

    short metaData = (short) itemMetaData.get(id);

    @SuppressWarnings("unused")
    String pluginName = (String) itemPlugin.get(id);

    PacketCustomItem p = new PacketCustomItem(id, blockId, metaData);

    for (Player player : players) {
      if (player instanceof SpoutCraftPlayer) {
        SpoutCraftPlayer sp = (SpoutCraftPlayer) player;
        if (sp.isSpoutCraftEnabled()) {
          sp.sendPacket(p);
        }
      }
    }
  }
  private void storeIds(@NotNull ConcurrentIntObjectMap<int[]> fileToForwardIds) {
    int forwardSize = 0;
    int backwardSize = 0;
    final TIntObjectHashMap<TIntArrayList> fileToBackwardIds =
        new TIntObjectHashMap<TIntArrayList>(fileToForwardIds.size());
    for (ConcurrentIntObjectMap.IntEntry<int[]> entry : fileToForwardIds.entries()) {
      int fileId = entry.getKey();
      int[] forwardIds = entry.getValue();
      forwardSize += forwardIds.length;
      for (int forwardId : forwardIds) {
        TIntArrayList backIds = fileToBackwardIds.get(forwardId);
        if (backIds == null) {
          backIds = new TIntArrayList();
          fileToBackwardIds.put(forwardId, backIds);
        }
        backIds.add(fileId);
        backwardSize++;
      }
    }
    log("backwardSize = " + backwardSize);
    log("forwardSize = " + forwardSize);
    log("fileToForwardIds.size() = " + fileToForwardIds.size());
    log("fileToBackwardIds.size() = " + fileToBackwardIds.size());
    assert forwardSize == backwardSize;

    // wrap in read action so that sudden quit (in write action) would not interrupt us
    myApplication.runReadAction(
        () -> {
          if (!myApplication.isDisposed()) {
            fileToBackwardIds.forEachEntry(
                new TIntObjectProcedure<TIntArrayList>() {
                  @Override
                  public boolean execute(int fileId, TIntArrayList backIds) {
                    storage.addAll(fileId, backIds.toNativeArray());
                    return true;
                  }
                });
          }
        });
  }
示例#20
0
 public void forall(Category c) {
   // get feature structures
   if (!(c instanceof AtomCat)) return;
   String type = ((AtomCat) c).getType();
   FeatureStructure fs = c.getFeatureStructure();
   GFeatStruc gfs = (GFeatStruc) fs;
   if (gfs == null || gfs.getInheritsFrom() == 0) return;
   int inhf = gfs.getInheritsFrom();
   FeatureStructure inhfFS = (FeatureStructure) featStrucMap.get(inhf);
   if (inhfFS != null) {
     // copy values of features from inhfFS not already present
     for (Iterator<String> it = inhfFS.getAttributes().iterator(); it.hasNext(); ) {
       String att = it.next();
       if (gfs.hasAttribute(att)) continue;
       gfs.setFeature(att, UnifyControl.copy(inhfFS.getValue(att)));
     }
     // for each possible attr used with this type and not already present,
     // add feature equation
     Collection<String> attrs = (Collection<String>) _catsToAttrs.get(type);
     if (attrs == null) return;
     for (Iterator<String> it = attrs.iterator(); it.hasNext(); ) {
       String att = it.next();
       if (gfs.hasAttribute(att)) continue;
       String varName = att.toUpperCase() + inhf;
       if (_lfAttrs.contains(att)) {
         gfs.setFeature(att, new HyloVar(varName));
         inhfFS.setFeature(att, new HyloVar(varName));
       } else {
         gfs.setFeature(att, new GFeatVar(varName));
         inhfFS.setFeature(att, new GFeatVar(varName));
       }
     }
   } else {
     System.err.println(
         "Warning: no feature structure with inheritsFrom index of "
             + inhf
             + " found in category "
             + c);
   }
 }
  /**
   * Detect different equalities cliques.
   *
   * @param matrix matrix of equalities
   * @param nbIntVars nb of IntegerVariable within the model
   * @param color array of colir, ie nb different variable
   * @param domainByColor list of domain by color.
   * @return nb of different color found
   */
  private int detect(
      final ISparseMatrix matrix,
      final int nbIntVars,
      final int[] color,
      final TIntObjectHashMap<IntegerVariableMerger> domainByColor) {
    int nb = -1;
    IntegerVariableMerger dtmp = new IntegerVariableMerger();
    final Iterator<Long> it = matrix.iterator();
    while (it.hasNext()) {
      final long v = it.next();
      final int i = (int) (v / nbIntVars);
      final int j = (int) (v % nbIntVars);

      if (color[i] == -1) {
        nb++;
        color[i] = nb;
        domainByColor.put(nb, new IntegerVariableMerger(model.getIntVar(i)));
      }
      final IntegerVariableMerger d = domainByColor.get(color[i]);
      // backup
      dtmp.copy(d);
      if (d.intersection(model.getIntVar(j))) {
        color[j] = color[i];
        domainByColor.put(color[i], d);
      } else {
        add(Choco.eq(model.getIntVar(i), model.getIntVar(j)));
        // rollback
        d.copy(dtmp);
        if (color[j] == -1) {
          nb++;
          color[j] = nb;
          domainByColor.put(nb, new IntegerVariableMerger(model.getIntVar(j)));
        }
      }
    }
    return nb;
  }
 /**
  * Merge equal IntegerVariable into a unique one.
  *
  * @param k number of unique variables
  * @param nbIntVars number of integer variable within the model
  * @param color array of indice of unique variables
  * @param domainByColor domain of unique variables
  */
 @Override
 protected void apply(
     final int k,
     final int nbIntVars,
     final int[] color,
     final TIntObjectHashMap<IntegerVariableMerger> domainByColor) {
   final IntDomainVar[] var = new IntDomainVar[k + 1];
   IntegerVariableMerger dtmp;
   IntegerVariable vtmp;
   for (int i = 0; i < nbIntVars; i++) {
     final int col = color[i];
     if (col != -1) {
       final IntegerVariable v = model.getIntVar(i);
       if (var[col] == null) {
         dtmp = domainByColor.get(col);
         vtmp = dtmp.create();
         vtmp.addOptions(dtmp.optionsSet);
         vtmp.findManager(CPModel.properties);
         var[col] = (IntDomainVar) ppsolver.getMod2Sol().readModelVariable(vtmp);
       }
       ppsolver.setVar(v, var[col]);
     }
   }
 }
示例#23
0
 public int[] searchBounds(Text key) throws IOException {
   if (key.getLength() == 0) return defaultReturn;
   int[] boundaries = map.get(key.charAt(0));
   if (boundaries == null) return defaultReturn;
   return boundaries;
 }
示例#24
0
  /**
   * optimise
   *
   * @param structureName
   * @param index
   * @param statsCounter
   * @param numEntries
   * @throws IOException
   */
  @SuppressWarnings("unchecked")
  public static void optimise(
      String structureName,
      Index index,
      LexiconBuilder.CollectionStatisticsCounter statsCounter,
      int numEntries)
      throws IOException {

    final String mapFileFilename =
        constructFilename(structureName, index.getPath(), index.getPrefix(), MAPFILE_EXT);
    final FixedSizeWriteableFactory<Text> keyFactory =
        (FixedSizeWriteableFactory<Text>) index.getIndexStructure(structureName + "-keyfactory");
    final FixedSizeWriteableFactory<LexiconEntry> valueFactory =
        (FixedSizeWriteableFactory<LexiconEntry>)
            index.getIndexStructure(structureName + "-valuefactory");
    // logger.info("Optimsing lexicon with "+ numEntries + " entries");
    // term id lookups
    boolean termIdsAligned = true;
    int[] termid2index = new int[numEntries];
    Arrays.fill(termid2index, -1);
    int counter = 0;
    int lastTermId = -1;

    // bsearch reduction
    int previousFirstChar = -1;
    int firstChar = 0;
    final TIntObjectHashMap<int[]> map = new TIntObjectHashMap<int[]>();

    Iterator<Map.Entry<Text, LexiconEntry>> iterator =
        new FSOrderedMapFile.EntryIterator<Text, LexiconEntry>(
            mapFileFilename, keyFactory, valueFactory);
    while (iterator.hasNext()) {
      Map.Entry<Text, LexiconEntry> lee = iterator.next();
      // System.err.println(lee.toString());

      // term id
      int termId = lee.getValue().getTermId();
      if (!(termId == lastTermId + 1)) termIdsAligned = false;
      if (termid2index[termId] != -1) {
        throw new WrappedIOException(
            new IllegalArgumentException(
                "Termid "
                    + termId
                    + " is not unique - used at entries "
                    + termid2index[termId]
                    + " and"
                    + counter));
      }
      termid2index[termId] = counter;
      lastTermId = termId;

      // bsearch reduction optimisaion
      firstChar = lee.getKey().charAt(0);
      if (firstChar != previousFirstChar) {
        int[] boundaries = new int[] {counter, 0};
        map.put(firstChar, boundaries);
        previousFirstChar = firstChar;
      }

      // increments
      statsCounter.count(lee.getValue());
      counter++;
    }
    if (counter != numEntries) termIdsAligned = false;
    IndexUtil.close(iterator);

    // deal with termids
    if (termIdsAligned) {
      index.setIndexProperty("index." + structureName + ".termids", "aligned");
      // logger.info("All ids for structure "+structureName+ " are aligned, skipping "
      //				+ID_EXT+ " file");
    } else {
      DataOutputStream dos =
          new DataOutputStream(
              Files.writeFileStream(
                  constructFilename(structureName, index.getPath(), index.getPrefix(), ID_EXT)));
      for (int indexof : termid2index) dos.writeInt(indexof);
      dos.close();
      index.setIndexProperty(
          "index." + structureName + ".termids", (numEntries > 15000000) ? "file" : "fileinmem");
    }

    int[] mapKeys = map.keys();
    Arrays.sort(mapKeys);
    final int mapKeysSize = mapKeys.length;
    for (int i = 0; i < mapKeysSize - 1; i++) {
      int nextLowerBoundary = (map.get(mapKeys[i + 1]))[0];
      int[] currentBoundaries = map.get(mapKeys[i]);
      currentBoundaries[1] = nextLowerBoundary;
      map.put(mapKeys[i], currentBoundaries);
    }
    // do something about the last entry
    int nextLowerBoundary = counter;
    int[] currentBoundaries = (int[]) map.get(mapKeys[mapKeysSize - 1]);
    currentBoundaries[1] = nextLowerBoundary;
    map.put(mapKeys[mapKeysSize - 1], currentBoundaries);

    final ObjectOutputStream oos =
        new ObjectOutputStream(
            Files.writeFileStream(
                constructFilename(structureName, index.getPath(), index.getPrefix(), HASH_EXT)));
    oos.writeObject(map);
    oos.close();
    index.setIndexProperty("index." + structureName + ".bsearchshortcut", "charmap");
    index.flush();
  }
示例#25
0
 public boolean binds(final PsiTypeVariable var) {
   return myBindings.get(var.getIndex()) != null;
 }
示例#26
0
 public CubicTemplate getTemplate(int id, int level) {
   return _cubics.get(hash(id, level));
 }
示例#27
0
 public ItemTemplate getItemTemplate(int itemId) {
   return items.get(itemId);
 }
示例#28
0
 public WrapperItem getItemWrapper(int itemId) {
   return wrappedItemData.get(itemId);
 }
示例#29
0
 /** Get a node object, given the ID of the node. */
 public Node getNode(int index) {
   return (Node) nodeMap.get(index);
 }
  @Override
  @Nullable
  public VirtualFileSystemEntry findRoot(
      @NotNull String basePath, @NotNull NewVirtualFileSystem fs) {
    String rootUrl = normalizeRootUrl(basePath, fs);
    boolean isFakeRoot = basePath.isEmpty();
    VirtualFileSystemEntry root;

    myRootsLock.readLock().lock();
    try {
      root = isFakeRoot ? mySuperRoot : myRoots.get(rootUrl);
      if (root != null) return root;
    } finally {
      myRootsLock.readLock().unlock();
    }

    myRootsLock.writeLock().lock();
    try {
      root = isFakeRoot ? mySuperRoot : myRoots.get(rootUrl);
      if (root != null) return root;

      int rootId = FSRecords.findRootRecord(rootUrl);
      root = myRootsById.get(rootId);
      if (root != null) return root;

      if (isFakeRoot) {
        // fake super-root
        root = new FakeRoot(fs, rootId);
      } else if (fs instanceof JarFileSystem) {
        // optimization: for jar roots do not store base path in the myName field, use local FS
        // file's getPath()
        String parentPath = basePath.substring(0, basePath.indexOf(JarFileSystem.JAR_SEPARATOR));
        VirtualFile parentLocalFile = LocalFileSystem.getInstance().findFileByPath(parentPath);
        if (parentLocalFile == null) return null;

        // check one more time since the findFileByPath could have created the root (by reentering
        // the findRoot)
        root = myRoots.get(rootUrl);
        if (root != null) return root;
        root = myRootsById.get(rootId);
        if (root != null) return root;

        root = new JarRoot(fs, rootId, parentLocalFile);
      } else {
        root = new FsRoot(fs, rootId, basePath);
      }

      if (isFakeRoot) {
        mySuperRoot = root;
      } else {
        FileAttributes attributes = fs.getAttributes(root);
        if (attributes == null || !attributes.isDirectory()) {
          return null;
        }
        final boolean newRoot = writeAttributesToRecord(rootId, 0, root, fs, attributes);
        if (!newRoot && attributes.lastModified != FSRecords.getTimestamp(rootId)) {
          root.markDirtyRecursively();
        }

        myRoots.put(rootUrl, root);
        myRootsById.put(rootId, root);

        if (rootId != root.getId()) throw new AssertionError();
      }

      return root;
    } finally {
      myRootsLock.writeLock().unlock();
    }
  }