Sparse Virtual File System  0.4.1
A Sparse Virtual File System.
_cSVFS.cpp
Go to the documentation of this file.
1 
35 #include "cp_svfs.h"
36 
37 #include <ctime>
38 #include <memory>
39 
40 #include "svfs.h"
41 #include "svfs_util.h"
42 
43 /* TODO: Implement pickling an SVFS?
44  * TODO: Implement the Buffer Protocol rather than returning a copy of the bytes? Look for PyBytes_FromStringAndSize().
45  * */
46 
50 #define SVFS_SVFS_METHOD_SIZE_T_WRAPPER(method_name, docstring) \
51 PyDoc_STRVAR( \
52  cp_SparseVirtualFileSystem_svf_##method_name##_docstring, \
53  #method_name"(self, id: str) -> int\n\n" \
54  docstring \
55 );\
56 static PyObject * \
57 cp_SparseVirtualFileSystem_svf_##method_name(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) { \
58  ASSERT_FUNCTION_ENTRY_SVFS(p_svfs); \
59  PyObject *ret = NULL; \
60  char *c_id = NULL; \
61  std::string cpp_id; \
62  AcquireLockSVFS _lock(self); \
63  static const char *kwlist[] = { "id", NULL}; \
64  if (! PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **)kwlist, &c_id)) { \
65  goto except; \
66  } \
67  cpp_id = std::string(c_id); \
68  try { \
69  if (self->p_svfs->has(cpp_id)) { \
70  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id); \
71  ret = PyLong_FromLong(svf.method_name()); \
72  } else { \
73  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id); \
74  goto except; \
75  } \
76  } catch (const std::exception &err) { \
77  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what()); \
78  goto except; \
79  } \
80  assert(! PyErr_Occurred()); \
81  assert(ret); \
82  goto finally; \
83 except: \
84  assert(PyErr_Occurred()); \
85  Py_XDECREF(ret); \
86  ret = NULL; \
87 finally: \
88  return ret; \
89 }
90 
91 
97 typedef struct {
98  PyObject_HEAD
100 #ifdef PY_THREAD_SAFE
101  PyThread_type_lock lock;
102 #endif
104 
105 #ifdef PY_THREAD_SAFE
106 
112 public:
114  assert(_pSVFS);
115  assert(_pSVFS->lock);
116  if (!PyThread_acquire_lock(_pSVFS->lock, NOWAIT_LOCK)) {
117  Py_BEGIN_ALLOW_THREADS
118  PyThread_acquire_lock(_pSVFS->lock, WAIT_LOCK);
119  Py_END_ALLOW_THREADS
120  }
121  }
122 
124  assert(_pSVFS);
125  assert(_pSVFS->lock);
126  PyThread_release_lock(_pSVFS->lock);
127  }
128 
129 private:
131 };
132 
133 #else
134 /* Make the class a NOP which should get optimised out. */
135 class AcquireLockSVFS {
136 public:
138 };
139 #endif
140 
141 // Function entry point test macro.
142 // After construction, we expect this invariant at the entry to each function.
143 // The cast is necessary when used with functions that take a SVFS as a PyObject* such as
144 // cp_SparseVirtualFileSystem_mapping_length
145 #define ASSERT_FUNCTION_ENTRY_SVFS(member) do { \
146  assert(self); \
147  assert(((cp_SparseVirtualFileSystem *)self)->member); \
148  assert(! PyErr_Occurred()); \
149 } while (0)
150 
151 
152 // Construction and destruction
153 #pragma mark Construction and destruction
154 
155 static PyObject *
156 cp_SparseVirtualFileSystem_new(PyTypeObject *type, PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(kwds)) {
157  assert(!PyErr_Occurred());
159  self = (cp_SparseVirtualFileSystem *) type->tp_alloc(type, 0);
160  if (self != NULL) {
161  self->p_svfs = nullptr;
162 #ifdef PY_THREAD_SAFE
163  self->lock = NULL;
164 #endif
165  }
166 // PyObject_Print((PyObject *)self, stdout);
167 // fprintf(stdout, "cp_SparseVirtualFileSystem_new() self %p\n", (void *)self);
168  assert(!PyErr_Occurred());
169  return (PyObject *) self;
170 }
171 
172 static int
173 cp_SparseVirtualFileSystem_init(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
174  assert(!PyErr_Occurred());
175  static const char *kwlist[] = {"overwrite_on_exit", "compare_for_diff", NULL};
177 
178 // TRACE_SELF_ARGS_KWARGS;
179 // fprintf(stdout, "Config was compare_for_diff=%d overwrite_on_exit=%d\n", config.compare_for_diff,
180 // config.overwrite_on_exit);
181 
182  // NOTE: With format unit 'p' we need to pass in an int.
183  int overwrite_on_exit = config.overwrite_on_exit ? 1 : 0;
184  int compare_for_diff = config.compare_for_diff ? 1 : 0;
185 
186  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|pp", (char **) kwlist, &overwrite_on_exit, &compare_for_diff)) {
187  assert(PyErr_Occurred());
188  return -1;
189  }
190  config.overwrite_on_exit = overwrite_on_exit != 0;
191  config.compare_for_diff = compare_for_diff != 0;
192 
193 // fprintf(stdout, "Config now compare_for_diff=%d overwrite_on_exit=%d\n", config.compare_for_diff,
194 // config.overwrite_on_exit);
195 
196  self->p_svfs = new SVFS::SparseVirtualFileSystem(config);
197 #ifdef PY_THREAD_SAFE
198  self->lock = PyThread_allocate_lock();
199  if (self->lock == NULL) {
200  delete self->p_svfs;
201  PyErr_SetString(PyExc_MemoryError, "Unable to allocate thread lock.");
202  return -2;
203  }
204 #endif
205 // fprintf(stdout, "cp_SparseVirtualFileSystem_init() self->p_svfs %p\n", (void *)self->p_svfs);
206  assert(!PyErr_Occurred());
207  return 0;
208 }
209 
210 static void
212 #ifdef PY_THREAD_SAFE
213  if (self->lock) {
214  PyThread_free_lock(self->lock);
215  self->lock = NULL;
216  }
217 #endif
218  delete self->p_svfs;
219  Py_TYPE(self)->tp_free((PyObject *) self);
220 }
221 
222 // END: Construction and destruction
223 #pragma mark END: Construction and destruction
224 
225 // SVFS functions
226 #pragma mark SVFS functions
227 
229  cp_SparseVirtualFileSystem_keys_docstring,
230  "keys(self) -> typing.List[str]\n\n"
231  "Returns the IDs of all the Sparse Virtual Files in the Sparse Virtual File System."
232 );
233 
234 static PyObject *
237 
238  Py_ssize_t index = 0;
239  PyObject * key = NULL;
240  // All items set to NULL on construction.
241  PyObject * ret = PyList_New(self->p_svfs->size());
242  AcquireLockSVFS _lock(self);
243 
244  if (!ret) {
245  PyErr_Format(PyExc_RuntimeError, "%s: Can create list of size %d", __FUNCTION__, self->p_svfs->size());
246  goto except;
247  }
248  try {
249  for (const auto &cpp_key: self->p_svfs->keys()) {
250  key = PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, cpp_key.c_str(), cpp_key.size());
251  if (!key) {
252  PyErr_Format(PyExc_RuntimeError, "%s: Can create key for %s", __FUNCTION__, cpp_key.c_str());
253  goto except;
254  }
255  // No error checking for this line. Steals reference.
256  PyList_SET_ITEM(ret, index, key);
257  key = NULL; // Safety habit with stolen reference.
258  ++index;
259  }
260  } catch (const std::exception &err) {
261  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
262  goto except;
263  }
264  assert(!PyErr_Occurred());
265  assert(ret);
266  goto finally;
267  except:
268  assert(PyErr_Occurred());
269  if (ret) {
270  for (Py_ssize_t i = 0; i < PyList_Size(ret); ++i) {
271  Py_XDECREF(PyList_GET_ITEM(ret, i));
272  }
273  }
274  Py_XDECREF(ret);
275  ret = NULL;
276  finally:
277  return ret;
278 }
279 
281  cp_SparseVirtualFileSystem_insert_docstring,
282  "insert(self, id: str) -> None\n\n"
283  "Inserts a Sparse Virtual File of ID and Unix file modification time as a float."
284 );
285 
286 static PyObject *
287 cp_SparseVirtualFileSystem_insert(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
289 
290  PyObject * ret = NULL;
291  char *c_id = NULL;
292  double mod_time;
293  static const char *kwlist[] = {"id", "mod_time", NULL};
294  AcquireLockSVFS _lock(self);
295 
296  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd", (char **) kwlist, &c_id, &mod_time)) {
297  goto except;
298  }
299  try {
300  self->p_svfs->insert(c_id, mod_time);
302  PyErr_Format(
303  PyExc_RuntimeError, "%s: Can not insert a new Sparse Virtual File ID = \"%s\". ERROR: %s",
304  __FUNCTION__, c_id, err.message().c_str()
305  );
306  goto except;
307  } catch (const std::exception &err) {
308  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
309  goto except;
310  }
311  Py_INCREF(Py_None);
312  ret = Py_None;
313  assert(!PyErr_Occurred());
314  assert(ret);
315  goto finally;
316  except:
317  assert(PyErr_Occurred());
318  Py_XDECREF(ret);
319  ret = NULL;
320  finally:
321  return ret;
322 }
323 
325  cp_SparseVirtualFileSystem_remove_docstring,
326  "remove(self, id: str) -> None\n\n"
327  "Removes a Sparse Virtual File of ID freeing that file's memory. Will raise an ``IndexError`` if the ID is absent."
328 );
329 
330 static PyObject *
331 cp_SparseVirtualFileSystem_remove(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
333 
334  PyObject * ret = NULL;
335  char *c_id = NULL;
336  static const char *kwlist[] = {"id", NULL};
337  AcquireLockSVFS _lock(self);
338 
339  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist, &c_id)) {
340  goto except;
341  }
342  try {
343  self->p_svfs->remove(c_id);
345  PyErr_Format(PyExc_IndexError, "%s: Can not remove a Sparse Virtual File. ERROR: %s",
346  __FUNCTION__, err.message().c_str()
347  );
348  goto except;
349  } catch (const std::exception &err) {
350  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
351  goto except;
352  }
353  Py_INCREF(Py_None);
354  ret = Py_None;
355  assert(!PyErr_Occurred());
356  assert(ret);
357  goto finally;
358  except:
359  assert(PyErr_Occurred());
360  Py_XDECREF(ret);
361  ret = NULL;
362  finally:
363  return ret;
364 }
365 
367  cp_SparseVirtualFileSystem_has_docstring,
368  "has(self, id: str) -> bool\n\n"
369  "Returns True if the Sparse Virtual File for the ID is in the Sparse Virtual File System."
370 );
371 
372 static PyObject *
373 cp_SparseVirtualFileSystem_has(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
375 
376  PyObject * ret = NULL;
377  char *c_id = NULL;
378  static const char *kwlist[] = {"id", NULL};
379 
380  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist, &c_id)) {
381  goto except;
382  }
383  try {
384  if (self->p_svfs->has(c_id)) {
385  Py_INCREF(Py_True);
386  ret = Py_True;
387  } else {
388  Py_INCREF(Py_False);
389  ret = Py_False;
390  }
391  } catch (const std::exception &err) {
392  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
393  goto except;
394  }
395  assert(!PyErr_Occurred());
396  assert(ret);
397  goto finally;
398  except:
399  assert(PyErr_Occurred());
400  Py_XDECREF(ret);
401  ret = NULL;
402  finally:
403  return ret;
404 }
405 
407  cp_SparseVirtualFileSystem_total_size_of_docstring,
408  "total_size_of(self) -> int\n\n"
409  "Returns the estimate of total memory usage of the Sparse Virtual File System."
410 );
411 
412 static PyObject *
415  try {
416  return PyLong_FromLong(self->p_svfs->size_of());
417  } catch (const std::exception &err) {
418  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
419  return NULL;
420  }
421 }
422 
424  cp_SparseVirtualFileSystem_total_bytes_docstring,
425  "total_bytes(self) -> int\n\n"
426  "Returns the total number of file bytes held by the Sparse Virtual File System."
427 );
428 
429 static PyObject *
432  try {
433  return PyLong_FromLong(self->p_svfs->num_bytes());
434  } catch (const std::exception &err) {
435  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
436  return NULL;
437  }
438 }
439 
441  cp_SparseVirtualFileSystem_total_blocks_docstring,
442  "total_blocks(self) -> int\n\n"
443  "Returns the total number of blocks of data held by the Sparse Virtual File System."
444 );
445 
446 static PyObject *
449  try {
450  return PyLong_FromLong(self->p_svfs->num_blocks());
451  } catch (const std::exception &err) {
452  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
453  return NULL;
454  }
455 }
456 
458  cp_SparseVirtualFileSystem_svf_has_data_docstring,
459  "has_data(self, id: str, file_position: int, length: int) -> bool\n\n"
460  "Checks if the Sparse Virtual File of the ID has data at the given file_position and length."
461  " This takes a string as an id, a file position and a length."
462  " This returns True if the Sparse Virtual File of that id has the data, False otherwise."
463  " This will raise an ``IndexError`` if the SVF of that id does not exist."
464 );
465 
466 static PyObject *
467 cp_SparseVirtualFileSystem_svf_has_data(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
469 
470  PyObject * ret = NULL;
471  char *c_id = NULL;
472  std::string cpp_id;
473  unsigned long long fpos = 0;
474  unsigned long long len = 0;
475  static const char *kwlist[] = {"id", "file_position", "length", NULL};
476  AcquireLockSVFS _lock(self);
477 
478  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sKK", (char **) kwlist, &c_id, &fpos, &len)) {
479  goto except;
480  }
481  cpp_id = std::string(c_id);
482  if (self->p_svfs->has(cpp_id)) {
483  try {
484  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
485  if (svf.has(fpos, len)) {
486  Py_INCREF(Py_True);
487  ret = Py_True;
488  } else {
489  Py_INCREF(Py_False);
490  ret = Py_False;
491  }
492  } catch (const std::exception &err) {
493  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
494  goto except;
495  }
496  } else {
497  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
498  goto except;
499  }
500  assert(!PyErr_Occurred());
501  assert(ret);
502  goto finally;
503  except:
504  assert(PyErr_Occurred());
505  Py_XDECREF(ret);
506  ret = NULL;
507  finally:
508  return ret;
509 }
510 
512  cp_SparseVirtualFileSystem_svf_write_docstring,
513  "write(self, id: str, file_position: int, data: bytes) -> None\n\n"
514  "Writes the data to the Sparse Virtual File of the given ID at file_position and length.\n\n"
515  "This takes a string as an id, a file position and data as a bytes object.\n"
516  "This will raise an ``IndexError`` if the SVF of that id does not exist.\n"
517  "This will raise an ``IOError`` if the given data is different than that seen before and only\n"
518  "new data up to this point will be written.\n"
519  "This will raise a ``RuntimeError`` if the data can not be written for any other reason.\n"
520 );
521 
522 static PyObject *
523 cp_SparseVirtualFileSystem_svf_write(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
525 
526  PyObject * ret = NULL;
527  char *c_id = NULL;
528  std::string cpp_id;
529  unsigned long long fpos = 0;
530  PyObject * py_bytes_data = NULL;
531  static const char *kwlist[] = {"id", "file_position", "data", NULL};
532  AcquireLockSVFS _lock(self);
533 
534  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sKS", (char **) kwlist, &c_id, &fpos, &py_bytes_data)) {
535  goto except;
536  }
537  cpp_id = std::string(c_id);
538  try {
539  if (self->p_svfs->has(cpp_id)) {
540  SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
541  try {
542  svf.write(fpos, PyBytes_AS_STRING(py_bytes_data), PyBytes_Size(py_bytes_data));
544  PyErr_Format(PyExc_IOError,
545  "%s: Can not write to a SVF id = \"%s\" as the given data is different from what is there. ERROR: %s",
546  __FUNCTION__, c_id, err.message().c_str());
547  goto except;
548  } catch (const SVFS::Exceptions::ExceptionSparseVirtualFile &err) {
549  PyErr_Format(PyExc_RuntimeError, "%s: Can not write to a SVF id = \"%s\". ERROR: %s",
550  __FUNCTION__, c_id, err.message().c_str());
551  goto except;
552  }
553  } else {
554  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
555  goto except;
556  }
557  } catch (const std::exception &err) {
558  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
559  goto except;
560  }
561  Py_INCREF(Py_None);
562  ret = Py_None;
563  assert(!PyErr_Occurred());
564  assert(ret);
565  goto finally;
566  except:
567  assert(PyErr_Occurred());
568  Py_XDECREF(ret);
569  ret = NULL;
570  finally:
571  return ret;
572 }
573 
575  cp_SparseVirtualFileSystem_svf_read_docstring,
576  "read(self, id: str, file_position: int, length: int) -> bytes\n\n"
577  "Read the data to the Sparse Virtual File at file_position and length returning a bytes object.\n"
578  "This takes a string as an id, a file position and a length.\n"
579  "\nThis will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist.\n"
580  "This will raise an ``IOError`` if any data is not present\n"
581  "This will raise a ``RuntimeError`` if the data can not be read for any other reason.\n"
582 );
583 
584 static PyObject *
585 cp_SparseVirtualFileSystem_svf_read(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
587 
588  PyObject * ret = NULL;
589  char *c_id = NULL;
590  std::string cpp_id;
591  unsigned long long fpos = 0;
592  unsigned long long len = 0;
593  static const char *kwlist[] = {"id", "file_position", "length", NULL};
594  AcquireLockSVFS _lock(self);
595 
596  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sKK", (char **) kwlist, &c_id, &fpos, &len)) {
597  goto except;
598  }
599  cpp_id = std::string(c_id);
600  try {
601  if (self->p_svfs->has(cpp_id)) {
602  SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
603  // Create a bytes object
604  ret = PyBytes_FromStringAndSize(NULL, len);
605  try {
606  svf.read(fpos, len, PyBytes_AS_STRING(ret));
608  PyErr_Format(PyExc_IOError, "%s: Can not read from a SVF id= \"%s\". ERROR: %s",
609  __FUNCTION__, c_id, err.message().c_str());
610  goto except;
611  } catch (const SVFS::Exceptions::ExceptionSparseVirtualFile &err) {
612  PyErr_Format(PyExc_RuntimeError, "%s: Fatal error reading from a SVF id= \"%s\". ERROR: %s",
613  __FUNCTION__, c_id, err.message().c_str());
614  goto except;
615  }
616  } else {
617  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
618  goto except;
619  }
620  } catch (const std::exception &err) {
621  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
622  goto except;
623  }
624  assert(!PyErr_Occurred());
625  assert(ret);
626  goto finally;
627  except:
628  assert(PyErr_Occurred());
629  Py_XDECREF(ret);
630  ret = NULL;
631  finally:
632  return ret;
633 }
634 
636  cp_SparseVirtualFileSystem_svf_erase_docstring,
637  "erase(self, id: str, file_position: int) -> None\n\n"
638  "Erases the data block in the Sparse Virtual File at a file position.\n"
639  "This takes a string as an id and a file_position.\n"
640  "This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist.\n"
641  "This will raise an ``IOError`` if there is not a block at the position.\n"
642  "This will raise a ``RuntimeError`` if the data can not be read for any other reason.\n"
643 );
644 
645 static PyObject *
646 cp_SparseVirtualFileSystem_svf_erase(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
648 
649  PyObject * ret = NULL;
650  char *c_id = NULL;
651  std::string cpp_id;
652  unsigned long long fpos = 0;
653  static const char *kwlist[] = {"id", "file_position", NULL};
654  AcquireLockSVFS _lock(self);
655 
656  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sK", (char **) kwlist, &c_id, &fpos)) {
657  goto except;
658  }
659  cpp_id = std::string(c_id);
660  try {
661  if (self->p_svfs->has(cpp_id)) {
662  SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
663  try {
664  svf.erase(fpos);
666  PyErr_Format(PyExc_IOError, "%s: Can not erase block from a SVF id= \"%s\". ERROR: %s",
667  __FUNCTION__, c_id, err.message().c_str());
668  goto except;
669  } catch (const SVFS::Exceptions::ExceptionSparseVirtualFile &err) {
670  PyErr_Format(PyExc_RuntimeError, "%s: Fatal error erasing from a SVF id= \"%s\". ERROR: %s",
671  __FUNCTION__, c_id, err.message().c_str());
672  goto except;
673  }
674  } else {
675  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
676  goto except;
677  }
678  } catch (const std::exception &err) {
679  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
680  goto except;
681  }
682  Py_INCREF(Py_None);
683  ret = Py_None;
684  assert(!PyErr_Occurred());
685  assert(ret);
686  goto finally;
687  except:
688  assert(PyErr_Occurred());
689  Py_XDECREF(ret);
690  ret = NULL;
691  finally:
692  return ret;
693 }
694 
696  cp_SparseVirtualFileSystem_svf_need_docstring,
697  "need(self, id: str, file_position: int, length: int, greedy_length: int = 0) -> typing.Tuple[typing.Tuple[int, int], ...]\n\n"
698  "Given a file_position and length this returns a ordered list ``[(file_position, length), ...]`` of seek/read"
699  " instructions of data that is required to be written to the Sparse Virtual File so that a subsequent read will succeed.\n"
700  "If greedy_length is > 0 then, if possible, blocks will be coalesced to reduce the size of the return value."
701  "\nUsage::\n\n"
702  " if not svfs.has(identity, file_position, length):\n"
703  " for fpos, read_len in svfs.need(identity, file_position, length):\n"
704  " # Somehow get the data at that seek/read position...\n"
705  " svfs.write(identity, fpos, data)\n"
706  " return svfs.read(identity, file_position, length):\n"
707 );
708 
709 static PyObject *
710 cp_SparseVirtualFileSystem_svf_need(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
712 
713  PyObject * ret = NULL; // PyListObject
714  char *c_id = NULL; // PyUnicodeObject
715  std::string cpp_id;
716  unsigned long long fpos = 0;
717  unsigned long long len = 0;
718  unsigned long long greedy_length = 0;
719  static const char *kwlist[] = {"id", "file_position", "length", "greedy_length", NULL};
720  AcquireLockSVFS _lock(self);
721 
722  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sKK|K", (char **) kwlist, &c_id, &fpos, &len, &greedy_length)) {
723  goto except;
724  }
725  cpp_id = std::string(c_id);
726  try {
727  if (self->p_svfs->has(cpp_id)) {
728  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
729  ret = cp_SparseVirtualFile_need_internal(&svf, fpos, len, greedy_length);
730  if (!ret) {
731  goto except;
732  }
733  } else {
734  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
735  goto except;
736  }
737  } catch (const std::exception &err) {
738  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
739  goto except;
740  }
741  assert(!PyErr_Occurred());
742  assert(ret);
743  goto finally;
744  except:
745  assert(PyErr_Occurred());
746  Py_XDECREF(ret);
747  ret = NULL;
748  finally:
749  return ret;
750 }
751 
753  cp_SparseVirtualFileSystem_svf_need_many_docstring,
754  "need_many(self, id: str, seek_reads: typing.List[typing.Tuple[int, int]], greedy_length: int = 0) -> typing.Tuple[typing.Tuple[int, int], ...]\n\n"
755  "Given a list of (file_position, length) this returns a ordered list ``[(file_position, length), ...]`` of seek/read"
756  " instructions of data that is required to be written to the Sparse Virtual File so that a subsequent read will"
757  " succeed.\n\n"
758  "If greedy_length is > 0 then, if possible, blocks will be coalesced to reduce the size of the return value."
759  "\n\n"
760  "See also :py:meth:`svfsc.cSVFS.need`"
761 );
762 
763 static PyObject *
766 
767  PyObject * ret = NULL; // PyListObject
768  char *c_id = NULL; // PyUnicodeObject
769  std::string cpp_id;
770 
771  PyObject * py_seek_reads = NULL;
772  unsigned long long greedy_len = 0;
773  static const char *kwlist[] = {"id", "seek_reads", "greedy_length", NULL};
774  AcquireLockSVFS _lock(self);
775 
776  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|K", (char **) kwlist, &c_id, &py_seek_reads, &greedy_len)) {
777  goto except;
778  }
779  cpp_id = std::string(c_id);
780  try {
781  if (self->p_svfs->has(cpp_id)) {
782  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
783  ret = cp_SparseVirtualFile_need_many_internal(py_seek_reads, &svf, greedy_len);
784  if (!ret) {
785  goto except;
786  }
787  } else {
788  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
789  goto except;
790  }
791  } catch (const std::exception &err) {
792  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
793  goto except;
794  }
795  assert(!PyErr_Occurred());
796  assert(ret);
797  goto finally;
798  except:
799  assert(PyErr_Occurred());
800  Py_XDECREF(ret);
801  ret = NULL;
802  finally:
803  return ret;
804 }
805 
830  cp_SparseVirtualFileSystem_svf_blocks_docstring,
831  "blocks(self, id: str) -> typing.Tuple[typing.Tuple[int, int], ...]\n\n"
832  "This returns a ordered tuple ((file_position, length), ...) of all the blocks held by the SVF identified"
833  "by the given id.\n"
834  "This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
835 );
836 
837 static PyObject *
838 cp_SparseVirtualFileSystem_svf_blocks(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) {
840 
841  PyObject * ret = NULL; // PyTupleObject
842  char *c_id = NULL; // PyUnicodeObject
843  std::string cpp_id;
844  PyObject * insert_item = NULL; // PyTupleObject
845  static const char *kwlist[] = {"id", NULL};
846  AcquireLockSVFS _lock(self);
847 
848  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist, &c_id)) {
849  goto except;
850  }
851  cpp_id = std::string(c_id);
852  try {
853  if (self->p_svfs->has(cpp_id)) {
854  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
855  SVFS::t_seek_reads seek_read = svf.blocks();
856  ret = PyTuple_New(seek_read.size());
857  if (!ret) {
858  PyErr_Format(PyExc_MemoryError, "%s: Can not create tuple for return", __FUNCTION__);
859  goto except;
860  }
861  for (size_t i = 0; i < seek_read.size(); ++i) {
862  insert_item = Py_BuildValue("KK", seek_read[i].first, seek_read[i].second);
863  if (!insert_item) {
864  PyErr_Format(PyExc_MemoryError, "%s: Can not create tuple", __FUNCTION__);
865  goto except;
866  }
867  PyTuple_SET_ITEM(ret, i, insert_item);
868  insert_item = NULL;
869  }
870  } else {
871  PyErr_Format(PyExc_IndexError, "%s: No SVF ID %s", __FUNCTION__, c_id);
872  goto except;
873  }
874  } catch (const std::exception &err) {
875  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
876  goto except;
877  }
878  assert(!PyErr_Occurred());
879  assert(ret);
880  goto finally;
881  except:
882  assert(PyErr_Occurred());
883  if (ret) {
884  for (Py_ssize_t i = 0; i < PyList_Size(ret); ++i) {
885  Py_XDECREF(PyList_GET_ITEM(ret, i));
886  }
887  }
888  Py_XDECREF(ret);
889  ret = NULL;
890  finally:
891  return ret;
892 }
893 
895  size_of,
896  "Returns the best guess of total memory usage used by the Sparse Virtual File identified by the given id."
897  " This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
898 );
899 
901  num_bytes,
902  "Returns the number of bytes of data held by the Sparse Virtual File identified by the given id."
903  " This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
904 );
905 
907  num_blocks,
908  "Returns the number of data blocks held by the Sparse Virtual File identified by the given id."
909  " This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
910 );
911 
912 
914  cp_SparseVirtualFileSystem_svf_block_touches_docstring,
915  "block_touches(self, id: str) -> typing.Dict[int, int]\n\n"
916  "This returns a dict ``{touch_int: file_position, ...}``"
917  " of the touch integer of each block mapped to the file position.\n"
918  "The caller can decide what older blocks can be used the erase(file_position)."
919 );
920 
929 static PyObject *
932 
933  PyObject * ret = NULL; // Dict
934  std::string cpp_id;
935  static const char *kwlist[] = {"id", NULL};
936  char *c_id = NULL;
937 
938  AcquireLockSVFS _lock(self);
939 
940  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist, &c_id)) {
941  goto except;
942  }
943  cpp_id = std::string(c_id);
944  try {
945  if (self->p_svfs->has(cpp_id)) {
946  SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
947  SVFS::t_block_touches svf_block_touches = svf.block_touches();
948  ret = PyDict_New();
949  if (!ret) {
950  PyErr_Format(PyExc_MemoryError, "%s: Can not create dict for return", __FUNCTION__);
951  goto except;
952  }
953  for (const auto &iter: svf_block_touches) {
954  PyObject * key = PyLong_FromLong(iter.first);
955  if (!key) {
956  PyErr_Format(PyExc_MemoryError, "%s: Can not create key", __FUNCTION__);
957  goto except;
958  }
959  PyObject * val = PyLong_FromLong(iter.second);
960  if (!val) {
961  PyErr_Format(PyExc_MemoryError, "%s: Can not create value", __FUNCTION__);
962  goto except;
963  }
964  PyDict_SetItem(ret, key, val);
965  Py_DECREF(key);
966  Py_DECREF(val);
967  }
968  } else {
969  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
970  goto except;
971  }
972  } catch (const std::exception &err) {
973  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
974  goto except;
975  }
976  assert(!PyErr_Occurred());
977  assert(ret);
978  goto finally;
979  except:
980  assert(PyErr_Occurred());
981  Py_XDECREF(ret);
982  ret = NULL;
983  finally:
984  return ret;
985 }
986 
988  cp_SparseVirtualFileSystem_svf_lru_punt_docstring,
989  "lru_punt(self, id: str, cache_size_upper_bound: int) -> int\n\n"
990  "Reduces the size of the cache to < the given size by removing older blocks, at least one block will be left.\n"
991  "There are limitations to this tactic, see the documentation in Technical Notes -> Cache Punting."
992 );
993 
1002 static PyObject *
1005 
1006  PyObject * ret = NULL; // Long
1007  size_t cache_size_upper_bound;
1008  std::string cpp_id;
1009  static const char *kwlist[] = {"id", "cache_size_upper_bound", NULL};
1010  char *c_id = NULL;
1011 
1012  AcquireLockSVFS _lock(self);
1013 
1014  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sK", (char **) kwlist, &c_id, &cache_size_upper_bound)) {
1015  goto except;
1016  }
1017  cpp_id = std::string(c_id);
1018  try {
1019  if (self->p_svfs->has(cpp_id)) {
1020  SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
1021  ret = Py_BuildValue("K", svf.lru_punt(cache_size_upper_bound));
1022  if (!ret) {
1023  PyErr_Format(PyExc_MemoryError, "%s: Can not create long", __FUNCTION__);
1024  goto except;
1025  }
1026  } else {
1027  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
1028  goto except;
1029  }
1030  } catch (const std::exception &err) {
1031  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
1032  goto except;
1033  }
1034  assert(!PyErr_Occurred());
1035  assert(ret);
1036  goto finally;
1037  except:
1038  assert(PyErr_Occurred());
1039  Py_XDECREF(ret);
1040  ret = NULL;
1041  finally:
1042  return ret;
1043 }
1044 
1046  cp_SparseVirtualFileSystem_svf_lru_punt_all_docstring,
1047  "lru_punt_all(self, cache_size_upper_bound: int) -> int\n\n"
1048  "Reduces the size of all IDs in the cache to < the given size by removing older blocks."
1049  " At least one block will be left for each ID.\n"
1050  "There are limitations to this tactic, see the documentation in Technical Notes -> Cache Punting."
1051 );
1052 
1061 static PyObject *
1064 
1065  PyObject * ret = NULL; // Long
1066  size_t cache_size_upper_bound;
1067  size_t total_removed = 0;
1068  static const char *kwlist[] = {"cache_size_upper_bound", NULL};
1069 
1070  AcquireLockSVFS _lock(self);
1071 
1072  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "K", (char **) kwlist, &cache_size_upper_bound)) {
1073  goto except;
1074  }
1075  try {
1076  for (const auto &iter: self->p_svfs->keys()) {
1077  SVFS::SparseVirtualFile &svf = self->p_svfs->at(iter);
1078  total_removed += svf.lru_punt(cache_size_upper_bound);
1079  }
1080  } catch (const std::exception &err) {
1081  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
1082  goto except;
1083  }
1084  ret = Py_BuildValue("K", total_removed);
1085  if (!ret) {
1086  PyErr_Format(PyExc_MemoryError, "%s: Can not create long", __FUNCTION__);
1087  goto except;
1088  }
1089  assert(!PyErr_Occurred());
1090  assert(ret);
1091  goto finally;
1092  except:
1093  assert(PyErr_Occurred());
1094  Py_XDECREF(ret);
1095  ret = NULL;
1096  finally:
1097  return ret;
1098 }
1099 
1101  cp_SparseVirtualFileSystem_svf_file_mod_time_matches_docstring,
1102  "file_mod_time_matches(self, id: str) -> bool\n\n"
1103  "Returns True if the file modification time of the Sparse Virtual File identified by the given id the matches"
1104  "the given time as a float.\n"
1105  "This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1106 );
1107 
1108 static PyObject *
1110  PyObject *kwargs) {
1112 
1113  PyObject * ret = NULL;
1114  char *c_id = NULL;
1115  double file_mod_time;
1116  std::string cpp_id;
1117  static const char *kwlist[] = {"id", "file_mod_time", NULL};
1118  AcquireLockSVFS _lock(self);
1119 
1120  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd", (char **) kwlist, &c_id, &file_mod_time)) {
1121  goto except;
1122  }
1123  cpp_id = std::string(c_id);
1124  try {
1125  if (self->p_svfs->has(cpp_id)) {
1126  SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
1127  if (svf.file_mod_time_matches(file_mod_time)) {
1128  Py_INCREF(Py_True);
1129  ret = Py_True;
1130  } else {
1131  Py_INCREF(Py_False);
1132  ret = Py_False;
1133  }
1134  } else {
1135  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
1136  goto except;
1137  }
1138  } catch (const std::exception &err) {
1139  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
1140  goto except;
1141  }
1142  assert(!PyErr_Occurred());
1143  assert(ret);
1144  goto finally;
1145  except:
1146  assert(PyErr_Occurred());
1147  Py_XDECREF(ret);
1148  ret = NULL;
1149  finally:
1150  return ret;
1151 }
1152 
1168  cp_SparseVirtualFileSystem_file_mod_time_docstring,
1169  "file_mod_time(self, id: str) -> float\n\n"
1170  "Returns the file modification time as a float in UNIX time of the Sparse Virtual File identified by the given id.\n"
1171  "This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1172 );
1173 
1174 // SVF: double file_mod_time() const noexcept { return m_file_mod_time; }
1175 static PyObject *
1178 
1179  PyObject * ret = NULL;
1180  char *c_id = NULL;
1181  std::string cpp_id;
1182  static const char *kwlist[] = {"id", NULL};
1183  AcquireLockSVFS _lock(self);
1184 
1185  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist, &c_id)) {
1186  goto except;
1187  }
1188  cpp_id = std::string(c_id);
1189  try {
1190  if (self->p_svfs->has(cpp_id)) {
1191  SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
1192  ret = PyFloat_FromDouble(svf.file_mod_time());
1193  } else {
1194  PyErr_Format(PyExc_IndexError, "%s: No SVF ID %s", __FUNCTION__, c_id);
1195  goto except;
1196  }
1197  } catch (const std::exception &err) {
1198  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
1199  goto except;
1200  }
1201  assert(!PyErr_Occurred());
1202  assert(ret);
1203  goto finally;
1204  except:
1205  assert(PyErr_Occurred());
1206  Py_XDECREF(ret);
1207  ret = NULL;
1208  finally:
1209  return ret;
1210 }
1211 
1213  count_write,
1214  "Returns the count of write operations on the Sparse Virtual File identified by the given id."
1215  " This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1216 );
1217 
1219  count_read,
1220  "Returns the count of read operations on the Sparse Virtual File identified by the given id."
1221  " This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1222 );
1223 
1225  bytes_write,
1226  "Returns the count of the number of bytes writen to the Sparse Virtual File identified by the given id."
1227  " This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1228 );
1229 
1231  bytes_read,
1232  "Returns the count of the number of bytes read from the Sparse Virtual File identified by the given id."
1233  " This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1234 );
1235 
1236 // This macro is for functions that return a datetime type such as time_write, time_read.
1237 #define SVFS_SVFS_METHOD_DATETIME_WRAPPER(method_name) static PyObject * \
1238 cp_SparseVirtualFileSystem_svf_##method_name(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs) { \
1239  ASSERT_FUNCTION_ENTRY_SVFS(p_svfs); \
1240  PyObject *ret = NULL; \
1241  char *c_id = NULL; \
1242  std::string cpp_id; \
1243  static const char *kwlist[] = { "id", NULL }; \
1244  if (! PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **)kwlist, &c_id)) { \
1245  goto except; \
1246  } \
1247  cpp_id = std::string(c_id); \
1248  if (self->p_svfs->has(cpp_id)) { \
1249  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id); \
1250  auto time = svf.method_name(); \
1251  const long seconds = std::chrono::time_point_cast<std::chrono::seconds>(time).time_since_epoch().count(); \
1252  int micro_seconds = std::chrono::time_point_cast<std::chrono::microseconds>(time).time_since_epoch().count() % 1000000; \
1253  const std::tm *p_struct_tm = std::gmtime(&seconds); \
1254  ret = datetime_from_struct_tm(p_struct_tm, micro_seconds); \
1255  } else { \
1256  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id); \
1257  goto except; \
1258  } \
1259  assert(! PyErr_Occurred()); \
1260  assert(ret); \
1261  goto finally; \
1262 except: \
1263  assert(PyErr_Occurred()); \
1264  Py_XDECREF(ret); \
1265  ret = NULL; \
1266 finally: \
1267  return ret; \
1268 }
1269 
1270 // NOTE: time_read and time_write functions are very similar.
1271 
1273  cp_SparseVirtualFileSystem_svf_time_write_docstring,
1274  "time_write(self, id: str) -> typing.Optional[datetime.datetime]\n\n"
1275  "Returns the timestamp of the last write to the Sparse Virtual File identified by the given id as a datetime.datetime."
1276  "or None if no write has taken place.\n"
1277  "This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1278 );
1279 //SVFS_SVFS_METHOD_DATETIME_WRAPPER(time_write)
1280 
1281 static PyObject *
1284  PyObject * ret = NULL;
1285  char *c_id = NULL;
1286  std::string cpp_id;
1287  static const char *kwlist[] = {"id", NULL};
1288  AcquireLockSVFS _lock(self);
1289 
1290  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist, &c_id)) {
1291  goto except;
1292  }
1293  cpp_id = std::string(c_id);
1294  try {
1295  if (self->p_svfs->has(cpp_id)) {
1296  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
1297  if (svf.count_write()) {
1298  auto time = svf.time_write();
1299  const long seconds = std::chrono::time_point_cast<std::chrono::seconds>(
1300  time).time_since_epoch().count();
1301  int micro_seconds =
1302  std::chrono::time_point_cast<std::chrono::microseconds>(time).time_since_epoch().count() %
1303  1000000;
1304  const std::tm *p_struct_tm = std::gmtime(&seconds);
1305  ret = datetime_from_struct_tm(p_struct_tm, micro_seconds);
1306  if (!ret) {
1307  goto except;
1308  }
1309  } else {
1310  Py_INCREF(Py_None);
1311  ret = Py_None;
1312  }
1313  } else {
1314  PyErr_Format(PyExc_IndexError, "%s: No SVF ID \"%s\"", __FUNCTION__, c_id);
1315  goto except;
1316  }
1317  } catch (const std::exception &err) {
1318  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
1319  goto except;
1320  }
1321  assert(!PyErr_Occurred());
1322  assert(ret);
1323  goto finally;
1324  except:
1325  assert(PyErr_Occurred());
1326  Py_XDECREF(ret);
1327  ret = NULL;
1328  finally:
1329  return ret;
1330 }
1331 
1332 
1334  cp_SparseVirtualFileSystem_svf_time_read_docstring,
1335  "time_read(self, id: str) -> typing.Optional[datetime.datetime]\n\n"
1336  "Returns the timestamp of the last read from the Sparse Virtual File identified by the given id as a datetime.datetime."
1337  "or None if no read has taken place.\n"
1338  "This will raise an ``IndexError`` if the Sparse Virtual File of that id does not exist."
1339 );
1340 //SVFS_SVFS_METHOD_DATETIME_WRAPPER(time_read)
1341 
1342 static PyObject *
1345  PyObject * ret = NULL;
1346  char *c_id = NULL;
1347  std::string cpp_id;
1348  static const char *kwlist[] = {"id", NULL};
1349  AcquireLockSVFS _lock(self);
1350 
1351  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist, &c_id)) {
1352  goto except;
1353  }
1354  cpp_id = std::string(c_id);
1355  try {
1356  if (self->p_svfs->has(cpp_id)) {
1357  const SVFS::SparseVirtualFile &svf = self->p_svfs->at(cpp_id);
1358  if (svf.count_read()) {
1359  auto time = svf.time_read();
1360  const long seconds = std::chrono::time_point_cast<std::chrono::seconds>(
1361  time).time_since_epoch().count();
1362  int micro_seconds =
1363  std::chrono::time_point_cast<std::chrono::microseconds>(time).time_since_epoch().count() %
1364  1000000;
1365  const std::tm *p_struct_tm = std::gmtime(&seconds);
1366  ret = datetime_from_struct_tm(p_struct_tm, micro_seconds);
1367  if (!ret) {
1368  goto except;
1369  }
1370  } else {
1371  Py_INCREF(Py_None);
1372  ret = Py_None;
1373  }
1374  } else {
1375  PyErr_Format(PyExc_IndexError, "%s: No Sparse Virtual File ID \"%s\"", __FUNCTION__, c_id);
1376  goto except;
1377  }
1378  } catch (const std::exception &err) {
1379  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
1380  goto except;
1381  }
1382  assert(!PyErr_Occurred());
1383  assert(ret);
1384  goto finally;
1385  except:
1386  assert(PyErr_Occurred());
1387  Py_XDECREF(ret);
1388  ret = NULL;
1389  finally:
1390  return ret;
1391 }
1392 
1394  cp_SparseVirtualFileSystem_config_docstring,
1395  "config(self) -> typing.Dict[str, bool]\n\n"
1396  "Returns the SVFS configuration as a dict."
1397 );
1398 
1399 static PyObject *
1401  PyObject * ret = Py_BuildValue(
1402  "{"
1403  "s:N" /* compare_for_diff */
1404  ",s:N" /* overwrite_on_exit */
1405  "}",
1406  "compare_for_diff", PyBool_FromLong(self->p_svfs->config().compare_for_diff ? 1 : 0),
1407  "overwrite_on_exit", PyBool_FromLong(self->p_svfs->config().overwrite_on_exit ? 1 : 0)
1408  );
1409  return ret;
1410 }
1411 
1412 
1413 // END: SVF functions
1414 #pragma mark END: SVFS functions
1415 
1416 // Mapping method for __len__ returns -1 on error.
1417 static Py_ssize_t
1420  try {
1421  return ((cp_SparseVirtualFileSystem *) self)->p_svfs->size();
1422  } catch (const std::exception &err) {
1423  PyErr_Format(PyExc_RuntimeError, "%s: FATAL caught std::exception %s", __FUNCTION__, err.what());
1424  return -1;
1425  }
1426 }
1427 
1428 static PyMemberDef cp_SparseVirtualFileSystem_members[] = {
1429 // {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0,
1430 // "first name"},
1431  {NULL, 0, 0, 0, NULL} /* Sentinel */
1432 };
1433 
1434 static PyMethodDef cp_SparseVirtualFileSystem_methods[] = {
1435  {
1436  "keys", (PyCFunction) cp_SparseVirtualFileSystem_keys, METH_NOARGS,
1437  cp_SparseVirtualFileSystem_keys_docstring
1438  },
1439  {
1440  "insert", (PyCFunction) cp_SparseVirtualFileSystem_insert, METH_VARARGS |
1441  METH_KEYWORDS,
1442  cp_SparseVirtualFileSystem_insert_docstring
1443  },
1444  {
1445  "remove", (PyCFunction) cp_SparseVirtualFileSystem_remove, METH_VARARGS |
1446  METH_KEYWORDS,
1447  cp_SparseVirtualFileSystem_remove_docstring
1448  },
1449  {
1450  "has", (PyCFunction) cp_SparseVirtualFileSystem_has, METH_VARARGS |
1451  METH_KEYWORDS,
1452  cp_SparseVirtualFileSystem_has_docstring
1453  },
1454  {
1455  "total_size_of", (PyCFunction) cp_SparseVirtualFileSystem_total_size_of, METH_NOARGS,
1456  cp_SparseVirtualFileSystem_total_size_of_docstring
1457  },
1458  {
1459  "total_bytes", (PyCFunction) cp_SparseVirtualFileSystem_total_bytes, METH_NOARGS,
1460  cp_SparseVirtualFileSystem_total_bytes_docstring
1461  },
1462  {
1463  "total_blocks", (PyCFunction) cp_SparseVirtualFileSystem_total_blocks, METH_NOARGS,
1464  cp_SparseVirtualFileSystem_total_blocks_docstring
1465  },
1466  {
1467  "has_data", (PyCFunction) cp_SparseVirtualFileSystem_svf_has_data, METH_VARARGS |
1468  METH_KEYWORDS,
1469  cp_SparseVirtualFileSystem_svf_has_data_docstring
1470  },
1471  {
1472  "write", (PyCFunction) cp_SparseVirtualFileSystem_svf_write, METH_VARARGS |
1473  METH_KEYWORDS,
1474  cp_SparseVirtualFileSystem_svf_write_docstring
1475  },
1476  {
1477  "read", (PyCFunction) cp_SparseVirtualFileSystem_svf_read, METH_VARARGS |
1478  METH_KEYWORDS,
1479  cp_SparseVirtualFileSystem_svf_read_docstring
1480  },
1481  {
1482  "erase", (PyCFunction) cp_SparseVirtualFileSystem_svf_erase, METH_VARARGS |
1483  METH_KEYWORDS,
1484  cp_SparseVirtualFileSystem_svf_erase_docstring
1485  },
1486  {
1487  "need", (PyCFunction) cp_SparseVirtualFileSystem_svf_need, METH_VARARGS |
1488  METH_KEYWORDS,
1489  cp_SparseVirtualFileSystem_svf_need_docstring
1490  },
1491  {
1492  "need_many", (PyCFunction) cp_SparseVirtualFileSystem_svf_need_many, METH_VARARGS |
1493  METH_KEYWORDS,
1494  cp_SparseVirtualFileSystem_svf_need_many_docstring
1495  },
1496  // ---- Meta information about the specific SVF ----
1497  {
1498  "blocks", (PyCFunction) cp_SparseVirtualFileSystem_svf_blocks, METH_VARARGS |
1499  METH_KEYWORDS,
1500  cp_SparseVirtualFileSystem_svf_blocks_docstring
1501  },
1502  {
1503  "size_of", (PyCFunction) cp_SparseVirtualFileSystem_svf_size_of, METH_VARARGS |
1504  METH_KEYWORDS,
1505  cp_SparseVirtualFileSystem_svf_size_of_docstring
1506  },
1507  {
1508  "num_bytes", (PyCFunction) cp_SparseVirtualFileSystem_svf_num_bytes, METH_VARARGS |
1509  METH_KEYWORDS,
1510  cp_SparseVirtualFileSystem_svf_num_bytes_docstring
1511  },
1512  {
1513  "num_blocks", (PyCFunction) cp_SparseVirtualFileSystem_svf_num_blocks, METH_VARARGS |
1514  METH_KEYWORDS,
1515  cp_SparseVirtualFileSystem_svf_num_blocks_docstring
1516  },
1517  {
1518  "file_mod_time_matches", (PyCFunction) cp_SparseVirtualFileSystem_svf_file_mod_time_matches,
1519  METH_VARARGS |
1520  METH_KEYWORDS,
1521  cp_SparseVirtualFileSystem_svf_file_mod_time_matches_docstring
1522  },
1523  // ---- Attribute access ----
1524  {
1525  "file_mod_time", (PyCFunction) cp_SparseVirtualFileSystem_file_mod_time, METH_VARARGS |
1526  METH_KEYWORDS,
1527  cp_SparseVirtualFileSystem_file_mod_time_docstring
1528  },
1529  {
1530  "count_write", (PyCFunction) cp_SparseVirtualFileSystem_svf_count_write, METH_VARARGS |
1531  METH_KEYWORDS,
1532  cp_SparseVirtualFileSystem_svf_count_write_docstring
1533  },
1534  {
1535  "count_read", (PyCFunction) cp_SparseVirtualFileSystem_svf_count_read, METH_VARARGS |
1536  METH_KEYWORDS,
1537  cp_SparseVirtualFileSystem_svf_count_read_docstring
1538  },
1539  {
1540  "bytes_write", (PyCFunction) cp_SparseVirtualFileSystem_svf_bytes_write, METH_VARARGS |
1541  METH_KEYWORDS,
1542  cp_SparseVirtualFileSystem_svf_bytes_write_docstring
1543  },
1544  {
1545  "bytes_read", (PyCFunction) cp_SparseVirtualFileSystem_svf_bytes_read, METH_VARARGS |
1546  METH_KEYWORDS,
1547  cp_SparseVirtualFileSystem_svf_bytes_read_docstring
1548  },
1549  {
1550  "time_write", (PyCFunction) cp_SparseVirtualFileSystem_svf_time_write, METH_VARARGS |
1551  METH_KEYWORDS,
1552  cp_SparseVirtualFileSystem_svf_time_write_docstring
1553  },
1554  {
1555  "time_read", (PyCFunction) cp_SparseVirtualFileSystem_svf_time_read, METH_VARARGS |
1556  METH_KEYWORDS,
1557  cp_SparseVirtualFileSystem_svf_time_read_docstring
1558  },
1559  {
1560  "config", (PyCFunction) cp_SparseVirtualFileSystem_config, METH_NOARGS,
1561  cp_SparseVirtualFileSystem_config_docstring
1562  },
1563  {
1564  "block_touches", (PyCFunction) cp_SparseVirtualFileSystem_svf_block_touches, METH_VARARGS |
1565  METH_KEYWORDS,
1566  cp_SparseVirtualFileSystem_svf_block_touches_docstring
1567  },
1568  {
1569  "lru_punt", (PyCFunction) cp_SparseVirtualFileSystem_svf_lru_punt, METH_VARARGS |
1570  METH_KEYWORDS,
1571  cp_SparseVirtualFileSystem_svf_lru_punt_docstring
1572  },
1573  {
1574  "lru_punt_all", (PyCFunction) cp_SparseVirtualFileSystem_svf_lru_punt_all, METH_VARARGS |
1575  METH_KEYWORDS,
1576  cp_SparseVirtualFileSystem_svf_lru_punt_all_docstring
1577  },
1578  {NULL, NULL, 0, NULL} /* Sentinel */
1579 };
1580 
1581 PyMappingMethods svfs_mapping_methods = {
1582  // Just length as we don't (yet) want to expose the underlying SVF to Python code.
1583  // via either mp_subscript (get), mp_ass_subscript (set).
1585 };
1586 
1587 // clang-format off
1588 // @formatter:off
1590  svfs_cSVFS_doc,
1591  "This class implements a Sparse Virtual File System where Sparse Virtual Files are mapped to a key (a string).\n"
1592  "This can be constructed with an optional boolean overwrite flag that ensures in-memory data is overwritten"
1593  " on destruction of any SVF."
1594 );
1595 // clang-format on
1596 // @formatter.on
1597 
1598 static PyTypeObject svfsc_cSVFS = {
1599  PyVarObject_HEAD_INIT(NULL, 0)
1600  .tp_name = "svfsc.cSVFS",
1601  .tp_basicsize = sizeof(cp_SparseVirtualFileSystem),
1602  .tp_itemsize = 0,
1603  .tp_dealloc = (destructor) cp_SparseVirtualFileSystem_dealloc,
1604  // Mapping methods, just __len__
1605  .tp_as_mapping = &svfs_mapping_methods,
1606  .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1607  .tp_doc = svfs_cSVFS_doc,
1608  .tp_methods = cp_SparseVirtualFileSystem_methods,
1609  .tp_members = cp_SparseVirtualFileSystem_members,
1610  .tp_init = (initproc) cp_SparseVirtualFileSystem_init,
1612 };
1613 
1614 #pragma mark - END SVFS
static PyObject * cp_SparseVirtualFile_need_many_internal(PyObject *py_seek_reads, const SVFS::SparseVirtualFile *pSvf, unsigned long long greedy_len)
Definition: _cSVF.cpp:696
static PyObject * cp_SparseVirtualFile_need_internal(const SVFS::SparseVirtualFile *pSvf, unsigned long long fpos, unsigned long long len, unsigned long long greedy_len)
Definition: _cSVF.cpp:600
static PyObject * cp_SparseVirtualFileSystem_svf_block_touches(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:930
static Py_ssize_t cp_SparseVirtualFileSystem_mapping_length(PyObject *self)
Definition: _cSVFS.cpp:1418
static PyObject * cp_SparseVirtualFileSystem_config(cp_SparseVirtualFileSystem *self)
Definition: _cSVFS.cpp:1400
static PyObject * cp_SparseVirtualFileSystem_total_blocks(cp_SparseVirtualFileSystem *self)
Definition: _cSVFS.cpp:447
static PyObject * cp_SparseVirtualFileSystem_svf_time_write(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:1282
static PyObject * cp_SparseVirtualFileSystem_remove(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:331
PyMappingMethods svfs_mapping_methods
Definition: _cSVFS.cpp:1581
static PyObject * cp_SparseVirtualFileSystem_insert(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:287
static PyObject * cp_SparseVirtualFileSystem_svf_lru_punt_all(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:1062
static PyObject * cp_SparseVirtualFileSystem_svf_blocks(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:838
static PyObject * cp_SparseVirtualFileSystem_svf_need(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:710
static PyObject * cp_SparseVirtualFileSystem_file_mod_time(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:1176
static PyObject * cp_SparseVirtualFileSystem_svf_has_data(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:467
static PyObject * cp_SparseVirtualFileSystem_svf_write(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:523
static void cp_SparseVirtualFileSystem_dealloc(cp_SparseVirtualFileSystem *self)
Definition: _cSVFS.cpp:211
static PyObject * cp_SparseVirtualFileSystem_keys(cp_SparseVirtualFileSystem *self)
Definition: _cSVFS.cpp:235
static int cp_SparseVirtualFileSystem_init(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:173
static PyTypeObject svfsc_cSVFS
Definition: _cSVFS.cpp:1598
static PyObject * cp_SparseVirtualFileSystem_svf_time_read(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:1343
static PyObject * cp_SparseVirtualFileSystem_has(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:373
static PyObject * cp_SparseVirtualFileSystem_svf_erase(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:646
#define SVFS_SVFS_METHOD_SIZE_T_WRAPPER(method_name, docstring)
Definition: _cSVFS.cpp:50
static PyMethodDef cp_SparseVirtualFileSystem_methods[]
Definition: _cSVFS.cpp:1434
static PyObject * cp_SparseVirtualFileSystem_svf_read(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:585
static PyObject * cp_SparseVirtualFileSystem_total_bytes(cp_SparseVirtualFileSystem *self)
Definition: _cSVFS.cpp:430
static PyObject * cp_SparseVirtualFileSystem_svf_file_mod_time_matches(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:1109
static PyObject * cp_SparseVirtualFileSystem_svf_lru_punt(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:1003
#define ASSERT_FUNCTION_ENTRY_SVFS(member)
Definition: _cSVFS.cpp:145
PyDoc_STRVAR(cp_SparseVirtualFileSystem_keys_docstring, "keys(self) -> typing.List[str]\n\n" "Returns the IDs of all the Sparse Virtual Files in the Sparse Virtual File System.")
static PyObject * cp_SparseVirtualFileSystem_svf_need_many(cp_SparseVirtualFileSystem *self, PyObject *args, PyObject *kwargs)
Definition: _cSVFS.cpp:764
static PyObject * cp_SparseVirtualFileSystem_new(PyTypeObject *type, PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(kwds))
Definition: _cSVFS.cpp:156
static PyMemberDef cp_SparseVirtualFileSystem_members[]
Definition: _cSVFS.cpp:1428
static PyObject * cp_SparseVirtualFileSystem_total_size_of(cp_SparseVirtualFileSystem *self)
Definition: _cSVFS.cpp:413
A RAII wrapper around the PyThread_type_lock for the CPython SVFS.
Definition: _cSVFS.cpp:111
AcquireLockSVFS(cp_SparseVirtualFileSystem *pSVFS)
Definition: _cSVFS.cpp:113
cp_SparseVirtualFileSystem * _pSVFS
Definition: _cSVFS.cpp:130
Might be thrown during a write operation where the data differs.
Definition: svf.h:224
Might be thrown during a erase operation where the file position is not at the exact beginning of a b...
Definition: svf.h:237
Exception specialisation for the SparseVirtualFile.
Definition: svf.h:207
const std::string & message() const
Definition: svf.h:211
Might be thrown during a write operation where the data differs.
Definition: svf.h:231
const std::string & message() const
Definition: svfs.h:58
Exception specialisation on insert error.
Definition: svfs.h:73
Exception specialisation on remove error.
Definition: svfs.h:80
Implementation of a Sparse Virtual File.
Definition: svf.h:288
size_t lru_punt(size_t cache_size_upper_bound)
Definition: svf.cpp:1023
t_block_touches block_touches() const noexcept
Returns a std::map of latest touch value key and file position value.
Definition: svf.cpp:1007
double file_mod_time() const noexcept
The file modification time as a double representing UNIX seconds.
Definition: svf.h:370
std::chrono::time_point< std::chrono::system_clock > time_write() const noexcept
Definition: svf.h:399
void write(t_fpos fpos, const char *data, size_t len)
Write the data a the given file position.
Definition: svf.cpp:452
std::chrono::time_point< std::chrono::system_clock > time_read() const noexcept
Definition: svf.h:406
size_t erase(t_fpos fpos)
Remove a particular block.
Definition: svf.cpp:907
size_t count_read() const noexcept
Count of read() operations.
Definition: svf.h:379
bool has(t_fpos fpos, size_t len) const noexcept
Do I have the data at the given file position and length?
Definition: svf.cpp:56
bool file_mod_time_matches(const double &file_mod_time) const noexcept
Definition: svf.h:361
size_t count_write() const noexcept
Count of write() operations.
Definition: svf.h:376
void read(t_fpos fpos, size_t len, char *p)
Read data and write to the buffer provided by the caller. This is non-const as it updates the non-con...
Definition: svf.cpp:503
t_seek_reads blocks() const noexcept
The existing blocks as a list of (file_position, size) pairs.
Definition: svf.cpp:776
A SparseVirtualFileSystem is a key/value store where the key is a file ID as a string and the value i...
Definition: svfs.h:94
std::vector< t_seek_read > t_seek_reads
Definition: svf.h:251
std::map< t_block_touch, t_fpos > t_block_touches
Definition: svf.h:255
Configuration for the Sparse Virtual File.
Definition: svf.h:262
Python wrapper around a C++ SparseVirtualFile.
Definition: _cSVFS.cpp:97
PyThread_type_lock lock
Definition: _cSVFS.cpp:101
PyObject_HEAD SVFS::SparseVirtualFileSystem * p_svfs
Definition: _cSVFS.cpp:99
PyObject * datetime_from_struct_tm(const std::tm *bdt, int usecond)
Definition: svfs_util.cpp:63