Skip to content

Conversation

screamerbg
Copy link
Contributor

This aims to fix caching thread safety in Mbed CLI. It uses directory creation which is atomic operation on all operating systems. I've tested with the script @adamelhakham wrote. Additionally @adamelhakham tested it in their CI. I'd still advise to try it in staging CI rather than live.
Addresses #660

CC @teetak01 @yogpan01

mbed/mbed.py Outdated
try:
if os.path.isfile(lock_file):
with open(lock_file, 'r', 0) as f:
pid = f.read(8)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concurrency issue here.
Other proces might have just opened the file, but not yet written to it.
On line 1385 it does:

                    with open(lock_file, 'wb', 0) as f:
                        info("Writing cache lock file %s for pid %s" % (lock_file, os.getpid()))
                        f.write(str(os.getpid()))
                        f.flush()
                        os.fsync(f)

So context switch might happen after open() but just before writing to a file.

This would lead to two processes thinking that they own the lock.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then this would be handled by

                        if not pid:
                            if int(os.path.getmtime(lock_file)) + timeout < int(time.time()):
                                info("Cache lock file exists, but is empty. Cleaning up")
                                os.remove(lock_file)
                                os.rmdir(lock_dir)

This means if a lock folder exists and the file has been created and empty (just opened), there will be a 5 minutes time window during which all concurrent processes will be waiting for the file to be written with a valid pid value. This prevents the concurrency issue you described.

@screamerbg
Copy link
Contributor Author

Will fix the Py3 issues. Please ignore for now.

Copy link
Contributor

@theotherjimmy theotherjimmy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that a context manager would improve the pythonishness and reduce the change of future programmer error.

mbed/mbed.py Outdated
shutil.copytree(cache, path)
self.cache_unlock(url)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be safer as a context manager? That way we could never forget to unlock the cache.

mbed/mbed.py Outdated
self.set_cache(url)
self.cache_unlock(url)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also use the context manager here.

@teetak01
Copy link

cc: @adamelhakham

Copy link
Contributor

@theotherjimmy theotherjimmy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed my own request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants