* @throws HistoryException
     */
    @Override
    public void store(History history, Repository repository)
            throws HistoryException {
        final RuntimeEnvironment env = RuntimeEnvironment.getInstance();
        String latestRev = null;
        // Return immediately when there is nothing to do.
        List<HistoryEntry> entries = history.getHistoryEntries();
        if (entries.isEmpty()) {
            return;
        }
        OpenGrokLogger.getLogger().log(Level.FINE,
            "Storing history for repo {0}",
            new Object[] {repository.getDirectoryName()});
        HashMap<String, List<HistoryEntry>> map =
                new HashMap<String, List<HistoryEntry>>();
        /*
         * Go through all history entries for this repository (acquired through
         * history/log command executed for top-level directory of the repo
         * and parsed into HistoryEntry structures) and create hash map which
         * maps file names into list of HistoryEntry structures corresponding
         * to changesets in which the file was modified.
         */
        for (HistoryEntry e : history.getHistoryEntries()) {
            // The history entries are sorted from newest to oldest.
            if (latestRev == null) {
                latestRev = e.getRevision();
            }
            for (String s : e.getFiles()) {
                /*
                 * We do not want to generate history cache for files which
                 * do not currently exist in the repository.
                 */
                File test = new File(env.getSourceRootPath() + s);
                if (!test.exists()) {
                    continue;
                }
                List<HistoryEntry> list = map.get(s);
                if (list == null) {
                    list = new ArrayList<HistoryEntry>();
                    map.put(s, list);
                }
                /*
                 * We need to do deep copy in order to have different tags
                 * per each commit.
                 */
                if (env.isTagsEnabled() && repository.hasFileBasedTags()) {
                    list.add(new HistoryEntry(e));
                } else {
                    list.add(e);
                }
            }
        }
        /*
         * Now traverse the list of files from the hash map built above
         * and for each file store its history (saved in the value of the
         * hash map entry for the file) in a file. Skip renamed files
         * which will be handled separately below.
         */
        final File root = RuntimeEnvironment.getInstance().getSourceRootFile();
        for (Map.Entry<String, List<HistoryEntry>> map_entry : map.entrySet()) {
            try {
                if (RuntimeEnvironment.isRenamedFilesEnabled() &&
                    isRenamedFile(map_entry, env, repository, history)) {
                        continue;
                }
            } catch (IOException ex) {
               OpenGrokLogger.getLogger().log(Level.WARNING,
                   "isRenamedFile() got exception: " + ex);
            }
            
            doFileHistory(map_entry, env, repository, null, root, false);
        }
        if (!RuntimeEnvironment.isRenamedFilesEnabled()) {
            finishStore(repository, latestRev);
            return;
        }
        /*
         * Now handle renamed files (in parallel).
         */
        HashMap<String, List<HistoryEntry>> renamed_map =
                new HashMap<String, List<HistoryEntry>>();
        for (final Map.Entry<String, List<HistoryEntry>> map_entry : map.entrySet()) {
            try {
                if (isRenamedFile(map_entry, env, repository, history)) {
                    renamed_map.put(map_entry.getKey(), map_entry.getValue());
                }
            } catch (IOException ex) {
                OpenGrokLogger.getLogger().log(Level.WARNING,
                    "isRenamedFile() got exception: " + ex);
            }
        }
        // The directories for the renamed files have to be created before
        // the actual files otherwise storeFile() might be racing for
        // mkdirs() if there are multiple renamed files from single directory
        // handled in parallel.
        for (final String file : renamed_map.keySet()) {
            File cache = getCachedFile(new File(env.getSourceRootPath() + file));
            File dir = cache.getParentFile();
            if (!dir.isDirectory() && !dir.mkdirs()) {
                OpenGrokLogger.getLogger().log(Level.WARNING,
                   "Unable to create cache directory '" + dir + "'.");
            }
        }
        final Repository repositoryF = repository;
        final CountDownLatch latch = new CountDownLatch(renamed_map.size());
        for (final Map.Entry<String, List<HistoryEntry>> map_entry : renamed_map.entrySet()) {
            RuntimeEnvironment.getHistoryRenamedExecutor().submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        doFileHistory(map_entry, env, repositoryF,
                            new File(env.getSourceRootPath() + map_entry.getKey()),
                            root, true);
                    } catch (Exception ex) {
                        // We want to catch any exception since we are in thread.
                        OpenGrokLogger.getLogger().log(Level.WARNING,
                            "doFileHistory() got exception: " + ex);