Exemple #1
0
 def remove_stale_owners(self):
     """Remove any lock owners that have gone stale."""
     with self.lock:
         content = self._read()
         if 'owners' not in content:
             return False
         fresh_owners = []
         for owner in content['owners']:
             if 'client_name' in owner:
                 result = self.p4.run('clients', '-e', owner['client_name'])
                 LOG.debug3('remove_stale_owners(): clients matching %s: %s',
                            owner['client_name'], result)
                 if len(result) > 0:
                     fresh_owners.append(owner)
                 else:
                     pid = owner.get('process_id', 'unknown')
                     LOG.warning('stale p4key-lock %s for %s removed', pid, self._repo_name)
             else:
                 # client-less owner, cannot safely remove this entry
                 fresh_owners.append(owner)
         if len(fresh_owners) < len(content['owners']):
             if len(fresh_owners) == 0:
                 P4Key.delete(self.p4, self.owners_key)
             else:
                 content['owners'] = fresh_owners
                 self._write(content)
             return True
     return False
Exemple #2
0
def _delete_p4key(p4, name):
    """Attempt to delete p4key. Report and continue on error."""
    try:
        P4Key.delete(p4, name)
    except P4.P4Exception as e:
        if str(e).find("No such p4key") < 0:
            print('ERROR: Failed to delete p4key {name}: {e}'.format(name=name,
                                                                     e=str(e)))
Exemple #3
0
def _delete_old_init_p4keys(p4, server_id):
    """Remove the old host-specific initialization p4keys, if any."""
    names = []
    names.append("git-fusion-{}-init-started".format(server_id))
    names.append("git-fusion-{}-init-complete".format(server_id))
    with p4.at_exception_level(p4.RAISE_NONE):
        for name in names:
            P4Key.delete(p4, name)
Exemple #4
0
def _init_if_needed(p4, started_p4key, complete_p4key, func, nop_msg):
    """Call func to do initialization if keys are not set.

    Check that the completed p4key is non-zero, as that indicates that
    initialization has already been done.

    If neither the started nor complete key are set, set the started key,
    call the function, and finally set the complete key.

    If only the started key is set, there may be an initialization attempt in
    progress.  Give it a chance to complete before assuming it has failed and
    restarting the initialization.

    Arguments:
      p4 -- P4 API object
      started_p4key -- name of init started p4key
      complete_p4key -- name of init completed p4key
      func -- initialization function to be called, takes a P4 argument.
              Must be idempotent since it is possible initialization may
              be performed more than once.
      nop_msg -- message to report if no initialization is needed

    Return True if initialization performed, False it not needed.
    """
    if P4Key.is_set(p4, complete_p4key):
        # Short-circuit when there is nothing to be done.
        Verbosity.report(Verbosity.INFO, nop_msg)
        return False

    check_times = 5

    while True:
        # If initialization has not been started, start it now.
        # Check before set to avoid a needless database write,
        # especially since this is run on every pull and push.
        if not P4Key.is_set(p4, started_p4key):
            if P4Key.acquire(p4, started_p4key):
                func(p4)
                # Set a p4key so we will not repeat initialization later.
                P4Key.acquire(p4, complete_p4key)
                return True

        # If initialization has been completed, we're done.
        if P4Key.is_set(p4, complete_p4key):
            Verbosity.report(Verbosity.INFO, nop_msg)
            return False

        # Another process started initialization.  It may still be working on
        # it or it may have died.  Wait a bit to give it a chance to complete.
        time.sleep(1)
        check_times -= 1
        if not check_times:
            # Other process failed to finish perhaps.
            # Steal the "lock" and do the init ourselves.
            P4Key.delete(p4, started_p4key)
        elif check_times < 0:
            raise RuntimeError(_('error: unable to aquire lock for initialization'))
