// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.indexing.hash;

import com.intellij.openapi.progress.ProgressManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Processor;
import com.intellij.util.indexing.*;
import com.intellij.util.indexing.impl.IndexStorage;
import com.intellij.util.indexing.impl.MapIndexStorage;
import com.intellij.util.indexing.impl.UpdatableValueContainer;
import com.intellij.util.indexing.impl.ValueContainerInputRemapping;
import com.intellij.util.indexing.provided.SharedIndexExtension;
import com.intellij.util.io.PersistentEnumeratorBase;
import com.intellij.util.io.PersistentHashMap;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.nio.file.Path;

@ApiStatus.Internal
public class HashBasedMapReduceIndex<Key, Value> extends VfsAwareMapReduceIndex<Key, Value> {
  HashBasedMapReduceIndex(@NotNull SharedIndexChunk chunk,
                          @NotNull SharedIndexExtension<Key, Value> sharedExtension,
                          @NotNull FileBasedIndexExtension<Key, Value> originalExtension,
                          @NotNull FileContentHashIndex hashIndex) throws IOException {
    super(originalExtension, createStorage(chunk.getPath(), originalExtension, sharedExtension, hashIndex.getHashIdToFileIdsFunction(chunk.getChunkId())), null, null, null, null);
  }

  private static <Key, Value> IndexStorage<Key, Value> createStorage(@NotNull Path baseFile,
                                                                     @NotNull FileBasedIndexExtension<Key, Value> originalExtension,
                                                                     @NotNull SharedIndexExtension<Key, Value> providedExtension,
                                                                     @NotNull ValueContainerInputRemapping hashToFileId) throws IOException {
    return new MyMapIndexStorage<>(baseFile.resolve(originalExtension.getName().getName()), originalExtension, providedExtension, hashToFileId);
  }

  private static class MyMapIndexStorage<Key, Value>
    extends MapIndexStorage<Key, Value>
    implements VfsAwareIndexStorage<Key, Value> {
    private MyMapIndexStorage(Path baseFile,
                              FileBasedIndexExtension<Key, Value> originalExtension,
                              SharedIndexExtension<Key, Value> providedExtension,
                              ValueContainerInputRemapping hashToFileIds) throws IOException {
      super(baseFile,
            providedExtension.createKeyDescriptor(baseFile),
            providedExtension.createValueExternalizer(baseFile),
            originalExtension.getCacheSize(), originalExtension.keyIsUniqueForIndexedFile(),
            true, true, hashToFileIds);
    }

    @Override
    protected void checkCanceled() {
      ProgressManager.checkCanceled();
    }

    @Override
    public boolean processKeys(@NotNull Processor<? super Key> processor, GlobalSearchScope scope, @Nullable IdFilter idFilter)
      throws StorageException {
      l.lock();
      try {
        myCache.clear(); // this will ensure that all new keys are made into the map
        return doProcessKeys(processor);
      }
      catch (IOException e) {
        throw new StorageException(e);
      }
      catch (RuntimeException e) {
        return unwrapCauseAndRethrow(e);
      }
      finally {
        l.unlock();
      }
    }

    private boolean doProcessKeys(@NotNull Processor<? super Key> processor) throws IOException {
      return myMap instanceof PersistentHashMap && PersistentEnumeratorBase.inlineKeyStorage(myKeyDescriptor)
             // process keys and check that they're already present in map because we don't have separated key storage we must check keys
             ? ((PersistentHashMap<Key, UpdatableValueContainer<Value>>)myMap).processKeysWithExistingMapping(processor)
             // optimization: process all keys, some of them might be already deleted but we don't care. We just read key storage file here
             : myMap.processKeys(processor);
    }
  }
}

@@ -176,16 +176,63 @@
 .hash;%0A%0A
+import com.intellij.openapi.diagnostic.Logger;%0A
 import c
@@ -273,24 +273,24 @@
 essManager;%0A
-
 import com.i
@@ -992,16 +992,68 @@
 le.Path;
+%0Aimport java.util.Collections;%0Aimport java.util.Map;
 %0A%0A@ApiSt
@@ -1160,16 +1160,104 @@
 alue%3E %7B%0A
+  private static final Logger LOG = Logger.getInstance(HashBasedMapReduceIndex.class);%0A%0A
   HashBa
@@ -1566,24 +1566,24 @@
 Exception %7B%0A
-
     super(or
@@ -1747,32 +1747,535 @@
 ll, null);%0A  %7D%0A%0A
+  @Override%0A  public @NotNull Map%3CKey, Value%3E getIndexedFileData(int fileId) throws StorageException %7B%0A    if (getExtension() instanceof SingleEntryFileBasedIndexExtension %7C%7C hasForwardIndex()) %7B%0A      return super.getIndexedFileData(fileId);%0A    %7D%0A    LOG.error(%22Shared index chunk for %22 + getExtension().getName() + %22 doesn't have forward index. Index data might be incomplete%22);%0A    return Collections.emptyMap();%0A  %7D%0A%0A  private boolean hasForwardIndex() %7B%0A    return getForwardIndex() != null;%0A  %7D%0A%0A
   private static

add an error logging when shared index try to access forward index but doesn't have it