Replace ACCOUNT_DIFF_PREFERENCES table with Git backend (part1)

Replace the usage of AccountDiffPreference with a different class in
extension API package.

Data is saved optimized in Git backend: default values are discarded
during save operation and restored during read operation; so that
this optimization step is transparent for the callers.

For example when only one setting, theme in this case, differs from
the default value, only this value is written into diff section in
preferences.config file:

+[diff]
+       theme = eclipse

To support live migration, the upgrade is done in two steps:

* part1 (this change):
  o Always write to both git and db
  o Introduce new configuration option to indicate whether to read from
    git or db, initially set to read from db
  o First binary update: some servers are reading/writing just the db;
    some servers are additionally writing to git
  o After first update: all servers are reading from the db, writing to
    both
  o Batch copy data from db to git (only related to non open source
    Gerrit version)
  o Update all servers to read from git. During the update, some will
    still be reading from the db; that's ok, because everybody is
    writing to git
* part2 (next change):
  o Bump database version, migrate the data from db to git, delete the
    table (and the flag) from the code and update the servers.

Change-Id: I30a6d82f4a8d0c33ae9bb26d7f93c66bd0cb8bee
This commit is contained in:
David Ostrovsky
2014-11-16 18:48:50 +01:00
committed by Edwin Kempin
parent ddd8ec8d06
commit 7d5a771844
43 changed files with 836 additions and 475 deletions

View File