Exemple #5
0
 def do_release(self):
     """Release a held lock."""
     label = "releasing p4key-lock for {}".format(self._repo_name)
     wait_reporter = p4gf_log.LongWaitReporter(label, LOG)
     while True:
         with self.lock:
             content = self._read()
             if self.ignore_pending_acquire or 'acquire_pending' not in content:
                 content = self._remove_self(content)
                 if content is None:
                     P4Key.delete(self.p4, self.owners_key)
                 else:
                     self._write(content)
                     if self._transfer_complete_cb:
                         self._transfer_complete_cb()
                 if self._post_lock_release_cb:
                     self._post_lock_release_cb()
                 td = time.time() - self._acquire_time
                 LOG.debug("p4key-lock released: %s after %s ms", self._repo_name, td)
                 return
         wait_reporter.been_waiting()
         time.sleep(_RETRY_PERIOD)
def main():
    """Parse the command-line arguments and report on locks."""
    # pylint: disable=too-many-statements
    desc = _("Report the currently held locks in Git Fusion.")
    parser = p4gf_util.create_arg_parser(desc=desc)
    parser.add_argument('--test',
                        action='store_true',
                        help=_('invoke test mode, acquire locks and report'))
    parser.add_argument(
        '--test2',
        action='store_true',
        help=_(
            'invoke test mode, acquire locks and report, set dead processes.'))
    args = parser.parse_args()

    p4gf_util.has_server_id_or_exit()
    server_id = p4gf_util.get_server_id()
    p4 = p4gf_create_p4.create_p4_temp_client()
    if not p4:
        sys.exit(1)
    print("Connecting to P4PORT={} as P4USER={}".format(p4.port, p4.user))
    if args.test or args.test2:
        repo_name = "p4gf_test_status_repo"
        status_key_name = p4gf_p4key.calc_repo_status_p4key_name(
            repo_name, None)
        p4gf_p4key.set(p4, status_key_name, 'Push 1 completed successfully')
        pushid_key_name = p4gf_p4key.calc_repo_push_id_p4key_name(repo_name)
        p4gf_p4key.set(p4, pushid_key_name, '1')
        # create a process and kill it and set its dead pid as a RepoLock owner below.

        if args.test:
            # A test with nothing stale
            with ExitStack() as stack:
                stack.enter_context(p4gf_lock.ReviewsLock(p4))
                stack.enter_context(p4gf_lock.RepoLock(p4, repo_name))
                stack.enter_context(p4gf_git_repo_lock.read_lock(repo_name))
                stack.enter_context(
                    p4gf_git_repo_lock.write_lock(repo_name, upgrade=True))
                print_lock_status(p4, server_id)

        else:  # if args.test2
            # Now a test with some DEAD processes and a stale view Lock
            dead_process = subprocess.Popen(['echo', 'x'],
                                            stdout=subprocess.DEVNULL)
            dead_process.kill()
            while dead_process.returncode is None:
                dead_process.communicate()
            lock2 = None
            with ExitStack() as stack:
                stack.enter_context(p4gf_lock.ReviewsLock(p4))
                # first lock owner
                lock1 = p4gf_lock.RepoLock(p4, repo_name)
                # second lock owner with same group_id and a dead pid
                lock2 = p4gf_lock.RepoLock(p4,
                                           repo_name,
                                           group_id=lock1.group_id)
                lock2.process_id = dead_process.pid
                # acquire the first RepoLock
                stack.enter_context(lock1)
                # Use low level method to add this DEAD pid to the group's lock owners
                lock2.do_acquire()
                stack.enter_context(p4gf_git_repo_lock.read_lock(repo_name))
                stack.enter_context(
                    p4gf_git_repo_lock.write_lock(repo_name, upgrade=True))
                print("Test 1:")
                print_lock_status(p4, server_id)
                p4gf_p4key.set(p4, pushid_key_name, '2')
                p4gf_p4key.set(p4, status_key_name,
                               'Push 2 failed: some error')
                # Finally lets set the P4GF_P4KEY_LOCK_VIEW - the least likley to be stale
                p4gf_p4key.set(p4, lock2.lock_key, '1')
                print("Test 2:")
                print_lock_status(p4, server_id)
                # Cant exit the ExistStack unless we clean this
                p4gf_p4key.delete(p4, lock2.lock_key)
            # Clean up this lock so the test may be run again
            p4gf_p4key.delete(p4, lock2.owners_key)
        # remove test keys
        p4gf_p4key.delete(p4, status_key_name)
        p4gf_p4key.delete(p4, pushid_key_name)
    else:
        print_lock_status(p4, server_id)
