// -*- indent-tabs-mode: nil -*- #ifndef __ARC_FILELOCK_H__ #define __ARC_FILELOCK_H__ #include #include namespace Arc { /// A general file locking class. /** * This class can be used when protected access is required to files * which are used by multiple processes or threads. Call acquire() to * obtain a lock and release() to release it when finished. check() can * be used to verify if a lock is valid for the current process. Locks are * independent of FileLock objects - locks are only created and destroyed * through acquire() and release(), not on creation or destruction of * FileLock objects. * * Unless use_pid is set false, the process ID and hostname of the calling * process are stored in a file filename.lock in the form pid\@hostname. * This information is used to determine whether a lock is still valid. * It is also possible to specify a timeout on the lock. * * To ensure an atomic locking operation, acquire() first creates a * temporary lock file filename.lock.XXXXXX, then attempts to rename * this file to filename.lock. After a successful rename the lock file * is checked to make sure the correct process ID and hostname are inside. * This eliminates race conditions where multiple processes compete to * obtain the lock. * @ingroup common * @headerfile FileLock.h arc/FileLock.h */ class FileLock { public: /// Default timeout for a lock const static int DEFAULT_LOCK_TIMEOUT; /// Suffix added to file name to make lock file const static std::string LOCK_SUFFIX; /// Create a new FileLock object. /** * @param filename The name of the file to be locked * @param timeout The timeout of the lock * @param use_pid If true, use process id in the lock and to * determine lock validity */ FileLock(const std::string& filename, unsigned int timeout=DEFAULT_LOCK_TIMEOUT, bool use_pid=true); /// Acquire the lock. /** * Returns true if the lock was acquired successfully. Locks are acquired * if no lock file currently exists, or if the current lock file is * invalid. A lock is invalid if the process ID inside the lock no longer * exists on the host inside the lock, or the age of the lock file is * greater than the lock timeout. * * @param lock_removed Set to true if an existing lock was removed due * to being invalid. In this case the caller may decide to check or * delete the file as it is potentially corrupted. * @return True if lock is successfully acquired */ bool acquire(bool& lock_removed); /// Acquire the lock. /** * Callers can use this version of acquire() if they do not care whether * an invalid lock was removed in the process of obtaining the lock. * @return True if lock is successfully acquired */ bool acquire(); /// Release the lock. /** * @param force Remove the lock without checking ownership or timeout * @return True if lock is successfully released */ bool release(bool force=false); /// Check the lock is valid. /** * @param log_error may be set to false to log error messages at INFO * level, in cases where the lock not existing or being owned by another * host are not errors. * @return 0 if the lock is valid for the current process, the pid inside * the lock if the lock is owned by another process on the same host, or * -1 if the lock is owned by another host or any other error occurred. */ int check(bool log_error = true); /// Get the lock suffix used static std::string getLockSuffix(); private: /// File to apply lock to std::string filename; /// Lock file name: filename + lock suffix std::string lock_file; /// Lock timeout int timeout; /// Whether to use process ID in the lock file bool use_pid; /// Process ID to use in the lock file std::string pid; /// Hostname to use in the lock file std::string hostname; /// Logger object static Logger logger; /// private acquire method. bool acquire_(bool& lock_removed); /// convenience method for writing pid@hostname to file bool write_pid(int h); }; } // namespace Arc #endif