Class GroupNameNotes


  • public class GroupNameNotes
    extends VersionedMetaData
    An enforcer of unique names for groups in NoteDb.

    The way groups are stored in NoteDb (see GroupConfig) doesn't enforce unique names, even though groups in Gerrit must not have duplicate names. The storage format doesn't allow to quickly look up whether a name has already been used either. That's why we additionally keep a map of name/UUID pairs and manage it with this class.

    To claim the name for a new group, create an instance of GroupNameNotes via forNewGroup(Project.NameKey, Repository, AccountGroup.UUID, AccountGroup.NameKey) and call commit(MetaDataUpdate) on it. For renaming, call forRename(Project.NameKey, Repository, AccountGroup.UUID, AccountGroup.NameKey, AccountGroup.NameKey) and also commit the returned GroupNameNotes. Both times, the creation of the GroupNameNotes will fail if the (new) name is already used. Committing the GroupNameNotes is necessary to make the adjustments for real.

    The map has an additional benefit: We can quickly iterate over all group name/UUID pairs without having to load all groups completely (which is costly).

    Internal details

    The map of names is represented by Git notes. They are stored on the branch RefNames.REFS_GROUPNAMES. Each commit on the branch reflects one moment in time of the complete map.

    As key for the notes, we use the SHA-1 of the name. As data, they contain a text version of a JGit Config file. That config file has two entries:

    • the name of the group (as clear text)
    • the UUID of the group which currently has this name
    • Method Detail

      • forRename

        public static GroupNameNotes forRename​(Project.NameKey projectName,
                                               org.eclipse.jgit.lib.Repository repository,
                                               AccountGroup.UUID groupUuid,
                                               AccountGroup.NameKey oldName,
                                               AccountGroup.NameKey newName)
                                        throws IOException,
                                               org.eclipse.jgit.errors.ConfigInvalidException,
                                               com.google.gerrit.exceptions.DuplicateKeyException
        Creates an instance of GroupNameNotes for use when renaming a group.

        Note: The returned instance of GroupNameNotes has to be committed via commit(MetaDataUpdate) in order to claim the new name and free up the old one.

        Parameters:
        projectName - the name of the project which holds the commits of the notes
        repository - the repository which holds the commits of the notes
        groupUuid - the UUID of the group which is renamed
        oldName - the current name of the group
        newName - the new name of the group
        Returns:
        an instance of GroupNameNotes configured for a specific renaming of a group
        Throws:
        IOException - if the repository can't be accessed for some reason
        org.eclipse.jgit.errors.ConfigInvalidException - if the note for the specified group doesn't exist or is in an invalid state
        com.google.gerrit.exceptions.DuplicateKeyException - if a group with the new name already exists
      • forNewGroup

        public static GroupNameNotes forNewGroup​(Project.NameKey projectName,
                                                 org.eclipse.jgit.lib.Repository repository,
                                                 AccountGroup.UUID groupUuid,
                                                 AccountGroup.NameKey groupName)
                                          throws IOException,
                                                 org.eclipse.jgit.errors.ConfigInvalidException,
                                                 com.google.gerrit.exceptions.DuplicateKeyException
        Creates an instance of GroupNameNotes for use when creating a new group.

        Note: The returned instance of GroupNameNotes has to be committed via commit(MetaDataUpdate) in order to claim the new name.

        Parameters:
        projectName - the name of the project which holds the commits of the notes
        repository - the repository which holds the commits of the notes
        groupUuid - the UUID of the new group
        groupName - the name of the new group
        Returns:
        an instance of GroupNameNotes configured for a specific group creation
        Throws:
        IOException - if the repository can't be accessed for some reason
        org.eclipse.jgit.errors.ConfigInvalidException - in no case so far
        com.google.gerrit.exceptions.DuplicateKeyException - if a group with the new name already exists
      • loadGroup

        public static Optional<GroupReference> loadGroup​(org.eclipse.jgit.lib.Repository repository,
                                                         AccountGroup.NameKey groupName)
                                                  throws IOException,
                                                         org.eclipse.jgit.errors.ConfigInvalidException
        Loads the GroupReference (name/UUID pair) for the group with the specified name.
        Parameters:
        repository - the repository which holds the commits of the notes
        groupName - the name of the group
        Returns:
        the corresponding GroupReference if a group/note with the given name exists
        Throws:
        IOException - if the repository can't be accessed for some reason
        org.eclipse.jgit.errors.ConfigInvalidException - if the note for the specified group is in an invalid state
      • loadAllGroups

        public static com.google.common.collect.ImmutableList<GroupReference> loadAllGroups​(org.eclipse.jgit.lib.Repository repository)
                                                                                     throws IOException,
                                                                                            org.eclipse.jgit.errors.ConfigInvalidException
        Loads the GroupReferences (name/UUID pairs) for all groups.

        Even though group UUIDs should be unique, this class doesn't enforce it. For this reason, it's technically possible that two of the GroupReferences have a duplicate UUID but a different name. In practice, this shouldn't occur unless we introduce a bug in the future.

        Parameters:
        repository - the repository which holds the commits of the notes
        Returns:
        the GroupReferences of all existing groups/notes
        Throws:
        IOException - if the repository can't be accessed for some reason
        org.eclipse.jgit.errors.ConfigInvalidException - if one of the notes is in an invalid state
      • updateAllGroups

        public static void updateAllGroups​(org.eclipse.jgit.lib.Repository repository,
                                           org.eclipse.jgit.lib.ObjectInserter inserter,
                                           org.eclipse.jgit.lib.BatchRefUpdate bru,
                                           Collection<GroupReference> groupReferences,
                                           org.eclipse.jgit.lib.PersonIdent ident)
                                    throws IOException
        Replaces the map of name/UUID pairs with a new version which matches exactly the passed GroupReferences.

        All old entries are discarded and replaced by the new ones.

        This operation also works if the previous map has invalid entries or can't be read anymore.

        Note: This method doesn't flush the ObjectInserter. It doesn't execute the BatchRefUpdate either.

        Parameters:
        repository - the repository which holds the commits of the notes
        inserter - an ObjectInserter for that repository
        bru - a BatchRefUpdate to which this method adds commands
        groupReferences - all GroupReferences (name/UUID pairs) which should be contained in the map of name/UUID pairs
        ident - the PersonIdent which is used as author and committer for commits
        Throws:
        IOException - if the repository can't be accessed for some reason
      • onLoad

        protected void onLoad()
                       throws IOException,
                              org.eclipse.jgit.errors.ConfigInvalidException
        Description copied from class: VersionedMetaData
        Set up the metadata, parsing any state from the loaded revision.
        Specified by:
        onLoad in class VersionedMetaData
        Throws:
        IOException
        org.eclipse.jgit.errors.ConfigInvalidException
      • onSave

        protected boolean onSave​(org.eclipse.jgit.lib.CommitBuilder commit)
                          throws IOException,
                                 org.eclipse.jgit.errors.ConfigInvalidException
        Description copied from class: VersionedMetaData
        Save any changes to the metadata in a commit.
        Specified by:
        onSave in class VersionedMetaData
        Returns:
        true if the commit should proceed, false to abort.
        Throws:
        IOException
        org.eclipse.jgit.errors.ConfigInvalidException
      • getNoteKey

        public static org.eclipse.jgit.lib.ObjectId getNoteKey​(AccountGroup.NameKey groupName)