sapling/edenscm/hgext/commitcloud/obsmarkers.py
Mark Thomas 7359c3df5d commitcloud: refactor sync processing
Summary:
Refactor how commit cloud sync works.

Sync is simplified by delegating backup processing to the existing backup code.
This happens first, which means the user's work is backed up earlier, and the
sync processing can assume that all backed up commits are available in the
cloud storage.

Sync no longer attempts to handle the case where cloud storage has changed.
Instead, backup processing should ensure that all local commits are backed up
to the current cloud storage.

If a commit can't be backed up, then treat this as a normal failure to
sync and ignore that commit for this sync attempt.  If a commit can't be
downloaded from the server then the sync fails.

Reviewed By: mitrandir77

Differential Revision: D15295499

fbshipit-source-id: d371c5bf0daedbbe42e8c7d4a0c3d1a40c21a36f
2019-05-20 06:19:48 -07:00

74 lines
2.8 KiB
Python

# Copyright 2018 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from edenscm.mercurial import lock as lockmod, obsolete
# Obsmarker syncing.
#
# To avoid lock interactions between transactions (which may add new obsmarkers)
# and sync (which wants to clear the obsmarkers), we use a two-stage process to
# sync obsmarkers.
#
# When a transaction completes, we append any new obsmarkers to the pending
# obsmarker file. This is protected by the obsmarkers lock.
#
# When a sync operation starts, we transfer these obsmarkers to the syncing
# obsmarker file. This transfer is also protected by the obsmarkers lock, but
# the transfer should be very quick as it's just moving a small amount of data.
#
# The sync process can upload the syncing obsmarkers at its leisure. The
# syncing obsmarkers file is protected by the infinitepush backup lock.
_obsmarkerslockname = "commitcloudpendingobsmarkers.lock"
_obsmarkerslocktimeout = 2
_obsmarkerspending = "commitcloudpendingobsmarkers"
_obsmarkerssyncing = "commitcloudsyncingobsmarkers"
def addpendingobsmarkers(repo, markers):
with lockmod.lock(repo.svfs, _obsmarkerslockname, timeout=_obsmarkerslocktimeout):
with repo.svfs.open(_obsmarkerspending, "ab") as f:
offset = f.tell()
# offset == 0: new file - add the version header
data = b"".join(
obsolete.encodemarkers(markers, offset == 0, obsolete._fm1version)
)
f.write(data)
def getsyncingobsmarkers(repo):
"""Transfers any pending obsmarkers, and returns all syncing obsmarkers.
The caller must hold the backup lock.
"""
# Move any new obsmarkers from the pending file to the syncing file
with lockmod.lock(repo.svfs, _obsmarkerslockname, timeout=_obsmarkerslocktimeout):
if repo.svfs.exists(_obsmarkerspending):
with repo.svfs.open(_obsmarkerspending) as f:
_version, markers = obsolete._readmarkers(f.read())
with repo.sharedvfs.open(_obsmarkerssyncing, "ab") as f:
offset = f.tell()
# offset == 0: new file - add the version header
data = b"".join(
obsolete.encodemarkers(markers, offset == 0, obsolete._fm1version)
)
f.write(data)
repo.svfs.unlink(_obsmarkerspending)
# Load the syncing obsmarkers
markers = []
if repo.sharedvfs.exists(_obsmarkerssyncing):
with repo.sharedvfs.open(_obsmarkerssyncing) as f:
_version, markers = obsolete._readmarkers(f.read())
return markers
def clearsyncingobsmarkers(repo):
"""Clears all syncing obsmarkers. The caller must hold the backup lock."""
repo.sharedvfs.tryunlink(_obsmarkerssyncing)