Current File : //usr/lib64/python3.6/site-packages/borg/__pycache__/repository.cpython-36.pyc
3

up�d.�@s�ddlZddlZddlZddlZddlZddlZddlZddlmZm	Z	ddl
mZddlm
Z
ddlmZddlmZddlmZdd	lTdd
lmZddlmZmZmZmZmZddlmZdd
lmZddlmZddlmZddlm Z m!Z!ddlm"Z"ddl#m$Z$m%Z%m&Z&ddl'm(Z(ddl)m*Z*ddl+m,Z,m-Z-m.Z.m/Z/ddl0m1Z1ddl2m3Z3m4Z4e(e5�Z'dZ6e7e6�Z8dZ9e7e9�e8k�s�t:�dZ;dZ<dZ=dZ>eee?�Z@Gdd�d�ZAGdd�d�ZBeBjCjDd k�s�t:�dS)!�N)�hexlify�	unhexlify)�defaultdict)�ConfigParser)�datetime)�partial)�islice�)�*)�NSIndex)�Error�ErrorWithTraceback�IntegrityError�format_file_size�parse_file_size)�Location)�ProgressIndicatorPercent)�
bin_to_hex)�hostname_is_unique)�secure_erase�safe_unlink)�msgpack)�Lock�	LockError�
LockErrorT)�
create_logger)�LRUCache)�SaveFile�SyncFile�sync_dir�safe_fadvise)�crc32)�IntegrityCheckedFile�FileIntegrityErrorsBORG_SEGsATTICSEG��c@sbeZdZdZGdd�de�ZGdd�de�ZGdd�de�ZGdd	�d	e�ZGd
d�de�Z	Gdd
�d
e�Z
Gdd�de�ZGdd�de�Z
Gdd�de�ZGdd�de�ZGdd�de�Zd{dd�Zdd�Zdd �Zd!d"�Zd#d$�Zed%d&��Zed'd(��Zd)d*�Zd+d,�Zd-d.�Zd/d0�Zd1d2�Zd3d4�Zd5d6�Z d7d8�Z!d9d:�Z"d;d<�Z#d=d>�Z$d?d@�Z%dAdB�Z&d|dCdD�Z'dEdF�Z(d}dGdH�Z)dIdJ�Z*d~dKdL�Z+ddMdN�Z,dOdP�Z-dQdR�Z.dSdT�Z/dUdV�Z0dWdX�Z1d�dYdZ�Z2d[d\�Z3d�d]d^�Z4d_d`�Z5dadb�Z6dcdd�Z7dedf�Z8dgdh�Z9d�didj�Z:d�dkdl�Z;dmdn�Z<d�dodp�Z=d�dqdr�Z>d�dsdt�Z?dudv�Z@d�dwdx�ZAdydz�ZBdS)��
Repositorya�
    Filesystem based transactional key value store

    Transactionality is achieved by using a log (aka journal) to record changes. The log is a series of numbered files
    called segments. Each segment is a series of log entries. The segment number together with the offset of each
    entry relative to its segment start establishes an ordering of the log entries. This is the "definition" of
    time for the purposes of the log.

    Log entries are either PUT, DELETE or COMMIT.

    A COMMIT is always the final log entry in a segment and marks all data from the beginning of the log until the
    segment ending with the COMMIT as committed and consistent. The segment number of a segment ending with a COMMIT
    is called the transaction ID of that commit, and a segment ending with a COMMIT is called committed.

    When reading from a repository it is first checked whether the last segment is committed. If it is not, then
    all segments after the last committed segment are deleted; they contain log entries whose consistency is not
    established by a COMMIT.

    Note that the COMMIT can't establish consistency by itself, but only manages to do so with proper support from
    the platform (including the hardware). See platform.base.SyncFile for details.

    A PUT inserts a key-value pair. The value is stored in the log entry, hence the repository implements
    full data logging, meaning that all data is consistent, not just metadata (which is common in file systems).

    A DELETE marks a key as deleted.

    For a given key only the last entry regarding the key, which is called current (all other entries are called
    superseded), is relevant: If there is no entry or the last entry is a DELETE then the key does not exist.
    Otherwise the last PUT defines the value of the key.

    By superseding a PUT (with either another PUT or a DELETE) the log entry becomes obsolete. A segment containing
    such obsolete entries is called sparse, while a segment containing no such entries is called compact.

    Sparse segments can be compacted and thereby disk space freed. This destroys the transaction for which the
    superseded entries where current.

    On disk layout:

    dir/README
    dir/config
    dir/data/<X // SEGMENTS_PER_DIR>/<X>
    dir/index.X
    dir/hints.X

    File system interaction
    -----------------------

    LoggedIO generally tries to rely on common behaviours across transactional file systems.

    Segments that are deleted are truncated first, which avoids problems if the FS needs to
    allocate space to delete the dirent of the segment. This mostly affects CoW file systems,
    traditional journaling file systems have a fairly good grip on this problem.

    Note that deletion, i.e. unlink(2), is atomic on every file system that uses inode reference
    counts, which includes pretty much all of them. To remove a dirent the inodes refcount has
    to be decreased, but you can't decrease the refcount before removing the dirent nor can you
    decrease the refcount after removing the dirent. File systems solve this with a lock,
    and by ensuring it all stays within the same FS transaction.

    Truncation is generally not atomic in itself, and combining truncate(2) and unlink(2) is of
    course never guaranteed to be atomic. Truncation in a classic extent-based FS is done in
    roughly two phases, first the extents are removed then the inode is updated. (In practice
    this is of course way more complex).

    LoggedIO gracefully handles truncate/unlink splits as long as the truncate resulted in
    a zero length file. Zero length segments are considered to not exist, while LoggedIO.cleanup()
    will still get rid of them.
    c@seZdZdZdS)zRepository.DoesNotExistzRepository {} does not exist.N)�__name__�
__module__�__qualname__�__doc__�r+r+�"/usr/lib64/python3.6/repository.py�DoesNotExist{sr-c@seZdZdZdS)zRepository.AlreadyExistsz"A repository already exists at {}.N)r'r(r)r*r+r+r+r,�
AlreadyExists~sr.c@seZdZdZdS)zRepository.PathAlreadyExistsz!There is already something at {}.N)r'r(r)r*r+r+r+r,�PathAlreadyExists�sr/c@seZdZdZdS)z!Repository.ParentPathDoesNotExistz:The parent path of the repo directory [{}] does not exist.N)r'r(r)r*r+r+r+r,�ParentPathDoesNotExist�sr0c@seZdZdZdS)zRepository.InvalidRepositoryz0{} is not a valid repository. Check repo config.N)r'r(r)r*r+r+r+r,�InvalidRepository�sr1c@seZdZdZdS)z"Repository.InvalidRepositoryConfigz?{} does not have a valid configuration. Check repo config [{}].N)r'r(r)r*r+r+r+r,�InvalidRepositoryConfig�sr2c@seZdZdZdS)zRepository.AtticRepositoryz8Attic repository detected. Please run "borg upgrade {}".N)r'r(r)r*r+r+r+r,�AtticRepository�sr3c@seZdZdZdS)zRepository.CheckNeededz3Inconsistency detected. Please run "borg check {}".N)r'r(r)r*r+r+r+r,�CheckNeeded�sr4cs eZdZdZ�fdd�Z�ZS)zRepository.ObjectNotFoundz.Object with key {} not found in repository {}.cs$t|t�rt|�}t�j||�dS)N)�
isinstance�bytesr�super�__init__)�self�idZrepo)�	__class__r+r,r8�s
z"Repository.ObjectNotFound.__init__)r'r(r)r*r8�
__classcell__r+r+)r;r,�ObjectNotFound�sr=c@seZdZdZdS)z%Repository.InsufficientFreeSpaceErrorzNInsufficient free space to complete transaction (required: {}, available: {}).N)r'r(r)r*r+r+r+r,�InsufficientFreeSpaceError�sr>c@seZdZdZdS)zRepository.StorageQuotaExceededzJThe storage quota ({}) has been exceeded ({}). Try deleting some archives.N)r'r(r)r*r+r+r+r,�StorageQuotaExceeded�sr?FNTc

Cs�tjj|�|_td|j�|_d|_d|_d|_i|_d|_	||_
||_||_d|_
||_||_||_d|_d|_||_|	|_dS)Nz	file://%sFr)�os�path�abspathrZ	_location�io�lock�index�shadow_index�_active_txn�	lock_wait�do_lock�	do_create�created�	exclusive�append_only�
storage_quota�storage_quota_use�transaction_doomed�check_segment_magic�make_parent_dirs)
r9rA�createrLrHrDrMrNrQrRr+r+r,r8�s$zRepository.__init__cCs|jr|j�dstd��dS)NFz&cleanup happened in Repository.__del__)rD�close�AssertionError)r9r+r+r,�__del__�szRepository.__del__cCsd|jj|jfS)Nz<%s %s>)r;r'rA)r9r+r+r,�__repr__�szRepository.__repr__cCs@|jrd|_|j|j�d|_|j|jt|j�|j|jd�|S)NFT)rHrD)	rJrSrArK�open�boolrLrHrI)r9r+r+r,�	__enter__�szRepository.__enter__cCsR|dk	rF|tko|jtjk}|jr6|r6tjd�d}nd}|j|d�|j�dS)NzGNo space left on device, cleaning up partial transaction to free space.TF)�cleanup)�OSError�errnoZENOSPCrG�logger�warning�	_rollbackrT)r9�exc_typeZexc_valZexc_tbZno_space_left_on_devicer[r+r+r,�__exit__�s

zRepository.__exit__cCs
t|j�S)N)rr:)r9r+r+r,�id_str�szRepository.id_strcCsTy:ttjj|d�d��}|jd�}d|kp0d|kSQRXWntk
rNdSXdS)z;Check whether there is already a Borg repository at *path*.�README�rb�dsBorg Backup repositorysBorg repositoryNF)rXr@rA�join�readr\)rA�fdZreadme_headr+r+r,�
is_repository�s
zRepository.is_repositorycCs�ytj|�}Wntk
r"Yn8X|j|�r8|j|��tj|j�sPtj|�rZ|j|��x>|}tj	j
tj	j|tj��}||kr�P|j|�r\|j|��q\WdS)a�
        Raise an exception if a repository already exists at *path* or any parent directory.

        Checking parent directories is done for two reasons:
        (1) It's just a weird thing to do, and usually not intended. A Borg using the "parent" repository
            may be confused, or we may accidentally put stuff into the "data/" or "data/<n>/" directories.
        (2) When implementing repository quotas (which we currently don't), it's important to prohibit
            folks from creating quota-free repositories. Since no one can create a repository within another
            repository, user's can only use the quota'd repository, when their --restrict-to-path points
            at the user's repository.
        N)
r@�stat�FileNotFoundErrorrjr.�S_ISDIR�st_mode�listdirr/rArBrg�pardir)r9rA�stZ
previous_pathr+r+r,�check_can_create_repository�s



z&Repository.check_can_create_repositorycCsv|j|�|jr.tjj|tj�}tj|dd�tjj|�sxytj|�Wn.t	k
rv}z|j
|�|�WYdd}~XnXttjj|d�d��}|jt
�WdQRXtjtjj|d��tdd�}|jd�|jdd	d
�|jddtt��|jddtt��|jdd
tt|j���|j�r2|jddt|j��n|jddd�|jddd�|jddttjd���|j||�dS)z0Create a new empty repository at `path`
        T)�exist_okNrd�w�data)�
interpolation�
repository�version�1�segments_per_dir�max_segment_sizerMrN�0�additional_free_spacer:� )rrrRr@rArgrp�makedirs�exists�mkdirrlr0rX�writeZREPOSITORY_READMErZadd_section�set�strZDEFAULT_SEGMENTS_PER_DIRZDEFAULT_MAX_SEGMENT_SIZE�intrMrNr�urandom�save_config)r9rA�parent_path�errri�configr+r+r,rS
s0


