Skip to content

Commit 4247c3c

Browse files
Christophe Meynardmeynardc
authored andcommitted
MMVII: FileLock to allow multi procress concurrent writes in same image
1 parent f18d684 commit 4247c3c

File tree

4 files changed

+139
-8
lines changed

4 files changed

+139
-8
lines changed

MMVII/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ src/GeneratedCodes/
2828
/build/*
2929
!/build/.keep
3030
!/build/NoCompile.sh
31+
/.cache

MMVII/include/MMVII_Sys.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include <unistd.h>
66
#endif
77

8-
#include "MMVII_AllClassDeclare.h"
98
#include "cMMVII_Appli.h"
109

1110
namespace MMVII
@@ -59,6 +58,29 @@ int GlobParalSysCallByMkF(const std::string & aNameMkF,const std::list<cParamCal
5958
std::string MMVII_CanonicalRootDirFromExec();
6059

6160

61+
class FileLock
62+
{
63+
public:
64+
FileLock();
65+
explicit FileLock(const std::string& name);
66+
~FileLock();
67+
bool lock(const std::string& name);
68+
void unlock();
69+
bool hasLock();
70+
71+
private:
72+
#ifdef WIN32
73+
void *mHandle = nullptr;
74+
#else
75+
int mFd = -1;
76+
#endif
77+
void doLock(const std::string& name);
78+
void doUnlock();
79+
bool doHasLock();
80+
};
81+
82+
83+
6284
};
6385

6486
#endif // _MMVII_Sys_H_

MMVII/src/ImagesBase/cGdalApi.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#ifndef CGDALAPI_H
22
#define CGDALAPI_H
33

4-
#include <MMVII_enums.h>
5-
#include <MMVII_Error.h>
6-
#include <MMVII_Ptxd.h>
7-
#include <MMVII_Image2D.h>
4+
#include "MMVII_Sys.h"
5+
#include "MMVII_enums.h"
6+
#include "MMVII_Error.h"
7+
#include "MMVII_Ptxd.h"
8+
#include "MMVII_Image2D.h"
89

910
#include <string>
1011
#include <gdal_priv.h>
@@ -97,6 +98,8 @@ class cGdalApi {
9798
/****************************************************
9899
* PRIVATE
99100
*****************************************************/
101+
102+
100103
/*******************************************
101104
* GDalIO
102105
* Helper class that does the real IO
@@ -162,6 +165,7 @@ class GdalIO {
162165
mGdalDataset = cGdalApi::OpenDataset(aDF.Name(), aMode==IoMode::Read ? GA_ReadOnly : GA_Update, cGdalApi::eOnError::RaiseError);
163166
}
164167

168+
FileLock gdalLock;
165169
if (aMode == IoMode::Read) {
166170
if (mGdalNbChan == mNbImg && mNbImg != 0) {
167171
GdalReadNtoN(aVecImV2,aRectIm,aRectFile,aDyn); // file N -> N img channels
@@ -173,6 +177,8 @@ class GdalIO {
173177
MMVII_INTERNAL_ERROR("Gdal read: Images vector size: " + std::to_string(mNbImg) + ", file channels: " + std::to_string(mGdalNbChan) + " (" + aName + ")");
174178
}
175179
} else {
180+
if (! notUpdatable)
181+
gdalLock.lock(aName);
176182
if (mGdalNbChan == mNbImg && mNbImg != 0) {
177183
GdalWriteNtoN(aVecImV2,aRectIm,aRectFile,aDyn); // img N -> N file channels
178184
} else if (mGdalNbChan != 0 && mNbImg == 1) {
@@ -192,6 +198,7 @@ class GdalIO {
192198
cGdalApi::CloseDataset(mFinalDataset);
193199
}
194200
cGdalApi::CloseDataset(mGdalDataset);
201+
gdalLock.unlock();
195202
}
196203

197204
private:
@@ -200,15 +207,17 @@ class GdalIO {
200207
class GDalBuffer
201208
{
202209
public:
203-
GDalBuffer(const cRect2& aRectIm, int nbChan=1)
210+
explicit GDalBuffer(const cRect2& aRectIm, int nbChan=1)
204211
: mBuffer(nbChan)
205212
, mRectIm(aRectIm)
206213
{
207214
auto aSize = sizeof(TypeFile)*aRectIm.Sz().x()*aRectIm.Sz().y();
208-
for (auto& aBuf : mBuffer)
215+
std::generate(mBuffer.begin(), mBuffer.end(),[aSize](){return static_cast<TypeFile*>(cMemManager::Calloc(1,aSize));});
216+
/* for (auto& aBuf : mBuffer)
209217
{
210-
aBuf = (TypeFile*) cMemManager::Calloc(1,aSize);
218+
aBuf = static_cast<TypeFile*>(cMemManager::Calloc(1,aSize));
211219
}
220+
*/
212221
}
213222
~GDalBuffer()
214223
{

MMVII/src/Utils/uti_sysdep.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#if (THE_MACRO_MMVII_SYS==MMVII_SYS_L) // Linux
1515
# include <unistd.h>
16+
# include <fcntl.h>
1617
#elif (THE_MACRO_MMVII_SYS==MMVII_SYS_W) // Windows
1718
# include <windows.h>
1819
# include <process.h>
@@ -166,6 +167,104 @@ int GlobParalSysCallByMkF(const std::string & aNameMkF,const std::list<cParamCal
166167
}
167168
}
168169

170+
FileLock::FileLock()
171+
{
172+
}
173+
174+
FileLock::FileLock(const std::string& name)
175+
{
176+
lock(name);
177+
}
178+
179+
FileLock::~FileLock()
180+
{
181+
unlock();
182+
}
183+
184+
bool FileLock::lock(const std::string& name)
185+
{
186+
if (hasLock())
187+
return false;
188+
doLock(name);
189+
return true;
190+
}
191+
192+
void FileLock::unlock()
193+
{
194+
if (hasLock())
195+
doUnlock();
196+
}
197+
198+
bool FileLock::hasLock()
199+
{
200+
return doHasLock();
201+
}
202+
203+
204+
#ifdef WIN32
205+
void FileLock::doLock(const std::string& fileName)
206+
{
207+
auto mutexName = std::filesystem::canonical(fileName).wstring();
208+
if (mutexName.length() < MAX_PATH) {
209+
std::replace( mutexName.begin(), mutexName.end(), '\\', '/');
210+
} else {
211+
auto key1 = std::hash<std::wstring>{}(mutexName);
212+
auto key2 = std::hash<std::wstring>{}(std::wstring(mutexName.rbegin(),mutexName.rend()));
213+
std::wstringstream ss;
214+
ss << std::hex << std::setw(16) << std::setfill(L'0') << key1 << "/" << key2;
215+
mutexName = ss.str();
216+
}
217+
mHandle = CreateMutexW(NULL, FALSE, mutexName.c_str());
218+
219+
if (!mHandle) {
220+
MMVII_INTERNAL_ERROR("Can't create Mutex on file '" + fileName + "'");
221+
}
222+
DWORD wait = WaitForSingleObject(mHandle, INFINITE);
223+
if (wait != WAIT_OBJECT_0 && wait != WAIT_ABANDONED) {
224+
MMVII_INTERNAL_ERROR("Can't wait for Mutex on file '" + fileName + "'");
225+
}
226+
}
227+
228+
void FileLock::doUnlock()
229+
{
230+
ReleaseMutex(mHandle);
231+
CloseHandle(mHandle);
232+
mHandle = nullptr;
233+
}
234+
235+
bool FileLock::doHasLock()
236+
{
237+
return mHandle != nullptr;
238+
}
239+
#else
240+
void FileLock::doLock(const std::string& fileName)
241+
{
242+
mFd = open(fileName.c_str(), O_WRONLY | O_CREAT,0666);
243+
if (mFd < 0) {
244+
MMVII_INTERNAL_ERROR("Can't open for locking: '" + fileName + "'");
245+
}
246+
auto ret = lockf(mFd, F_LOCK, 0);
247+
if (ret < 0) {
248+
MMVII_INTERNAL_ERROR("Can't lock file '" + fileName + "'");
249+
}
250+
}
251+
252+
void FileLock::doUnlock()
253+
{
254+
if (lockf(mFd, F_ULOCK, 0))
255+
mFd = -1;
256+
}
257+
258+
bool FileLock::doHasLock()
259+
{
260+
return mFd >= 0;
261+
}
262+
#endif
263+
264+
265+
266+
267+
169268
static fs::path MMVII_RawSelfExecName();
170269

171270

0 commit comments

Comments
 (0)