copy: Reduce calls to stat() by 50% in chown_recursive

This reduces the number of times `stat()` or `chown()` are called by the
copy module. Reductions come from

- combining loops for owner and group, thus not looping twice
- not looping over the list of directories returned by `os.walk()`, each
  directory is already handled when `os.walk()` descends into it

Possible further reductions could be achieved by
- exiting early from the check_mode loop
- Replacing `m.set_owner_if_different()` & `m.set_group_if_different()`
  calls with a single method.

I propose to do these separately, if there is interest.
pull/75741/head
Alex Willmer 3 years ago
parent f4ff6768f3
commit 60cbd7f4c8

@ -0,0 +1,3 @@
minor_changes:
- copy - Reduce disk accesses by 50% when setting owner and group of copied
files and directories

@ -360,62 +360,34 @@ def chown_recursive(path, module):
owner = module.params['owner']
group = module.params['group']
if owner is not None:
if not module.check_mode:
for dirpath, dirnames, filenames in os.walk(path):
owner_changed = module.set_owner_if_different(dirpath, owner, False)
if owner_changed is True:
changed = owner_changed
for dir in [os.path.join(dirpath, d) for d in dirnames]:
owner_changed = module.set_owner_if_different(dir, owner, False)
if owner_changed is True:
changed = owner_changed
for file in [os.path.join(dirpath, f) for f in filenames]:
owner_changed = module.set_owner_if_different(file, owner, False)
if owner_changed is True:
changed = owner_changed
else:
uid = pwd.getpwnam(owner).pw_uid
for dirpath, dirnames, filenames in os.walk(path):
owner_changed = (os.stat(dirpath).st_uid != uid)
if owner_changed is True:
changed = owner_changed
for dir in [os.path.join(dirpath, d) for d in dirnames]:
owner_changed = (os.stat(dir).st_uid != uid)
if owner_changed is True:
changed = owner_changed
for file in [os.path.join(dirpath, f) for f in filenames]:
owner_changed = (os.stat(file).st_uid != uid)
if owner_changed is True:
changed = owner_changed
if group is not None:
if not module.check_mode:
for dirpath, dirnames, filenames in os.walk(path):
group_changed = module.set_group_if_different(dirpath, group, False)
if group_changed is True:
changed = group_changed
for dir in [os.path.join(dirpath, d) for d in dirnames]:
group_changed = module.set_group_if_different(dir, group, False)
if group_changed is True:
changed = group_changed
for file in [os.path.join(dirpath, f) for f in filenames]:
group_changed = module.set_group_if_different(file, group, False)
if group_changed is True:
changed = group_changed
else:
gid = grp.getgrnam(group).gr_gid
for dirpath, dirnames, filenames in os.walk(path):
group_changed = (os.stat(dirpath).st_gid != gid)
if group_changed is True:
changed = group_changed
for dir in [os.path.join(dirpath, d) for d in dirnames]:
group_changed = (os.stat(dir).st_gid != gid)
if group_changed is True:
changed = group_changed
for file in [os.path.join(dirpath, f) for f in filenames]:
group_changed = (os.stat(file).st_gid != gid)
if group_changed is True:
changed = group_changed
if owner is None and group is None:
return changed
if module.check_mode:
uid = pwd.getpwnam(owner).pw_uid if owner is not None else None
gid = grp.getgrnam(group).gr_gid if group is not None else None
for dirpath, dirnames, filenames in os.walk(path):
stat = os.stat(dirpath)
changed = changed or (uid is not None and uid != stat.st_uid)
changed = changed or (gid is not None and gid != stat.st_gid)
for filename in filenames:
filepath = os.path.join(dirpath, filename)
stat = os.stat(filepath)
changed = changed or (uid is not None and uid != stat.st_uid)
changed = changed or (gid is not None and gid != stat.st_gid)
return changed
for dirpath, dirnames, filenames in os.walk(path):
changed = module.set_owner_if_different(dirpath, owner, changed)
changed = module.set_group_if_different(dirpath, group, changed)
for filename in filenames:
filepath = os.path.join(dirpath, filename)
changed = module.set_owner_if_different(filepath, owner, changed)
changed = module.set_group_if_different(filepath, group, changed)
return changed

Loading…
Cancel
Save