zRepository.createc CsTtjj|d�}tjj|d�}tjj|�r>tjd�t|dd�tjj|�r�d}ytj||�Wnntk
r�}z6|j	t	j
t	jt	jt	j
t	jt	jfkr�tj|�n�WYdd}~Xntk
r�tj|�YnXy"t|��}|j|�WdQRXWnDtk
�r4}z&|j�r�tjd|j|jf�WYdd}~XnXtjj|��rPt|dd�dS)Nr�z
config.oldz=Old config file not securely erased on previous config updateT)Zavoid_collateral_damagez�Failed to securely erase old repository config file (hardlinks not supported). Old repokey data, if any, might persist on physical storage.zT%s: Failed writing to '%s'. This is expected when working on read-only repositories.)r@rArg�isfiler^r_r�linkr\r]ZEMLINKZENOSYSZEPERMZEACCESZENOTSUPZEIO�AttributeErrorrr��PermissionErrorrI�strerror�filename)r9rAr�Zconfig_pathZold_config_pathZlink_error_msg�erir+r+r,r�*s2
"
"zRepository.save_configcCs8|js
t�|jd�}|jjdd|�|j|j|j�dS)Nzutf-8rw�key)r�rU�decoder�r�rA)r9�keydatar+r+r,�save_keyMs

zRepository.save_keycCs |jjdddd�j�}|jd�S)Nrwr��)�fallbackzutf-8)r��get�strip�encode)r9r�r+r+r,�load_keySszRepository.load_keycCsp|jr|jj�rtd��tjj|jd�}y,t|d��}tj	t
|j��dd�SQRXWntk
rjdSXdS)Nz-bug in code, exclusive lock should exist here�nonce�r�big)�	byteorder)
rIrD�got_exclusive_lockrUr@rArgrXr��
from_bytesrrhrl)r9�
nonce_pathrir+r+r,�get_free_nonceXs zRepository.get_free_noncecCs�|jr|jj�rtd��|j�|kr.td��tjj|jd�}y4t	|dd��}|j
t|jddd���WdQRXWn@t
k
r�}z$|jr��tjd	|j|jf�WYdd}~XnXdS)
Nz-bug in code, exclusive lock should exist herez6nonce space reservation with mismatched previous stater�F)�binary�r�)r�zT%s: Failed writing to '%s'. This is expected when working on read-only repositories.)rIrDr�rUr��	Exceptionr@rArgrr�r�to_bytesr�r^r_r�r�)r9Znext_unreservedZstart_noncer�rir�r+r+r,�commit_nonce_reservationcs&z#Repository.commit_nonce_reservationcCsB|jrt|jd��|j�tjtjj|jd��tj|j�dS)z.Destroy the repository at `self.path`
        z is in append-only moder�N)	rM�
ValueErrorrArTr@�removerg�shutilZrmtree)r9r+r+r,�destroyts
zRepository.destroycs2t�fdd�tj�j�D��}|r*|dSdSdS)Nc3sT|]L}|jd�r|dd�j�rtjtjj�j|��jdkrt|dd��VqdS)zindex.�Nr)�
startswith�isdigitr@rkrArg�st_sizer�)�.0�fn)r9r+r,�	<genexpr>~sz6Repository.get_index_transaction_id.<locals>.<genexpr>r	���)�sortedr@rorA)r9�indicesr+)r9r,�get_index_transaction_id}s
z#Repository.get_index_transaction_idcCsh|j�}|jj�}|dk	r6|dkr6d|j}|j|��||krd|dk	rT||krTd}n|}|j||�dS)Nz,%s" - although likely this is "beyond repair)r�rC�get_segments_transaction_idrAr4�replay_segments)r9�index_transaction_id�segments_transaction_id�msgZreplay_fromr+r+r,�check_transaction�s


zRepository.check_transactioncCs|j�|j�S)N)r�r�)r9r+r+r,�get_transaction_id�szRepository.get_transaction_idcCsttjj|jd��j�dS)NrD)rr@rArg�
break_lock)r9r+r+r,r��szRepository.break_lockcCs|jdk	r|jj||�dS)N)rD�migrate_lock)r9Zold_idZnew_idr+r+r,r��s
zRepository.migrate_lockc	CsB||_ytj|�}Wntk
r2|j|��YnXtj|j�sJ|j|��|rrttjj	|d�||t
�d�j�|_nd|_t
dd�|_y0ttjj	|jd���}|jj|�WdQRXWn(tk
r�|j�|j|j��YnXd|jj�k�r|j�|j|d��|jjdd�}|dk�r2|j�|j|d	|��t|jjdd
��|_|jtk�rj|j�|j|dt��|jjdd�|_t|jjdd
dd��|_|j�p�|jjdddd�|_|jdk�r�t|jjdddd��|_t|jjdd�j��|_ t!|j|j|j�|_"|j#�r>|j"j$�}|dk	�r>|j"j%|�t&k�r>|j�|j'|��dS)NrD)ZtimeoutZkill_stale_locks)rvr�rwzno repository section foundrxr	z;repository version %d is not supported by this borg versionr{zmax_segment_size >= %drzr}r)r�rMFrNr:)(rAr@rkrlr-rmrnr1rrgr�acquirerDrr�rXZ	read_filerTZsectionsr2Zgetintrr�r{ZMAX_SEGMENT_SIZE_LIMITrzr}rMZ
getbooleanrNrr�r:�LoggedIOrCrQ�get_latest_segment�get_segment_magic�ATTIC_MAGICr3)	r9rArLrHrDrqriZrepo_version�segmentr+r+r,rX�sT
$


zRepository.opencCs0|jr,|jr|jj�d|_|jj�d|_dS)N)rDrCrT�release)r9r+r+r,rT�s

zRepository.closecCsT|jr|j}|j�|�|j�|j�|jj�|js@|j�|j�|j�dS)zCommit transaction
        N)	rP�rollback�check_free_space�log_storage_quotarC�write_commitrM�compact_segments�write_index)r9�
save_spaceZ	exceptionr+r+r,�commit�s
zRepository.commitcCs�d|}tjj|j|�}y$t|d��}tj|�}WdQRXWntk
rPdSX|jd�dkrxtj	d|jd�|�dS||j
�S)Nzintegrity.%dresversionr$z'Unknown integrity data version %r in %s)r@rArgrXr�unpackrlr�r^r_r�)r9�transaction_idr��integrity_fileZintegrity_pathri�	integrityr+r+r,�_read_integrity�szRepository._read_integritycCs�|dkrt�Stjj|jd|�}|j|d�}y$t|d|d��}tj|�SQRXWnbttt	fk
r�}z@t
jd|�tj|�|s��|j
|j��|j�|j|j��Sd}~XnXdS)Nzindex.%dsindexF)r��integrity_datazARepository index missing or corrupted, trying to recover from: %s)rr@rArgr�r"rhr�r\r#r^r_�unlink�prepare_txnr�r��
open_index)r9r��auto_recover�
index_pathr�ri�excr+r+r,r��s
zRepository.open_indexc
(Cs�d|_|jrZ|jj�rZ|jdk	r*td��y|jj�Wn ttfk
rXd|_�YnX|j	sj|dkr�y|j
|dd�|_	WnLttt
fk
r�}z*tjd|�|j�|j
|dd�|_	WYdd}~XnX|dkr�i|_t�|_d|_|jj��n�|�r|jj|�tjj|jd|�}tjj|jd|�}|j|d	�}y(t|d|d
��}tj|�}WdQRXWnltj tj!t"t
fk
�r�}	zBtjd|	�t#|	t"��s�tj$|�tj$|�|j�|j%|�dSd}	~	XnX|dd
k�r>tj&d|�|d|_t�|_d|_x,t'|d�D]}
tj&d|
�|j(|
��qWtj&d�nF|ddk�r^td|d��n&|d|_t|d�|_|j)dd�|_|j*�x@|jj+�D]2\}}x&t,|�D]}
|
|k�r�|j-|
��q�W�q�WdS)NTz-bug in code, exclusive lock should exist hereF)r�z9Checking repository transaction due to previous error: %srzhints.%dzindex.%dshints)r�r�zARepository hints file missing or corrupted, trying to recover: %ssversionr	zUpgrading from v1 hints.%dssegmentsscompactz%Rebuilding sparse info for segment %dzUpgrade to v2 hints completer$zUnknown hints file version: %dsstorage_quota_use).rGrIrDr�rLrUZupgraderrrEr�r�r\r#r^r_r��segments�	FreeSpace�compactrOrF�clearrCr[r@rArgr�r"rr�ZUnpackExceptionZ	ExtraDatarlr5r�r��debugr��_rebuild_sparser�r��items�listr�)
r9r��
do_cleanupr�Z
hints_pathr�r�ri�hintsr�r�r�Zshadowed_segmentsr+r+r,r�sp
"





zRepository.prepare_txnc!Csdd�}dd�}d|j|j|jd�}ddi}|jj�}|dk	sBt�|jr�ttj	j
|j	d�d	��$}td
|tj
�jt�f|d�WdQRXd|}tj	j
|j	|�}t|d
|dd��}	tj||	�||	�WdQRX|	j|d<d|}
tj	j
|j	|
�}t|d
|
dd��}	|jj|	�||	�WdQRX|	j|d<d|}tj	j
|j	|�}
t|
d
d��}	tj||	�||	�WdQRX||
�t|j	�||�||�t|j	�d|}xLtj|j	�D]<}|jd��s̐q�|j|��rܐq�tjtj	j
|j	|���q�Wd|_dS)NcSs|j�tj|j��dS)N)�flushr@�fsync�fileno)rir+r+r,�flush_and_syncWsz.Repository.write_index.<locals>.flush_and_synccSstj|d|�dS)Nz.tmp)r@�rename)�filer+r+r,�
rename_tmp[sz*Repository.write_index.<locals>.rename_tmpr$)sversionssegmentsscompactsstorage_quota_usesversionZtransactions�aztransaction %d, UTC time %s)r�zhints.%dz.tmpT)r�r�shintszindex.%dsindexzintegrity.%d�wbz.%d�index.�hints.�
integrity.)r�r�r�)r�r�rOrCr�rUrMrXr@rArg�printrZutcnowZstrftimeZ
ISO_FORMATr"r�packr�rEr�rror��endswithr�)r9r�r�r�r�r��logZ
hints_nameZ
hints_fileriZ
index_nameZ
index_fileZintegrity_namer�Zcurrent�namer+r+r,r�VsV

$



zRepository.write_indexcCs�|jj�d}t|j�dt|j�dd}||7}||j7}|js�|jt}t|j�dkr�d}xD|jj	�D]6\}}y||j
j|�|7}Wqntk
r�YqnXqnWt
jd�t||�}t
jd|�||7}n||7}ytj|j�}Wn4tk
�r}zt
jdt|��dSd}~XnX|j|j}	t
jd	j||	��|	|k�r�|j�rdt
jd
�|j�n|jdd�t|�}
t|	�}|j|
|��dS)
zJPre-commit check for sufficient free space to actually perform the commit.��
irzAcheck_free_space: few segments, not requiring a full free segmentzBcheck_free_space: calculated working space for compact as %d bytesz.Failed to check free space before committing: Nz2check_free_space: required bytes {}, free bytes {}z@Not enough free space to initialize repository at this location.T)r[)rE�size�lenr�r�r}rMr{�MAX_OBJECT_SIZEr�rC�segment_sizerlr^r��minr@�statvfsrAr\r_r��f_bavail�f_frsize�formatrK�errorr�r`rr>)r9Zrequired_free_spaceZ
hints_sizeZfull_segment_sizeZcompact_working_spacer�ZfreeZst_vfsZos_errorZ
free_spaceZformatted_requiredZformatted_freer+r+r,r��sB
 








zRepository.check_free_spacecCs$|jr tjdt|j�t|j��dS)Nz!Storage quota: %s out of %s used.)rNr^�inforrO)r9r+r+r,r��szRepository.log_storage_quotacs��js
dS�j}�j�}�j}g�td��d���fdd�	}�jd�tt�j�ddd	d
�}�xt�jj	��D�]�\�}�j
j��s��jd���j�=|j
�qn�j
j��}d||}|d
�jkr�|d|kr�jd�|d|�|j
�qn|j�d��jd�|�|d|��x�j
j�dd�D�]\}	}
}}|	tk�rH�q,�jj|
�}
|
�|fk}|	tk�r�|�r�y�j
j|
|dd�\}}Wn0tjk
�r�|��j
j|
|�\}}YnX||f�j|
<|j|d�||d7<|�d8<�q,|	tk�rZ|�rZy�j|
j��Wnttfk
�r:YnX�jt|��j
jj8_n�|	tk�r,|
�r,|
�jk�p�t �fdd��j|
D��}|dk�p��|k}|�s�|�ry�j
j!|
dd�\}}Wn.tjk
�r�|��j
j!|
�\}}YnX�j||7<|j|d�n�j|
�s,�j|
=�q,W|�dk�sJt"d���j#��|j
�qnW|j$�|dd��j}�j%dt&||���jd�dS)zBCompact sparse segments by copying data into new segments
        Nzborg.debug.compact_segmentsTcsv�jj|d�}�jd|rdnd|�xH�D]@}�jd|��jj|�}|dksVtd���jj|��j|=q*Wg�dS)N)�intermediatez+complete_xfer: wrote %scommit at segment %dz
intermediate r�z)complete_xfer: deleting unused segment %drz<Corrupted segment reference count - corrupted index or hints)rCr�r�r��poprU�delete_segmentr�)rr��count)r^r9�unusedr+r,�
complete_xfer�s
z2Repository.compact_segments.<locals>.complete_xferzcompaction started.zCompacting segments %3.0f%%r	zrepository.compact_segments)�totalr��step�msgidz3segment %d not found, but listed in compaction datag�?g�������?g333333�?z>not compacting segment %d (maybe freeable: %2.2f%% [%d bytes])gY@rzNcompacting segment %d with usage count %d (maybe freeable: %2.2f%% [%d bytes]))�include_data)�
raise_fullc3s|]}|�kVqdS)Nr+)r�Zshadowed)r�r+r,r�'sz.Repository.compact_segments.<locals>.<genexpr>z<Corrupted segment reference count - corrupted index or hintsF)rz+compaction freed about %s repository space.zcompaction completed.)T)'r�rOr�r�rr�rr�r�r�rC�segment_existsr_�showr�r{�
setdefault�iter_objects�
TAG_COMMITrEr��TAG_PUT�	write_putr��SegmentFullrFr��KeyErrorr��put_header_fmtr��
TAG_DELETE�any�write_deleterU�append�finishrr)r9Zquota_use_beforer�r�r	�piZfreeable_spacer�Zfreeable_ratio�tagr��offsetruZin_indexZis_index_objectZnew_segmentZshadowed_put_existsZdelete_is_not_stabler�Zquota_use_afterr+)r^r�r9rr,r��s�
"
"

zRepository.compact_segmentsc
Cs�|j}d|_|j|dd�z�tdd�|jj�D��}t|ddd�}x\t|jj��D]J\}\}}|j|�|dk	rz||krzqR||kr�P|jj|�}	|j	||	�qRW|j
�|j�Wd||_|j�XdS)NF)r�css|]
}dVqdS)r	Nr+)r��_r+r+r,r�gsz-Repository.replay_segments.<locals>.<genexpr>zReplaying segments %3.0f%%zrepository.replay_segments)r
r�r)
rLr��sumrC�segment_iteratorr�	enumeraterr�
_update_indexrr�r�)
r9r�r�Zremember_exclusive�
segment_countr�ir�r��objectsr+r+r,r�as&
zRepository.replay_segmentscCs�d|j|<�xN|D�]D\}}}}|tkr�y6|j|\}}	|j||7<|j|d8<Wntk
rrYnX||f|j|<|j|d7<|j|7_q|tk�r y|jj|�\}}Wntk
r�YnHX|jj	|��rX|j|d8<|jj
|||dd�}|j||7<q|tk�r.qqdj||�}
|dk�rP|j
|
��q||
�qW|j|dk�r~|jj|�|j|<dS)z2some code shared between replay_segments and checkrr	F)�	read_datazUnexpected tag {} in segment {}N)r�rrEr�rrOrrrCrrhrrr4r�)r9r�r(Zreportrr�r r��sr!r�r+r+r,r%xs:



zRepository._update_indexc
Cs�y|jj|�}Wn tk
r0|jj|�dSX|j|dkrN||j|<dSd|j|<xl|jj|dd�D]X\}}}}|tkr�|jj	|d�||fkr�|j||7<qj|t
krj|j||7<qjWdS)	zNRebuild sparse bytes count for a single segment relative to the current index.NrF)r)r	r�r�)r�r�)rCr�rlr�rr�rrrEr�r)r9r�r�rr�r r�r+r+r,r��s

zRepository._rebuild_sparsec!s�|jr|rt|jd��d��fdd�}tjd�|js>t�y"|j�}|j|�}tj	d|�Wn<t
k
r�}z |jj�}d}tj	d|�WYdd}~XnX|dkr�tj	d	�|j
�}|dkr�tj	d
�|jj�}|dkr�|d�dS|r�|jj|�|jj�}tj	d|�tj	d
|�|jd�tdd�|jj�D��}tj	d|�t|dddd�}	x�t|jj��D]�\}
\}}|	j|
�||k�r��qhtj	d|�yt|jj|��}
WnXtk
�r}z:|t|��g}
|�r�|jj||�t|jj|��}
WYdd}~XnX|j||
|��qhW|	j�|�rV|dk�rV|dj|��|d|j_|jj�tjd�|�rX|�rXt |�t |j!�k�r�|d�tj"dt |��tj"dt |j!��n
tjd�d}d}xB|j!j#�D]4\}}|j$||�}||k�r�tj%|t&|�||��q�WxR|j#�D]F\}}||j!k�r&�q|j!j$||�}||k�rtj%|t&|�||��qW|�rn|j'�|j(�|j)���r�|�r�tjd�n
tj"d �n
tjd!���p�|S)"z�Check repository consistency

        This method verifies all segment checksums and makes sure
        the index is consistent with the data stored in the segments.
        z is in append-only modeFcsd�tj|�dS)NT)r^r)r�)�error_foundr+r,�report_error�sz&Repository.check.<locals>.report_errorzStarting repository checkz&Read committed index of transaction %dNz#Failed to read committed index (%s)zNo segments transaction foundz1No index transaction found, trying latest segmentz'This repository contains no valid data.zSegment transaction is    %szDetermined transaction is %scss|]
}dVqdS)r	Nr+)r�r!r+r+r,r��sz#Repository.check.<locals>.<genexpr>zFound %d segmentszChecking segments %3.1f%%g�������?zrepository.check)r
r�rrzchecking segment file %s...zAdding commit tag to segment {}r	zStarting repository index checkzIndex object count mismatch.zcommitted index: %d objectszrebuilt index:   %d objectszIndex object count match.z5ID: %-64s rebuilt index: %-16s committed index: %-16sz<not found>z6Completed repository check, errors found and repaired.z)Completed repository check, errors found.z.Completed repository check, no problems found.)*rMr�rAr^rrGrUr�r�r�r�rCr�r�r�r[r�r"r#rr$rr�rrr��recover_segmentr%rrr�r�r�rEr�	iteritemsr�r_rr�r�r�)r9Zrepairr�r,r�Z
current_indexr�r�r&rr'r�r�r(r�Zline_formatZ	not_foundr��valueZ
current_valuer+)r+r,�check�s�










"





zRepository.checkccs�x�|jj�D]z\}}y6x0|jj|dd�D]\}}}}|||||fVq(WWqtk
r�}ztjd||t|�f�WYdd}~XqXqWdS)a�Very low level scan over all segment file entries.

        It does NOT care about what's committed and what not.
        It does NOT care whether an object might be deleted or superseded later.
        It just yields anything it finds in the segment files.

        This is intended as a last-resort way to get access to all repo contents of damaged repos,
        when there is uncommitted, but valuable data in there...
        T)r
z6Segment %d (%s) has IntegrityError(s) [%s] - skipping.N)rCr#rrr^rr�)r9r�r�rr�r rur�r+r+r,�scan_low_levels
zRepository.scan_low_levelcCs,|r|jj|jj��d|_d|_d|_dS)z	
        NF)rCr[r�rErGrP)r9r[r+r+r,r`,s
zRepository._rollbackcCs|jdd�dS)NF)r[)r`)r9r+r+r,r�5szRepository.rollbackcCs |js|j|j��|_t|j�S)N)rEr�r�r�)r9r+r+r,�__len__9szRepository.__len__cCs |js|j|j��|_||jkS)N)rEr�r�)r9r:r+r+r,�__contains__>szRepository.__contains__cCs4|js|j|j��|_dd�t|jj|d�|�D�S)zd
        list <limit> IDs starting from after id <marker> - in index (pseudo-random) order.
        cSsg|]\}}|�qSr+r+)r��id_r!r+r+r,�
<listcomp>Isz#Repository.list.<locals>.<listcomp>)�marker)rEr�r�rr.)r9�limitr6r+r+r,r�CszRepository.listc
Cs|dk	r|dkrtd��|js2|j�}|j|�|_|dk}|rBdn|j|\}}g}x�|jj|�D]�\}}	|jj||ddd�}
xxyt|
�\}}}
}Wntt	fk
r�PYnX|dkr�d}q�|t
kr�||
f|jj|�kr�|j|�t
|�|kr�|Sq�WqbW|S)a�
        list <limit> IDs starting from after id <marker> - in on-disk order, so that a client
        fetching data in this order does linear reads and reuses stuff from disk cache.

        We rely on repository.check() has run already (either now or some time before) and that:

        - if we are called from a borg check command, self.index is a valid, fresh, in-sync repo index.
        - if we are called from elsewhere, either self.index or the on-disk index is valid and in-sync.
        - the repository segments are valid (no CRC errors).
          if we encounter CRC errors in segment entry headers, rest of segment is skipped.
        Nr	z$please use limit > 0 or limit = NonerF)r)r
)rr)r�rEr�r�rCr#r�next�
StopIterationrrr�rr�)r9r7r6r�Zat_startZ
start_segmentZstart_offset�resultr�r�Zobj_iteratorrr:r r�r+r+r,�scanKs.
zRepository.scancCs^|js|j|j��|_y|j|\}}|jj|||�Stk
rX|j||j�d�YnXdS)N)rEr�r�rCrhrr=rA)r9r:r�r r+r+r,r�vszRepository.getccsx|D]}|j|�VqWdS)N)r�)r9�idsZis_preloadedr4r+r+r,�get_manys
zRepository.get_manycCs�|js|j|j��y|j|\}}Wntk
r:YnX|j|||dd�|jj||�\}}|jt	|�|jj
j7_|jj
|d�|j|d7<||f|j|<|jr�|j|jkr�|jt|j�t|j��|_|j�dS)z�put a repo object

        Note: when doing calls with wait=False this gets async and caller must
              deal with async results / exceptions later.
        F)�update_shadow_indexrr	N)rGr�r�rEr�_deleterCrrOr�rr�r�rrNr?rrP)r9r:ru�waitr�r r+r+r,�put�s zRepository.putcCsd|js|j|j��y|jj|�\}}Wn$tk
rL|j||j�d�YnX|j|||dd�dS)z�delete a repo object

        Note: when doing calls with wait=False this gets async and caller must
              deal with async results / exceptions later.
        NT)r>)	rGr�r�rErrr=rAr?)r9r:r@r�r r+r+r,�delete�szRepository.deletecCs�|r|jj|g�j|�|j|d8<|jj|||dd�}|j||7<|jj|�\}}|j||7<|jj|d�dS)Nr	F)r)r)rFrrr�rCrhr�r)r9r:r�r r>r�r+r+r,r?�szRepository._deletecCsdS)aCGet one async result (only applies to remote repositories).

        async commands (== calls with wait=False, e.g. delete and put) have no results,
        but may raise exceptions. These async exceptions must get collected later via
        async_response() calls. Repeat the call until it returns None.
        The previous calls might either return one (non-None) result or raise an exception.
        If wait=True is given and there are outstanding responses, it will wait for them
        to arrive. With wait=False, it will only return already received responses.
        Nr+)r9r@r+r+r,�async_response�szRepository.async_responsecCsdS)z>Preload objects (only applies to remote repositories)
        Nr+)r9r<r+r+r,�preload�szRepository.preload)FFNTFNTF)NT)F)T)T)N)FF)NN)NN)F)T)T)T)Cr'r(r)r*rr-r.r/r0r1r2r3r
r4r=r>r?r8rVrWrZrb�propertyrc�staticmethodrjrrrSr�r�r�r�r�r�r�r�r�r�r�rXrTr�r�r�r�r�r�r�r�r�r%r�r0r1r`r�r2r3r�r;r�r=rArBr?rCrDr+r+r+r,r&5s~D

##		
2


GF:
'
d	

+	



r&c@sdeZdZGdd�de�Zejd�Zejdks0t	�ejd�Z
e
jdksHt	�ejd�Zejdks`t	�ejd	�Zejd
ksxt	�ej
de�Zej
ee��eZd>dd
�Zdd�Zdd�Zd?dd�Zdd�Zdd�Zdd�Zdd�Zdd�Zd@d d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Z d,d-�Z!dAd0d1�Z"d2d3�Z#dBd4d5�Z$dCd6d7�Z%dDd8d9�Z&dEd:d;�Z'dFd<d=�Z(dS)Gr�c@seZdZdZdS)zLoggedIO.SegmentFullz2raised when a segment is full, before opening nextN)r'r(r)r*r+r+r+r,r�srz<IIB�	z<IIB32s�)z<IB�z<Ir��ZcCs>||_t||jd�|_d|_||_||_d|_d|_d|_	dS)N)Zdisposer)
rAr�	_close_fd�fdsr�r7rzr �	_write_fd�_fds_cleaned)r9rAr7rzZcapacityr+r+r,r8�szLoggedIO.__init__cCs|j�|jj�d|_dS)N)�
close_segmentrLr�)r9r+r+r,rT�s
zLoggedIO.closecCs&|\}}t|j�ddd�|j�dS)NrZDONTNEED)r r�rT)r9�ts_fd�tsrir+r+r,rK�szLoggedIO._close_fdNFc#s��dkr|sdnd
�tjj|jd�}�|j�tj|�}|sP�fdd�|D�}n�fdd�|D�}t|t|d	�}x�|D]x}tjtjj||��}|s��fd
d�|D�}n�fdd�|D�}t|t|d	�}x&|D]}t|�tjj|||�fVq�WqvWdS)Nrr$r~r	rucs$g|]}|j�rt|��kr|�qSr+)r�r�)r��dir)�start_segment_dirr+r,r5�sz-LoggedIO.segment_iterator.<locals>.<listcomp>cs$g|]}|j�rt|��kr|�qSr+)r�r�)r�rR)rSr+r,r5�s)r��reversecs$g|]}|j�rt|��kr|�qSr+)r�r�)r�r�)r�r+r,r5�scs$g|]}|j�rt|��kr|�qSr+)r�r�)r�r�)r�r+r,r5sll��)r@rArgrzror�r�)r9r�rTZ	data_path�dirsrR�	filenamesr�r+)r�rSr,r#�s"



zLoggedIO.segment_iteratorcCs x|jdd�D]
\}}|SWdS)NT)rT)r#)r9r�r�r+r+r,r�szLoggedIO.get_latest_segmentcCs,x&|jdd�D]\}}|j|�r|SqWdS)z+Return the last committed segment.
        T)rTN)r#�is_committed_segment)r9r�r�r+r+r,r�
s
z$LoggedIO.get_segments_transaction_idcCsh|d|_d}xF|jdd�D]6\}}||krP||jkr>|j|=t|�|d7}qPqWtjd||�dS)z:Delete segment files left by aborted transactions
        r	rT)rTzICleaned up %d uncommitted segment files (== everything after segment %d).N)r�r#rLrr^r�)r9r�rr�r�r+r+r,r[s


zLoggedIO.cleanupc
(Csy|j|�}Wntk
r"dSXt|j|�d��n}y|j|jjtj�Wn6t	k
r�}z|j
t
jkrpdS|�WYdd}~XnX|j|jj�|j
kr�dSWdQRXd}xZyt|�\}}}}	Wn(tk
r�dStk
r�PYnX|tk�r�d}q�|r�dSq�W|S)z4Check if segment ends with a COMMIT_TAG tag
        FreNT)rrrX�segment_filename�seek�
header_fmtr�r@�SEEK_ENDr\r]ZEINVALrh�COMMITr8r9r)
r9r��iteratorrir�Zseen_commitrr�r r!r+r+r,rW%s6
zLoggedIO.is_committed_segmentcCs"tjj|jdt||j�t|��S)Nru)r@rArgr�rz)r9r�r+r+r,rXEszLoggedIO.segment_filenamecCs�|r*|jr*|j|jkr*|r"|j�|j�|js�|j|jdkr�tjj	|jdt
|j|j��}tjj|�s�tj|�t
tjj	|jd��t|j|j�dd�|_|jjt�t|_|j|jkr�|j|j=|jS)NrruT)r�)r r7rrOrMr�rzr@rArgr�r�r�rrrXr��MAGIC�	MAGIC_LENrL)r9Zno_newr�dirnamer+r+r,�get_write_fdHs 

zLoggedIO.get_write_fdcsptj�����fdd�}��fdd�}|�y�j�\}}Wntk
rX|�}YnX�jj��|f�|S)Ncs"t�j��d�}�|f�j�<|S)Nre)rXrXrL)ri)�nowr�r9r+r,�open_fdcsz LoggedIO.get_fd.<locals>.open_fdcsT��jtdkrP��_x6t�jj��D]$\}}|\}}�|tkr(�j|=q(WdS)Nr�)rNZ
FD_MAX_AGEr�rLr�)�krPrQri)rbr9r+r,�	clean_oldhsz"LoggedIO.get_fd.<locals>.clean_old)�timeZ	monotonicrLrZupd)r9r�rcrerQrir+)rbr�r9r,�get_fd^szLoggedIO.get_fdcCs6|jd}|_|dk	r2|jd7_d|_|j�dS)Nr	r)rMr�r rT)r9rir+r+r,rO~s
zLoggedIO.close_segmentcCs>||jkr|j|=yt|j|��Wntk
r8YnXdS)N)rLrrXrl)r9r�r+r+r,r�s
zLoggedIO.delete_segmentcCs"|j|�}tjj|�o tjj|�S)N)rXr@rAr��getsize)r9r�r�r+r+r,r�s
zLoggedIO.segment_existscCstjj|j|��S)N)r@rArhrX)r9r�r+r+r,r��szLoggedIO.segment_sizecCs|j|�}|jd�|jt�S)Nr)rgrYrhr_)r9r�rir+r+r,r��s

zLoggedIO.get_segment_magicrTc	cs�|j|�}|j|�|dkr>|jt�tkr:tdj|d���t}|j|jj�}x||r�|j	||j|||t
ttf|d�\}}}	}
|r�||	||
fVn||	||fV||7}|j|�}|j|�|j|jj�}qNWdS)a7
        Return object iterator for *segment*.

        If read_data is False then include_data must be False as well.
        Integrity checks are skipped: all data obtained from the iterator must be considered informational.

        The iterator returns four-tuples of (tag, key, offset, data|size).
        rz-Invalid segment magic [segment {}, offset {}])r)N)
rgrYrhr_r^rrrZr��_readrrr)r9r�r r
r)ri�headerr�rr�rur+r+r,r�s$	



zLoggedIO.iter_objectsc&Cs�tjd|�||jkr |j|=tjj|�t|jjkr^t	|dd��}|j
t�WdQRXdSt	|dd���}t|d���}t
j
|j�dt
jd���}t|�}|}z�|j
t�x�t|�|jjk�rT|jj|d|jj��\}	}
}|
tk�s&|tk�s&|
|jjk�s&|
t|�k�s&t|d|
��d@|	k�r4|d	d�}q�|j
|d|
��||
d�}q�WWd~|j�XWdQRXWdQRXWdQRXdS)
Nzattempting to recover T)r�rer)�accessr�l��r	)r^rrLr@rArhr_rZr�rr�r^rX�mmapr�ZACCESS_READ�
memoryviewr�r�r��
MAX_TAG_IDr!r�)r9r�r�riZdst_fdZsrc_fdZmmru�d�crcr�rr+r+r,r-�s0

"(zLoggedIO.recover_segmentcCs�||jkr|jr|jj�|j|�}|j|�|j|jj�}|j||j|||t	f|�\}}}	}
||	krvt
dj||���|r~|
S|S)z�
        Read entry from *segment* at *offset* with *id*.

        If read_data is False the size of the entry is returned instead and integrity checks are skipped.
        The return value should thus be considered informational.
        zJInvalid segment entry header, is not for wanted id [segment {}, offset {}])r�rM�syncrgrYrhrr�rirrr)r9r�r r:r)rirjr�rr�rur+r+r,rh�s


"
z
LoggedIO.readcCs&t|�tkstd��y|j|�}Wn8tjk
rZ}	ztdj|||	��d�WYdd}	~	XnX||jkrt|\}
}}}
n"||j	kr�|\}
}}d}
nt
d��|tkr�tdj|||���||jkr�tdj|||���||j}|�rt|j
|�}t|�|k�rtdj|||t|����t|tt|�dd���d@|
k�r@td	j||���|
dk�r|ttfk�r|dd
�|d
d�}
}n�|
dk�r�|ttfk�r�|j
d
�}
|d
8}t|
�d
k�r�tdj||d
t|
����|j�}|j|tj�|}d}||k�rtdj||||���||k�rtd
j||���|||
|fS)Nz7Exceeding MAX_TAG_ID will break backwards compatibilityz8Invalid segment entry header [segment {}, offset {}]: {}z$_read called with unsupported formatz?Invalid segment entry size {} - too big [segment {}, offset {}]zAInvalid segment entry size {} - too small [segment {}, offset {}]zPSegment entry data short read [segment {}, offset {}]: expected {}, got {} bytesr�l��z7Segment entry checksum mismatch [segment {}, offset {}]r~zOSegment entry key short read [segment {}, offset {}]: expected {}, got {} byteszPSegment entry data short seek [segment {}, offset {}]: expected {}, got {} byteszPInvalid segment entry header, did not get acceptable tag [segment {}, offset {}])�maxrnrUr��structrrrrrZ�	TypeErrorr�r�rhr�r!rmrr�tellrYr@�SEEK_CUR)r9riZfmtrjr�r Zacceptable_tagsr)Z	hdr_tupler�rpr�rr�ZlengthruZoldposZseekedr+r+r,ri�sZ 





$




zLoggedIO._readc
Cs�t|�}|tkr tdj|t���|j|d�}||jj}|j}|jj	|t
�}|jj	t|t|t|���d@�}	|j
dj|	|||f��|j|7_|j|fS)Nz$More than allowed put data [{} > {}])rl���)r�Z
MAX_DATA_SIZErrrarr�r �header_no_crc_fmtr�r�crc_fmtr!r�rgr�)
r9r:rurZ	data_sizerir�r rjrpr+r+r,r)s zLoggedIO.write_putcCsn|j|d�}|jj|jjt�}|jjt|t|��d@�}|jdj	|||f��|j
|jj7_
|j|jjfS)N)rl��rw)rarxr�rr�rryr!r�rgr r�)r9r:rrirjrpr+r+r,r7szLoggedIO.write_deletecCsr|r|j�}|j�n|j�|j�}|jj|jjt�}|jjt	|�d@�}|j
dj||f��|j�|jdS)Nl��rwr	)
rarqrOrxr�rZr�rryr!r�rgr�)r9rrirjrpr+r+r,r�?s
zLoggedIO.write_commit)rJ)NF)FF)rFT)T)T)F)F)F))r'r(r)r�rrs�StructrZr�rUrrxryr�rZ_commitr!r\r8rTrKr#r�r�r[rWrXrargrOrrr�r�rr-rhrirrr�r+r+r+r,r��sD






 
 
%

7

r�rH)Er]rlr@r�rkrsrfZbinasciirr�collectionsrZconfigparserrr�	functoolsr�	itertoolsrZ	constantsZ	hashindexrZhelpersrr
rrrrrrrrrrZlockingrrrr^rZlrucacher�platformrrrr Zalgorithms.checksumsr!Zcrypto.file_integrityr"r#r'r^r�r_r�rUrrrrnr�r�r&r�rr�r+r+r+r,�<module>sh