@@ -14,91 +14,140 @@
package com.google.gerrit.server.account;
import com.google.gerrit.extensions.client.Theme;
import static com.google.gerrit.server.config.ConfigUtil.loadSection;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.UserConfigSections;
import com.google.gerrit.server.patch.PatchListKey;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
@Singleton
public class GetDiffPreferences implements RestReadView<AccountResource> {
private final Provider<CurrentUser> self;
private final Provider<ReviewDb> db;
private final Provider<AllUsersName> allUsersName;
private final GitRepositoryManager gitMgr;
private final boolean readFromGit;
@Inject
GetDiffPreferences(Provider<CurrentUser> self, Provider<ReviewDb> db) {
GetDiffPreferences(Provider<CurrentUser> self,
Provider<ReviewDb> db,
@GerritServerConfig Config cfg,
Provider<AllUsersName> allUsersName,
GitRepositoryManager gitMgr) {
this.self = self;
this.db = db;
this.allUsersName = allUsersName;
this.gitMgr = gitMgr;
readFromGit = cfg.getBoolean("user", null, "readPrefsFromGit", false);
}
@Override
public DiffPreferencesInfo apply(AccountResource rsrc)
throws AuthException, OrmException {
throws AuthException, OrmException, ConfigInvalidException, IOException {
if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("restricted to administrator");
}
Account.Id userId = rsrc.getUser().getAccountId();
AccountDiffPreference a = db.get().accountDiffPreferences().get(userId);
if (a == null) {
a = new AccountDiffPreference(userId);
}
return DiffPreferencesInfo.parse(a);
return readFromGit
? readFromGit(userId, gitMgr, allUsersName.get(), null)
: readFromDb(userId);
}
public static class DiffPreferencesInfo {
static DiffPreferencesInfo parse(AccountDiffPreference p) {
DiffPreferencesInfo info = new DiffPreferencesInfo();
info.context = p.getContext();
info.expandAllComments = p.isExpandAllComments() ? true : null;
info.ignoreWhitespace = p.getIgnoreWhitespace();
info.intralineDifference = p.isIntralineDifference() ? true : null;
info.lineLength = p.getLineLength();
info.manualReview = p.isManualReview() ? true : null;
info.retainHeader = p.isRetainHeader() ? true : null;
info.showLineEndings = p.isShowLineEndings() ? true : null;
info.showTabs = p.isShowTabs() ? true : null;
info.showWhitespaceErrors = p.isShowWhitespaceErrors() ? true : null;
info.skipDeleted = p.isSkipDeleted() ? true : null;
info.skipUncommented = p.isSkipUncommented() ? true : null;
info.hideTopMenu = p.isHideTopMenu() ? true : null;
info.autoHideDiffTableHeader = p.isAutoHideDiffTableHeader() ? true : null;
info.hideLineNumbers = p.isHideLineNumbers() ? true : null;
info.syntaxHighlighting = p.isSyntaxHighlighting() ? true : null;
info.tabSize = p.getTabSize();
info.renderEntireFile = p.isRenderEntireFile() ? true : null;
info.hideEmptyPane = p.isHideEmptyPane() ? true : null;
info.theme = p.getTheme();
return info;
static DiffPreferencesInfo readFromGit(Account.Id id,
GitRepositoryManager gitMgr, AllUsersName allUsersName,
DiffPreferencesInfo in)
throws IOException, ConfigInvalidException, RepositoryNotFoundException {
try (Repository git = gitMgr.openRepository(allUsersName)) {
VersionedAccountPreferences p =
VersionedAccountPreferences.forUser(id);
p.load(git);
DiffPreferencesInfo prefs = new DiffPreferencesInfo();
loadSection(p.getConfig(), UserConfigSections.DIFF, null, prefs,
DiffPreferencesInfo.defaults(), in);
return prefs;
}
}
private DiffPreferencesInfo readFromDb(Account.Id id)
throws OrmException {
AccountDiffPreference a = db.get().accountDiffPreferences().get(id);
return nullify(initFromDb(a));
}
static DiffPreferencesInfo initFromDb(AccountDiffPreference a) {
DiffPreferencesInfo prefs = DiffPreferencesInfo.defaults();
if (a != null) {
prefs.context = (int)a.getContext();
prefs.expandAllComments = a.isExpandAllComments();
prefs.hideLineNumbers = a.isHideLineNumbers();
prefs.hideTopMenu = a.isHideTopMenu();
prefs.ignoreWhitespace = PatchListKey.WHITESPACE_TYPES.inverse().get(
a.getIgnoreWhitespace().getCode());
prefs.intralineDifference = a.isIntralineDifference();
prefs.lineLength = a.getLineLength();
prefs.manualReview = a.isManualReview();
prefs.renderEntireFile = a.isRenderEntireFile();
prefs.retainHeader = a.isRetainHeader();
prefs.showLineEndings = a.isShowLineEndings();
prefs.showTabs = a.isShowTabs();
prefs.showWhitespaceErrors = a.isShowWhitespaceErrors();
prefs.skipDeleted = a.isSkipDeleted();
prefs.skipUncommented = a.isSkipUncommented();
prefs.syntaxHighlighting = a.isSyntaxHighlighting();
prefs.tabSize = a.getTabSize();
prefs.theme = a.getTheme();
prefs.hideEmptyPane = a.isHideEmptyPane();
prefs.autoHideDiffTableHeader = a.isAutoHideDiffTableHeader();
}
public short context;
public Boolean expandAllComments;
public Whitespace ignoreWhitespace;
public Boolean intralineDifference;
public int lineLength;
public Boolean manualReview;
public Boolean retainHeader;
public Boolean showLineEndings;
public Boolean showTabs;
public Boolean showWhitespaceErrors;
public Boolean skipDeleted;
public Boolean skipUncommented;
public Boolean syntaxHighlighting;
public Boolean hideTopMenu;
public Boolean autoHideDiffTableHeader;
public Boolean hideLineNumbers;
public Boolean renderEntireFile;
public Boolean hideEmptyPane;
public int tabSize;
public Theme theme;
return prefs;
}
private static DiffPreferencesInfo nullify(DiffPreferencesInfo prefs) {
prefs.expandAllComments = b(prefs.expandAllComments);
prefs.hideLineNumbers = b(prefs.hideLineNumbers);
prefs.hideTopMenu = b(prefs.hideTopMenu);
prefs.intralineDifference = b(prefs.intralineDifference);
prefs.manualReview = b(prefs.manualReview);
prefs.renderEntireFile = b(prefs.renderEntireFile);
prefs.retainHeader = b(prefs.retainHeader);
prefs.showLineEndings = b(prefs.showLineEndings);
prefs.showTabs = b(prefs.showTabs);
prefs.showWhitespaceErrors = b(prefs.showWhitespaceErrors);
prefs.skipDeleted = b(prefs.skipDeleted);
prefs.skipUncommented = b(prefs.skipUncommented);
prefs.syntaxHighlighting = b(prefs.syntaxHighlighting);
prefs.hideEmptyPane = b(prefs.hideEmptyPane);
prefs.autoHideDiffTableHeader = b(prefs.autoHideDiffTableHeader);
return prefs;
}
private static Boolean b(Boolean b) {
if (b == null) {
return null;
}
return b ? Boolean.TRUE : null;
}
}