CMS 3D CMS Logo

LStoreFile.cc
Go to the documentation of this file.
4 #include <cassert>
5 #include <vector>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <pthread.h>
9 #include <dlfcn.h>
10 #include <iostream>
11 #include <cstring>
12 
13 using namespace edm::storage;
14 
15 // dlsym isn't reentrant, need a locak around it
16 pthread_mutex_t LStoreFile::m_dlopen_lock = PTHREAD_MUTEX_INITIALIZER;
17 
19  : m_fd(nullptr),
20  m_close(false),
21  m_name(),
22  m_library_handle(nullptr),
23  m_is_loaded(false),
24  redd_init(nullptr),
25  redd_read(nullptr),
26  redd_close(nullptr),
27  redd_lseek(nullptr),
28  redd_open(nullptr),
29  redd_write(nullptr),
30  redd_term(nullptr),
31  redd_errno(nullptr),
32  redd_strerror(nullptr) {
33  loadLibrary();
34 }
35 
37  : m_fd(fd),
38  m_close(true),
39  m_name(),
40  m_library_handle(nullptr),
41  m_is_loaded(false),
42  redd_init(nullptr),
43  redd_read(nullptr),
44  redd_close(nullptr),
45  redd_lseek(nullptr),
46  redd_open(nullptr),
47  redd_write(nullptr),
48  redd_term(nullptr),
49  redd_errno(nullptr),
50  redd_strerror(nullptr) {
51  loadLibrary();
52 }
53 
54 LStoreFile::LStoreFile(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */)
55  : m_fd(nullptr), m_close(false), m_is_loaded(false) {
56  loadLibrary();
57  open(name, flags, perms);
58 }
59 
60 LStoreFile::LStoreFile(const std::string &name, int flags /* = IOFlags::OpenRead*/, int perms /* = 066 */)
61  : m_fd(nullptr), m_close(false), m_is_loaded(false) {
62  loadLibrary();
63  open(name.c_str(), flags, perms);
64 }
65 
67  if (m_close)
68  edm::LogError("LStoreFileError") << "Destructor called on LStore file '" << m_name
69  << "' but the file is still open";
70  closeLibrary();
71 }
72 
73 // Helper macro to perform dlsym()
74 // Double cast is supposed to be more compliant
75 // otherwise, GCC complains with the pointer conversion
76 #define REDD_LOAD_SYMBOL(NAME, TYPE) \
77  dlerror(); \
78  NAME = reinterpret_cast<TYPE>(reinterpret_cast<size_t>(dlsym(m_library_handle, #NAME))); \
79  if ((retval = dlerror())) { \
80  throw cms::Exception("LStoreFile::loadLibrary()") << "Failed to load dlsym LStore library: " << retval; \
81  } \
82  if (NAME == NULL) { \
83  throw cms::Exception("LStoreFile::loadLibrary()") << "Got a null pointer back from dlsym()\n"; \
84  }
85 
87  edm::LogError("LStoreFile::loadLibrary()") << "Loading library\n";
89  // until ACCRE removes the java dependency from their client libs,
90  // we'll dlopen() them so they don't need to be brought along with cmssw
91  // if you're running LStore at your site, you will have the libs anyway
92  // TODO add wrappers to make this work in OSX as well (CMSSW's getting ported?)
93  // TODO should be easy, just need to know the "proper" way to do #if OSX
94  // -Melo
95 
96  m_library_handle = dlopen("libreddnet.so", RTLD_LAZY);
97  if (m_library_handle == nullptr) {
98  throw cms::Exception("LStoreFile::loadLibrary()") << "Can't dlopen() LStore libraries: " << dlerror();
99  }
100 
101  char *retval = nullptr;
102  // Explicitly state the size of these values, keeps weird 64/32 bit stuff away
103  REDD_LOAD_SYMBOL(redd_init, int32_t(*)());
104  REDD_LOAD_SYMBOL(redd_read, int64_t(*)(void *, char *, int64_t));
105  REDD_LOAD_SYMBOL(redd_lseek, int64_t(*)(void *, int64_t, uint32_t));
106  REDD_LOAD_SYMBOL(redd_open, void *(*)(const char *, int, int));
107  REDD_LOAD_SYMBOL(redd_write, int64_t(*)(void *, const char *, int64_t));
108  REDD_LOAD_SYMBOL(redd_term, int32_t(*)());
109  REDD_LOAD_SYMBOL(redd_errno, int32_t(*)());
111 
112  if ((*redd_init)()) {
113  throw cms::Exception("LStoreFile::loadLibrary()") << "Error in redd_init: " << (*redd_strerror)();
114  }
115  m_is_loaded = true;
116 }
117 
119  try {
120  LStoreFile::MutexWrapper lockObj(&this->m_dlopen_lock);
121 
122  // What is the correct idiom for propagating error messages
123  // in functions that are exclusively called in destructors?
124  // Seriously. I have no idea
125  // melo
126  if (m_is_loaded) {
127  if ((*redd_term)()) {
128  throw cms::Exception("LStoreFile::closeLibrary()") << "Error in redd_term: " << (*redd_strerror)();
129  }
130  }
131  if (m_library_handle != nullptr) {
132  if (dlclose(m_library_handle)) {
133  throw cms::Exception("LStoreFile::closeLibrary()") << "Error on dlclose(): " << dlerror();
134  }
135  }
136  } catch (cms::Exception &e) {
137  edm::LogError("LStoreFileError") << "LStoreFile had an error in its destructor: " << e;
138  }
139  m_is_loaded = false;
140 }
141 
143 void LStoreFile::create(const char *name, bool exclusive /* = false */, int perms /* = 066 */) {
144  open(name,
146  perms);
147 }
148 
149 void LStoreFile::create(const std::string &name, bool exclusive /* = false */, int perms /* = 066 */) {
150  open(name.c_str(),
152  perms);
153 }
154 
155 void LStoreFile::open(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
156  open(name.c_str(), flags, perms);
157 }
158 
159 void LStoreFile::open(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
160  // Actual open
161  if ((name == nullptr) || (*name == 0))
162  throw cms::Exception("LStoreFile::open()") << "Cannot open a file without a name";
163 
164  if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0)
165  throw cms::Exception("LStoreFile::open()") << "Must open file '" << name << "' at least for read or write";
166 
167  // If I am already open, close old file first
168  if (m_fd != nullptr && m_close)
169  close();
170 
171  // Translate our flags to system flags
172  int openflags = 0;
173 
175  openflags |= O_RDWR;
176  else if (flags & IOFlags::OpenRead)
177  openflags |= O_RDONLY;
178  else if (flags & IOFlags::OpenWrite)
179  openflags |= O_WRONLY;
180 
182  openflags |= O_NONBLOCK;
183 
185  openflags |= O_APPEND;
186 
188  openflags |= O_CREAT;
189 
191  openflags |= O_EXCL;
192 
194  openflags |= O_TRUNC;
195 
196  void *newfd = nullptr;
197  if ((newfd = (*redd_open)(name, openflags, perms)) == nullptr)
198  throw cms::Exception("LStoreFile::open()")
199  << "redd_open(name='" << name << "', flags=0x" << std::hex << openflags << ", permissions=0" << std::oct
200  << perms << std::dec << ") => error '" << (*redd_strerror)() << "' (redd_errno=" << (*redd_errno)() << ")";
201 
202  m_name = name;
203  m_fd = newfd;
204 
205  m_close = true;
206 
207  edm::LogInfo("LStoreFileInfo") << "Opened " << m_name;
208 }
209 
210 void LStoreFile::close(void) {
211  if (m_fd == nullptr) {
212  edm::LogError("LStoreFileError") << "LStoreFile::close(name='" << m_name << "') called but the file is not open";
213  m_close = false;
214  return;
215  }
216  edm::LogInfo("LStoreFile::close()") << "closing " << m_name << std::endl;
217  if ((*redd_close)(m_fd) == -1)
218  edm::LogWarning("LStoreFileWarning") << "redd_close(name='" << m_name << "') failed with error '"
219  << (*redd_strerror)() << "' (redd_errno=" << (*redd_errno)() << ")";
220 
221  m_close = false;
222  m_fd = nullptr;
223 
224  // Caused hang. Will be added back after problem is fixed.
225  // edm::LogInfo("LStoreFileInfo") << "Closed " << m_name;
226 }
227 
228 void LStoreFile::abort(void) {
229  if (m_fd != nullptr)
230  (*redd_close)(m_fd);
231 
232  m_close = false;
233  m_fd = nullptr;
234 }
235 
237  IOSize done = 0;
238  while (done < n) {
239  ssize_t s = (*redd_read)(m_fd, (char *)into + done, n - done);
240  if (s == -1)
241  throw cms::Exception("LStoreFile::read()")
242  << "redd_read(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << (*redd_strerror)()
243  << "' (redd_errno=" << (*redd_errno)() << ")";
244  done += s;
245  }
246  return done;
247 }
248 
249 IOSize LStoreFile::write(const void *from, IOSize n) {
250  IOSize done = 0;
251  while (done < n) {
252  ssize_t s = (*redd_write)(m_fd, (const char *)from + done, n - done);
253  if (s == -1)
254  throw cms::Exception("LStoreFile::write()")
255  << "redd_write(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << (*redd_strerror)()
256  << "' (redd_errno=" << (*redd_errno)() << ")";
257  done += s;
258  }
259 
260  return done;
261 }
266  if (m_fd == nullptr)
267  throw cms::Exception("LStoreFile::position()") << "LStoreFile::position() called on a closed file";
268  if (whence != CURRENT && whence != SET && whence != END)
269  throw cms::Exception("LStoreFile::position()") << "LStoreFile::position() called with incorrect 'whence' parameter";
270 
272  uint32_t mywhence = (whence == SET ? SEEK_SET : whence == CURRENT ? SEEK_CUR : SEEK_END);
273  if ((result = (*redd_lseek)(m_fd, (off_t)offset, (uint32_t)mywhence)) == -1)
274  throw cms::Exception("LStoreFile::position()")
275  << "redd_lseek64(name='" << m_name << "', offset=" << offset << ", whence=" << mywhence
276  << ") failed with error '" << (*redd_strerror)() << "' (redd_errno=" << (*redd_errno)() << ")";
277  return result;
278 }
279 
280 void LStoreFile::resize(IOOffset /* size */) {
281  throw cms::Exception("LStoreFile::resize()") << "LStoreFile::resize(name='" << m_name << "') not implemented";
282 }
283 
285 
287  m_lock = target;
288  pthread_mutex_lock(m_lock); // never fails
289 }
290 
292  int retval;
293  if ((retval = pthread_mutex_unlock(m_lock))) {
294  // congrats. pthread_mutex_lock failed and we're in a destructor
295  // I don't know what to do here
296  // Then again, if the mutex is jammed, things are already boned
297  // Cry for a second, then continue with life, I guess
298  // melo
299 
300  char buf[1024];
301  edm::LogError("LStoreFileError") << "LStoreFile couldn't unlock a mutex. Not good."
302  << strerror_r(retval, buf, 1024);
303  }
304 }
int64_t IOOffset
Definition: IOTypes.h:20
int64_t(* redd_read)(void *, char *, int64_t)
Definition: LStoreFile.h:62
IOSize write(const void *from, IOSize n) override
Definition: LStoreFile.cc:249
void close(void) override
Definition: LStoreFile.cc:210
virtual void abort(void)
Definition: LStoreFile.cc:228
int64_t(* redd_lseek)(void *, int64_t, uint32_t)
Definition: LStoreFile.h:64
int32_t(* redd_close)(void *)
Definition: LStoreFile.h:63
void *(* redd_open)(const char *, int32_t, int32_t)
Definition: LStoreFile.h:65
Log< level::Error, false > LogError
MutexWrapper(pthread_mutex_t *lock)
Definition: LStoreFile.cc:286
virtual void create(const char *name, bool exclusive=false, int perms=0666)
Definition: LStoreFile.cc:143
virtual void open(const char *name, int flags=IOFlags::OpenRead, int perms=0666)
Definition: LStoreFile.cc:159
int64_t(* redd_write)(void *, const char *, int64_t)
Definition: LStoreFile.h:66
~LStoreFile(void) override
Definition: LStoreFile.cc:66
int32_t(* redd_term)()
Definition: LStoreFile.h:67
int32_t(* redd_errno)()
Definition: LStoreFile.h:68
void resize(IOOffset size) override
Definition: LStoreFile.cc:280
Log< level::Info, false > LogInfo
size_t IOSize
Definition: IOTypes.h:15
const std::string &(* redd_strerror)()
Definition: LStoreFile.h:69
#define REDD_LOAD_SYMBOL(NAME, TYPE)
Definition: LStoreFile.cc:76
int32_t(* redd_init)()
Definition: LStoreFile.h:61
virtual IOOffset position() const
Definition: Storage.cc:504
#define O_NONBLOCK
Definition: SysFile.h:23
Log< level::Warning, false > LogWarning
fd
Definition: ztee.py:136
static pthread_mutex_t m_dlopen_lock
Definition: LStoreFile.h:42