Exemple #7
0
 def do_release(self):
     """First delete the owner key, then release the lock."""
     P4Key.delete(self.p4, p4gf_const.P4GF_REVIEWS_COMMON_LOCK_OWNER)
     super(ReviewsLock, self).do_release()
Exemple #8
0
 def do_release(self):
     """Release a held lock."""
     P4Key.delete(self.p4, self.lock_key)
Exemple #9
0
def unset_server_id_p4key(server_id):
    """Delete the server-id p4key."""
    if server_id:
        P4Key.delete(p4, p4gf_const.P4GF_P4KEY_SERVER_ID + server_id)
def delete_all(args, p4, metrics):
    """Remove all Git Fusion clients, as well as the object cache.

    Keyword arguments:
        args -- parsed command line arguments
        p4   -- Git user's Perforce client
    """
    # pylint:disable=too-many-branches
    p4.user = p4gf_const.P4GF_USER
    group_list = [p4gf_const.P4GF_GROUP_PULL, p4gf_const.P4GF_GROUP_PUSH]
    print(_('Connected to {P4PORT}').format(P4PORT=p4.port))
    print_verbose(args, _('Scanning for Git Fusion clients...'))
    client_name = p4gf_util.get_object_client_name()
    locks = _lock_all_repos(p4)
    if args.delete:
        was_prevented = _prevent_access(p4)
    else:
        was_prevented = None
    delete_clients(args, p4, metrics)
    # Retrieve the names of the initialization/upgrade "lock" p4keys.
    p4keys = [
        p4gf_const.P4GF_P4KEY_ALL_PENDING_MB,
        p4gf_const.P4GF_P4KEY_ALL_REMAINING_MB
    ]
    # Key patterns NOT published in p4gf_const because they have trailing *
    # wildcards and it's not worth cluttering p4gf_const for this one use.
    p4key_patterns = [
        'git-fusion-init-started*', 'git-fusion-init-complete*',
        'git-fusion-upgrade-started*', 'git-fusion-upgrade-complete*',
        'git-fusion-index-*'
    ]
    for p4key_pattern in p4key_patterns:
        d = P4Key.get_all(p4, p4key_pattern)
        p4keys.extend(sorted(d.keys()))
    localroot = get_p4gf_localroot(p4)
    if not args.delete:
        if localroot:
            if args.no_obliterate:
                print(NTR('p4 sync -f #none'))
            else:
                print(NTR('p4 client -f -d {}').format(client_name))
                print(NTR('rm -rf {}').format(localroot))
        if not args.no_obliterate:
            print(
                NTR('p4 obliterate -hay //{}/objects/...').format(
                    p4gf_const.P4GF_DEPOT))
        for p4key in p4keys:
            print(NTR('p4 key -d {}').format(p4key))
        for group in group_list:
            print(NTR('p4 group -a -d {}').format(group))
    else:
        if localroot:
            if not args.no_obliterate:
                # Need this in order to use --gc later on
                # client should not exist; this is likely a NOOP
                p4gf_util.p4_client_df(p4, client_name)
                metrics.clients += 1
                print_verbose(
                    args,
                    _("Deleting client '{client_name}'s workspace...").format(
                        client_name=client_name))
                _remove_local_root(localroot)
        _delete_cache(args, p4, metrics)
        print_verbose(args, _('Removing initialization p4keys...'))
        for p4key in p4keys:
            delete_p4key(p4, p4key, metrics)
        for group in group_list:
            delete_group(args, p4, group, metrics)
    _release_locks(locks)
    if was_prevented is not None:
        if was_prevented != '0':
            P4Key.set(p4, p4gf_const.P4GF_P4KEY_PREVENT_NEW_SESSIONS,
                      was_prevented)
        else:
            P4Key.delete(p4, p4gf_const.P4GF_P4KEY_PREVENT_NEW_SESSIONS)