GlusterfsGeo-replication provides a continuous, asynchronous, incremental data backup strategy that can be over the LAN, WAN, Internet. With Geo-replication, we are able to create data redundancy in the storage environment and provide data disaster recovery.

Geo-replication uses master-slave mode:

1, Master-on behalf of a volume;

2, Slave - may be a volume or a folder;

\u0026 nbsp; LAN remote migration diagram

WAN migration diagram

Web migration map

Master side, in the migration started off-site, the volume selection will be set geo-replication.indexing: on

Volume Name: gg

Type: Distribute

Status: Started

Number of Bricks: 2

Transport-type: tcp

Bricks:

Brick1: 10.28.1.96:/data/g1

Brick2: 10.28.1.96:/data/g2

Options Reconfigured:

geo-replication.indexing: on

At the same time modify the marker configuration file, about to open xtime, the purpose of the future is uploaded to the master side of the file will be marked on the time stamp:

volume swift-marker

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; type features / marker

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; option volume-uuid 40f278e4-4769-4206-a33b-67064a853c61

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; option timestamp-file /etc/glusterd/vols/swift/marker.tstamp

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; option xtime on

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; option quota off

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; subvolumes swift-io-threads

\u0026 nbsp; end-volume

rsync-sS-aR http://blog.chinaunix.net/2364.txt http://blog.chinaunix.net/2366.txt http://blog.chinaunix.net/2362.txt http: // blog. chinaunix.net/2365.txt http://blog.chinaunix.net/2368.txt http://blog.chinaunix.net/2367.txt http://blog.chinaunix.net/2363.txt / tmp / liuhong

xattr.getxattr ('aums.txt', 'trusted.glusterfs.81fa9632-e2d1-4337-aee8-83afa72728df.xtime')

'Ob \\ xdcV \\ x00 \\ x06 \\ x01 \\ x12'

>>> b = struct.unpack ('! II', 'Ob \\ xdcV \\ x00 \\ x06 \\ x01 \\ x12')

>>> b

(1331878998, 393490)

\u0026 nbsp;

\u0026 nbsp;

Note: due to time and other reasons, the command line analysis, parameter validity check, rpc communication and other parts of the analysis, but to do the analysis of the relocation of the core business, later make up the part.

\u0026 nbsp;

Off-site migration start-up and migration process

The figure shows:

1) \u0026 nbsp; Set the volume identification on the master side of the volume set parameters geo-replication.indexing: on; Also modify the brick marker configuration file for each parameter xtime on;

ret = glusterd_set_marker_gsync (volinfo); // Set the appropriate parameters for the volume

\u0026 nbsp;

2) \u0026 nbsp; storage uuid slave information;

3) \u0026 nbsp; at the ready to begin synchronization phase, master first check input, slave synchronization process already exists; check offsite migration master end volume of work directory exists, if it does not exist is created, then there will be off-site migration status file With process files stored in this directory:

-rwxr-xr-x 1 root root 6 Mar 21 10:25 gluster% 3A% 2F% 2F10.28.1.96% 3Ar1.pid // The process number is stored

// Store the status number of the relocation

-rwxr-xr-x 1 root root 7 Mar 21 10:49 gluster% 3A% 2F% 2F10.28.1.96% 3Ar1.status

\u0026 nbsp;

4) \u0026 nbsp; Check the master end migrate the log directory exists, if it does not exist then create;

5) \u0026 nbsp; Generate a command to execute a shell file called python script gsyncd.py, such as:

/ usr / local / libexec / glusterfs / gsyncd --monitor -c /etc/glusterd/geo-replication/gsyncd.conf: g1 10.28.1.96::m1

6) \u0026 nbsp; In gsyncd.py, the first parameter check, parameter preparation and related initialization;

7) If you bring monitoring parameters, start the monitor, the monitor file monitor.py will run based on the status of the process run OK, starting ..., faulty, and these will be set to the status of the state file, When inquiring the running status, it will directly inquire these documents;

8) Ssh and slave to establish password-less key authentication;

9) \u0026 nbsp; volume mount, the master volume and slave volume will be linked to the master end of a temporary folder, in order to facilitate the back of the directory entry contrast;

def connect (self):

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; def umount_l (d):

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; time.sleep (0.2) # XXX temporary workaround

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; argv = ['umount', '-l', d]

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # os.spawnvp (mode, file, args)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; #argv [0] = umount

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; return os.spawnvp (os.P_WAIT, argv [0], argv)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # Create a temporary folder for mounted volumes

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; d = tempfile.mkdtemp (prefix = 'gsyncd-aux-mount-')

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp;. . . . . . . . . . . . . . . . . . . . . . . . . . . .

if os.spawnvp (os.P_WAIT, argv [0], argv): # Mount the volume to the client's d directory

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; raise RuntimeError ('command failed:' + '' .join (argv))

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp ;. . . . . . . . . . . . . . . . . . . . . . . . . . . .

os.chdir (d) # Change the current working directory to d, that is, into the mounted directory, so after the implementation of crawl can only be used path'.'

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # Execute mounted offload

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; if umount_l (d)! = 0:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; raise RuntimeError ('umounting% s failed'% d)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # After uninstallation

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; mounted = False

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; finally:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; try:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # unmount if mount status

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; if mounted:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; umount_l (d)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; os.rmdir (d) # Delete Temporary Folder

10) call the master's GMaster (self, args [0]). Crawl_loop (), recursive recursive, check and copy files, called in crawl_loop as follows:

t = Thread (target = keep_alive) # Create a new thread keep_alive, keep the link between master and slave smooth

t.start ()

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # This will consistently crawl as long as self.terminate is None

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; while not self.terminate: # abort

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.crawl () // Loop through the crawl method

11) The crawl method is the core method of relocation. In this method, the master and slave end volume information is checked and obtained first. Then, the master and slave ends recursively with the path '.', Ie, the root directory, as follows :

a) Each path gets the xtime of the path from the master (the value written by the markerxlator when the file is written), that is, xtl, which is temporarily generated if it does not exist.

if not xtl: #xtl is initially None

xtl = self.xtime (path) # Get the xtime record value from xattr, local

if isinstance (xtl, int): # If xtl is an integer, this joins the path to failjob

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.add_failjob (path, 'no-local-node')

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; return

b) Then get the xtime of the path from the slave side, that is xtr; check the slave side of the folder exists, if not exist in the slave side to create the folder;

c) and then xtr XTL comparison, if xtl
d) If xtl> xtr, traversing all directory entries in the path of the master end to obtain the set dem;

\u0026 nbsp;

dem = self.master.server.entries (path)

At the same time read the slave side of the path of all directory entries, the directory entry set des;

try:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; des = self.slave.server.entries (path) # List the list under the slave path

# There is a consistency check error, that is, if the path master directory for the directory, while the slave for the file, delete the file, and then create the path to table of Contents

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; except OSError: # If slave side path does not exist or is not a directory, clean path

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.slave.server.purge (path)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; try:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # Create directories on the slave side with path as path

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.slave.server.mkdir (path)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # again to return all directory entries in the slave path

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; des = self.slave.server.entries (path)

e) through dd = set (des) -set (dem) to calculate the slave end there and master no directory entry, delete them, because the corresponding slave, it does not master should be dirty data;

f) traversing each directory entry in the demos, comparing their xtime with the xtime of the slave-side path, and synchronizing if they are larger than xtime on the slave side;

for e in dem: # Traverses all directory entries under the master

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # Get the absolute path to each item

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; e = os.path.join (path, e) #e is the file or folder name

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # The xtime does not find the corresponding xtime, it sets the timestamp and returns xtime

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; xte = self.xtime (e) # Get the timestamp within xattr for each master file

if isinstance (xte, int): # If xte is an integer, then a warning

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; logging.warn ('irregular irregular xtime for% s:% s'% , errno.errorcode [xte]))

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # Compare master timestamps, folder timestamps with slave end parent timestamps

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # This eliminates the need to traverse all the files in the slave-side folder and their folders

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; elif xte> xtr: # If the master time stamp is greater than the time stamp of the file at the slave end

chld.append ((e, xte)) # Time difference between the object and master timestamp Join the tuple

h) Determine the file type in the chld tuple. If it is a link, create a link directly on the slave and set xtime;

if stat.S_ISLNK (mo): # to determine whether the link

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # create a link on the slave side named e e

if indulgently (e, lambda e: self.slave.server.symlink (os.readlink () e), e)) == False:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; continue # create link failed

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; #e: on behalf of the object path; xte: on behalf of time; adct: on behalf of the property to be set

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # Set xte to the xattr content of slave side files

\u0026 Nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.sendmark (e, xte, adct) # create a successful link, set its xattr, and Attribute, that is, only to ensure that the user, with the same group

If it is a file, put it into the synchronous queue ready to be synchronized by rsync;

elif stat.S_ISREG (mo):

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; logging.debug ('syncing% s ...'% e)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; #syncer is a Synchronizer Object

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; pb = self.syncer.add (e) # Add e to the list of files to synchronize

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; def regjob (e, xte, pb):

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; if pb.wait ():

\u0026 Nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; logging.debug ( 'synced' + e)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.sendmark ( e, xte) # Set the file's extended attributes

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; return True True

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; else:

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; logging.error 'failed to sync backup software pc' + e)

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; #e: for each specific file path; pb for the need to synchronize the file queue

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; # Synchronize the file under path path e, set the xattr value of this file to xte

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.add_job (path, 'reg', regjob, e, xte, pb)

If the folder, recursively call crawl, ready to traverse its subdirectories;

\u0026 nbsp; elif stat.S_ISDIR (mo):

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; adct ['mode'] = mo # Add the mode parameter in adct

\u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp;

\u0026 Nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; if indulgently (e, lambda e: (self.add_job (path, 'cwait', self .wait, e, xte, adct),

\u0026 Nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; self.crawl (e, xte),

\u0026 Nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; \u0026 nbsp; True) [- 1], blame = e) = = False:

Other file types ignore synchronization.

Note: Generally clear, traversal recursion is infinite loop.

\u0026 nbsp; Relative to the start-up process, the stop process is relatively simple, just related to delete the relevant slave information and process files and status files

The figure shows:

1) get its uuid by slave name;

2) uuid to delete the information recorded in the start;

3) by the process of reading from the process file to close the process, and then delete the process file;
이 게시물을..