Properly await termination of all index executor threads on shutdown

When Gerrit is shutdown we must wait for all currently running index
threads to finish because otherwise these index events are lost and the
index becomes stale.

There are 2 executors for indexing, one for interactive indexing and one
for batch indexing.

A first attempt to fix this was done by change I7bda130585, but it broke
the site after online reindexing (see issue 4618) and hence it was
reverted by change I6ec90eb733.

Change Id332ec0215 fixed the issue partly. In addition to the
Index#close() method which closes the index it added a Index#stop()
method that stops the (interactive) index executor and awaits the
termination of all running index threads. The Index#stop() method is
only called when Gerrit is shutdown, while Index#close() is also invoked
when online reindexing is done. There are several issues with this fix:

1. It only cared about the interactive index executor, but not about the
   batch index executor.
2. The IndexCollection#stop() method which is called on Gerrit shutdown
   missed to call Index#stop() on the write index if it was the same
   Index instance as the read index.
3. Although documented developers were confused about Index having both
   a close() and a stop() method and there was a danger of calling
   stop() accidentally and thus break all further indexing.
4. Closing the interactive index executor when stopping the change index
   assumed that the inactive index executor is only used by the change
   index. This assumption is currently true, but only because the other
   indexes (account, group, project) missed to use this executor.
5. The interactive index executor was only stopped when Lucene was used,
   but not when ElasticSearch was used.

Due to 1. and 2. all query tests (e.g. LuceneQueryChangesTest) were
leaking threads. Each test case accumulated more running (interactive
and batch) index threads. These threads consumed memory and in the end
this possibly resulted in an OutOfMemoryError (only for running
LuceneQueryChangesTest on Mac, see issue 7611).

To fix this IndexModule adds a new LifecycleListener that is responsible
for shutting down both index executors:

- Both index executors are now shutdown (interactive and batch).
- The stop() method of LifecycleListeners is only invoked when Gerrit is
  shutdown and it's unlikely to be triggered during normal Gerrit
  runtime (e.g. when online reindexing is done).
- There is exactly one place that shuts down the index executors (as
  opposed to n indexes trying to take care of it). This makes sure that
  the executors can be shared across indexes.
- The stop() method from Index is removed so that there is less
  confusion about stop() vs. close().

One important thing is that the executors are shutdown before closing
the indexes. This ensures that all writes have been performed in-memory
before the final flush to disk is done. This means that the
LifecycleListener to stop the executors must be registered after the
LifecycleListeners that close the indexes (on Gerrit start the
LifecycleListeners are invoked in the order in which they are
registered, on shutdown of Gerrit the order is reversed).

IndexModule also allows to provide external executors for the
interactive and batch indexing (instead of creating new executors). In
this case IndexModule doesn't register a LifecycleListener to shutdown
the executors since they are externally managed. Providing external
executors is only used by Google for their multi-tenant setup. In this
setup the executors are global singletons in the process that are shared
by many sites and shutting down one site must not shut down the global
executors.

This fixes the OutOfMemoryError that was observed on Mac when running
the LuceneQueryChangesTest (see issue 7611).

Bug: Issue 7611
Change-Id: I093fb19b56aba90fbb7579f0e59da435c4c1b702
Signed-off-by: Edwin Kempin <ekempin@google.com>
4 files changed
tree: 69f1a4280124866dbf4e637344359566af36d09b
  1. .settings/
  2. contrib/
  3. Documentation/
  4. gerrit-acceptance-framework/
  5. gerrit-acceptance-tests/
  6. gerrit-antlr/
  7. gerrit-cache-h2/
  8. gerrit-common/
  9. gerrit-elasticsearch/
  10. gerrit-extension-api/
  11. gerrit-gpg/
  12. gerrit-gwtdebug/
  13. gerrit-gwtexpui/
  14. gerrit-gwtui/
  15. gerrit-gwtui-common/
  16. gerrit-httpd/
  17. gerrit-launcher/
  18. gerrit-lucene/
  19. gerrit-main/
  20. gerrit-oauth/
  21. gerrit-openid/
  22. gerrit-patch-commonsnet/
  23. gerrit-patch-jgit/
  24. gerrit-pgm/
  25. gerrit-plugin-api/
  26. gerrit-plugin-gwtui/
  27. gerrit-prettify/
  28. gerrit-reviewdb/
  29. gerrit-server/
  30. gerrit-sshd/
  31. gerrit-test-util/
  32. gerrit-util-cli/
  33. gerrit-util-http/
  34. gerrit-util-ssl/
  35. gerrit-war/
  36. lib/
  37. plugins/
  38. polygerrit-ui/
  39. ReleaseNotes/
  40. tools/
  41. website/
  42. .bazelproject
  43. .editorconfig
  44. .git-blame-ignore-revs
  45. .gitignore
  46. .gitmodules
  47. .mailmap
  48. .pydevproject
  49. BUILD
  50. COPYING
  51. INSTALL
  52. README.md
  53. SUBMITTING_PATCHES
  54. version.bzl
  55. WORKSPACE
README.md

Gerrit Code Review

Gerrit is a code review and project management tool for Git based projects.

Build Status

Objective

Gerrit makes reviews easier by showing changes in a side-by-side display, and allowing inline comments to be added by any reviewer.

Gerrit simplifies Git based project maintainership by permitting any authorized user to submit changes to the master Git repository, rather than requiring all approved changes to be merged in by hand by the project maintainer.

Documentation

For information about how to install and use Gerrit, refer to the documentation.

Source

Our canonical Git repository is located on googlesource.com. There is a mirror of the repository on Github.

Reporting bugs

Please report bugs on the issue tracker.

Contribute

Gerrit is the work of hundreds of contributors. We appreciate your help!

Please read the contribution guidelines.

Note that we do not accept Pull Requests via the Github mirror.

Getting in contact

The IRC channel on freenode is #gerrit. An archive is available at: echelog.com.

The Developer Mailing list is repo-discuss on Google Groups.

License

Gerrit is provided under the Apache License 2.0.

Build

Install Bazel and run the following:

    git clone --recursive https://gerrit.googlesource.com/gerrit
    cd gerrit && bazel build release

Install binary packages (Deb/Rpm)

The instruction how to configure GerritForge/BinTray repositories is here

On Debian/Ubuntu run:

    apt-get update & apt-get install gerrit=<version>-<release>

NOTE: release is a counter that starts with 1 and indicates the number of packages that have been released with the same version of the software.

On CentOS/RedHat run:

    yum clean all && yum install gerrit-<version>[-<release>]

On Fedora run:

    dnf clean all && dnf install gerrit-<version>[-<release>]

Use pre-built Gerrit images on Docker

Docker images of Gerrit are available on DockerHub

To run a CentOS 7 based Gerrit image:

    docker run -p 8080:8080 gerritforge/gerrit-centos7[:version]

To run a Ubuntu 15.04 based Gerrit image:

    docker run -p 8080:8080 gerritforge/gerrit-ubuntu15.04[:version]

NOTE: release is optional. Last released package of the version is installed if the release number is omitted.