LibrePCB Developers Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DirectoryLock Class Referencefinal

This class can be used to implement file-based directory locks. More...

#include <directorylock.h>

+ Collaboration diagram for DirectoryLock:

Public Types

enum  LockStatus
 The return type of getStatus() More...
 

Public Member Functions

 DirectoryLock () noexcept
 The default constructor. More...
 
 DirectoryLock (const DirectoryLock &other)=delete
 Copy constructor. More...
 
 DirectoryLock (const FilePath &dir) noexcept
 A constructor which will call setDirToLock() More...
 
 ~DirectoryLock () noexcept
 The destructor (this may also unlock the locked file) More...
 
void setDirToLock (const FilePath &dir) noexcept
 Specify the directory for which you need the lock. More...
 
const FilePathgetDirToLock () const noexcept
 Get the filepath of the directory to lock (passed by setDirToLock()) More...
 
const FilePathgetLockFilepath () const noexcept
 Get the filepath of the lock file (NOT the directory to lock!) More...
 
LockStatus getStatus () const
 Get the lock status of the specified directory. More...
 
void tryLock (bool *wasStale=nullptr)
 Lock the specified directory if not already locked. More...
 
bool unlockIfLocked ()
 Unlock the specified directory if it was locked by this object. More...
 
void lock ()
 Lock the specified directory (create/update the lock file) More...
 
void unlock ()
 Unlock the specified directory (remove the lock file) More...
 
DirectoryLockoperator= (const DirectoryLock &rhs)=delete
 

Private Attributes

FilePath mDirToLock
 The filepath to the directory to lock (passed by setDirToLock()) More...
 
FilePath mLockFilePath
 The filepath to the lock file. More...
 
bool mLockedByThisObject
 This attribute defines if the lock is active by this object. More...
 

Detailed Description

This class can be used to implement file-based directory locks.

Many classes of this project open some directories (workspaces, projects, library elements, ...). But it's very dangerous if a directory is opened multiple times simultaneously (by the same or another instance of the application, maybe even on different computers if the directories are located on a network drive). To avoid such problems, this class provides a mechanism to create directory locks.

How such a directory lock works:

Let's say that you want to open the directory "/foo/bar/". Then a lock file with the filepath "/foo/bar/.lock" will be created. After closing the directory, the lock file will be removed. So, while the directory (e.g. a project) is open, there will be a lock file in the same directory. If the same or another instance of the application now wants to open the same directory at the same time, the lock file is detected and opening the directory will be denied.

The lock file is a simple UTF-8 encoded text file with 5 lines with following values:

  1. The full name (first name + last name) of the user which holds the lock
  2. The username (logon name) of the user which holds the lock
  3. The hostname of the user's computer which holds the lock
  4. The process id (PID) of the application instance which holds the lock
  5. The process name of the application instance which holds the lock
  6. The datetime when the lock file was created/updated (UTC and ISO format!)

Example:

Homer Simpson
homer
homer-workstation
1234
librepcb
2013-04-13T12:43:52Z

The lock file (and especially its content) is also used to detect application crashes. If the application crashes while a directory was locked, the lock file will still exist after the application was crashed. Now, if the user tries to open the locked directory again, the content of the lock file will be parsed. If the username and the hostname in the lock file is equal to the current user which tries to get the lock, it's clear that the lock file does NOT exist because the locked directory is already open, but that the application was crashed while the directory was locked. If there exists a backup of the locked directory (e.g. project auto-save), this allows to ask the user whether the backup should be restored or not.

How to use this class:

First, you need to create an instance of this class for the directory you want to protect with a lock. There are two different constructors for this purpose. If you use the default constructor, you need to call setDirToLock() afterwards. Now you can read the lock status of the specified directory with getStatus(). With lock() you can create the lock file, and with unlock() you can remove the lock file. There are also the two convenience methods tryLock() and unlockIfLocked(), just read their documentation for more information.

Note
The destructor will automatically call unlockIfLocked(). This allows a reliable implementation of a directory lock, because you can add a DirectoryLock instance to the attributes of your class which access a directory which should be locked. This will ensure that the lock will be released when your object gets destroyed (RAII). See the code example below.

Code Example:

class MyDirectoryOpeningClass // a class which opens a directory and needs
to lock it
{
public:
MyDirectoryOpeningClass() // constructor
: myLock(FilePath("C:/myDirectory")) // variant 1 to set the
filepath
{
myLock.setDirToLock(FilePath("C:/myDirectory")); // variant 2
switch (myLock.getStatus()) // Note: this line can throw an
exception!
{
case Unlocked:
// No lock exists --> lock the directory now
myLock.lock(); // Note: this line can throw an
exception! break; case Locked:
// The directory is already locked by another instance!
throw Exception("Directory is locked!");
break;
case StaleLock:
// The application was crashed while the lock was
active.
// Ask the user whether a backup should be restored or
not. break; default:
// Should not happen...
break;
}
// if you don't care about stale locks, you could just do this
instead:
// myLock.tryLock(); // Note: this line can throw an exception!
}
~MyDirectoryOpeningClass() // destructor
{
// You do not have to (but you could) call
myLock.unlockIfLocked(),
// as it will be called automatically in the destructor of
myLock.
// try { myLock.unlockIfLocked(); } catch (...) { }
}
private:
DirectoryLock myLock; // an instance, not only a pointer (important
for RAII)!
};
Author
ubruhin
Date
2014-07-29

Member Enumeration Documentation

enum LockStatus
strong

The return type of getStatus()

Enumerator
Unlocked 

the directory is not locked (lock file does not exist)

Locked 

the directory is locked by another application instance

StaleLock 

the directory is locked by a crashed application instance

Constructor & Destructor Documentation

DirectoryLock ( )
noexcept

The default constructor.

Warning
If you use this constructor, you need to call setDirToLock() afterwards (before calling any other method of this class)!
DirectoryLock ( const DirectoryLock other)
delete

Copy constructor.

Parameters
otherThe object to copy
DirectoryLock ( const FilePath dir)
explicitnoexcept

A constructor which will call setDirToLock()

Parameters
dirSee setDirToLock()
~DirectoryLock ( )
noexcept

The destructor (this may also unlock the locked file)

Note
The destructor will also try to unlock the directory if it was locked with this object.

+ Here is the call graph for this function:

Member Function Documentation

void setDirToLock ( const FilePath dir)
noexcept

Specify the directory for which you need the lock.

Parameters
filepathThe filepath to the directory to lock
Warning
This method must not be called when this object already holds a lock!
const FilePath& getDirToLock ( ) const
inlinenoexcept

Get the filepath of the directory to lock (passed by setDirToLock())

Returns
The filepath to the directory to lock (invalid if no filepath was set)
const FilePath& getLockFilepath ( ) const
inlinenoexcept

Get the filepath of the lock file (NOT the directory to lock!)

Returns
The filepath to the lock file (invalid if no valid filepath was set)
DirectoryLock::LockStatus getStatus ( ) const

Get the lock status of the specified directory.

Returns
The current lock status (see LockStatus)
Exceptions
Exceptionon error (e.g. invalid filepath, no access rights, ...)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void tryLock ( bool *  wasStale = nullptr)

Lock the specified directory if not already locked.

This is a save method to get a lock without the need for first reading the lock status with getStatus(). Depending on the lock status, this method does following:

  • Unlocked: Set "wasStale = false" and get the lock (calling lock())
  • StaleLock: Set "wasStale = true" and get the lock (calling lock())
  • Locked: Throw exception (something like "Directory already locked")
Parameters
wasStaleThis variable will be set to true if there was a stale lock, and to false if not (if a valid pointer was passed).
Exceptions
Exceptionon error (e.g. already locked, no access rights, ...)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool unlockIfLocked ( )

Unlock the specified directory if it was locked by this object.

If the specified directory is locked by this object, this method calls unlock(). Otherwise this method does nothing.

Returns
True if the lock has been released by this object, false otherwise.
Exceptions
Exceptionon error (e.g. invalid filepath, no access rights, ...)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void lock ( )

Lock the specified directory (create/update the lock file)

Warning
This method will always overwrite an already existing lock file, even if it was created by another application instance! So: Always check the lock status first with getStatus(), or use tryLock() instead!
Exceptions
Exceptionon error (e.g. invalid filepath, no access rights, ...)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void unlock ( )

Unlock the specified directory (remove the lock file)

Warning
This method will always remove an existing lock file, even if it was created by another application instance! So: Always check the lock status first with getStatus(), or use unlockIfLocked() instead!
Exceptions
Exceptionon error (e.g. invalid filepath, no access rights, ...)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

DirectoryLock& operator= ( const DirectoryLock rhs)
delete

Member Data Documentation

FilePath mDirToLock
private

The filepath to the directory to lock (passed by setDirToLock())

FilePath mLockFilePath
private

The filepath to the lock file.

Example: If the filepath "/foo/bar" was passed to setDirToLock(), this attribute will have the value "/foo/bar/.lock".

bool mLockedByThisObject
private

This attribute defines if the lock is active by this object.

If lock() was called successfully, mLockedByThisObject is set to true. If unlock() was called successfully, mLockedByThisObject is set to false.

In other words: This attribute is true while this object has the ownership over the lock file (between calling lock() and unlock()).

The only goal of this attrubute is to decide whether the destructor should remove the lock or not. If the destructor is called while this attribute is true, the destructor will call unlock() to remove the file lock.


The documentation for this class was generated from the following files: