- 17 Jan, 2017 2 commits
-
-
Kirill Smelkov authored
to avoid bugging on `pybuf->ob_refcnt != 1`when an exception was internally raised & caught somewhere in loadblk() implementation. Details are in 9aa6a5d7, 61b18a40. The last patch also resorts to buffer unpinning when nothing helps (please see details about unpinning there). Fixes: nexedi/wendelin.core#7 /cc @Tyagov @klaus @jm /reviewed-on nexedi/wendelin.core!3
-
Kirill Smelkov authored
to avoid deadlocks. Description is in the last patch. Fixes: nexedi/wendelin.core#6 /cc @Tyagov, @klaus, @jm /reviewed-on nexedi/wendelin.core!2
-
- 16 Jan, 2017 4 commits
-
-
Kirill Smelkov authored
There are situations possible when both exc_traceback and frame objects are garbage-collected, but frame's f_locals remains not collected because e.g. it was explicitly added to somewhere. We cannot detect such cases (dicts are not listed in referrers). So if nothing helped, as a last resort, unpin pybuf from its original memory and make it point to zero-sized NULL. In general this is not strictly correct to do as other buffers & memoryview objects created from pybuf, copy its pointer on initialization and thus pybuf unpinning won't adjust them. However we require BigFile implementations to make sure not to use such-created objects, if any, after return from loadblk(). Finally fixes nexedi/wendelin.core#7
-
Kirill Smelkov authored
This code was added in 6da5172e (bigfile/py: Teach storeblk() how to correctly propagate traceback on error) to unpin a storeblk pybuf to not care whether its refcount == 1 - this way to be able to propagate python error upper not caring whether pybuf is still referenced or not. 9aa6a5d7 (bigfile/py: Teach loadblk() to automatically break reference cycles to pybuf) adds a note that such unpinning is not strictly correct: becuase of other buffer objects were created from pybuf - they are copying pointers on initialization and unpinning pybuf won't adjust them. However for loadblk codepath it turned out (see next patch) it is not completely possible to unreference pybuf in all cases. For this reason loadblk will be falling back to unpinning too. As a preparatory step move common code to shared functions.
-
Kirill Smelkov authored
It turns out some code wants to store tracebacks e.g. for further logging/whatever. This way GC won't help to free up references to pybuf. However if pybuf remain referenced only from calling frames, we can change there reference to pybuf to a stub object "<pybuf>" and this way remove the reference. With added test but without loadblk changes the failure would be as: pybigfile_loadblk WARN: pybuf->ob_refcnt != 1 even after GC: pybuf (ob_refcnt=2): <read-write buffer ptr 0x7fae4911f000, size 2097152 at 0x7fae4998cef0> pybuf referrers: [<frame object at 0x556daff41aa0>] <-- NOTE bigfile/_bigfile.c:613 pybigfile_loadblk BUG!
-
Kirill Smelkov authored
As comments being removed states "on python3 exception state is cleared upon exiting from `except`" - so let's move exc_* fetching under except clause - this way we'll get correct exception objects on both py2 and py3.
-
- 12 Jan, 2017 2 commits
-
-
Kirill Smelkov authored
We'll need it in next patch to get and analyze this list.
-
Kirill Smelkov authored
Instead of only printing "BUG" let's print information about objects which still refer to pybuf - to help debugging. For example with the following artificial pybuf leak ``` diff --git a/bigfile/tests/test_basic.py b/bigfile/tests/test_basic.py index c737621..f5e057a 100644 --- a/bigfile/tests/test_basic.py +++ b/bigfile/tests/test_basic.py @@ -126,6 +126,7 @@ def test_basic(): # test that python exception state is preserved across pagefaulting def test_pagefault_savestate(): + zzz = [] class BadFile(BigFile): def loadblk(self, blk, buf): # simulate some errors in-between to overwrite thread exception @@ -154,6 +155,7 @@ def loadblk(self, blk, buf): # which result in holding additional ref to buf, but loadblk caller # will detect and handle this situation via garbage-collecting # above cycle. + zzz.append(buf) self.loadblk_run = 1 ``` it dies this way: bigfile/_bigfile.c:567 pybigfile_loadblk WARN: pybuf->ob_refcnt != 1 even after GC: pybuf (ob_refcnt=2): <read-write buffer ptr 0x7f08d3e88000, size 2097152 at 0x7f08d48b7070> pybuf referrers: [[<read-write buffer ptr 0x7f08d3e88000, size 2097152 at 0x7f08d48b7070>]] bigfile/_bigfile.c:573 pybigfile_loadblk BUG!
-
- 11 Jan, 2017 2 commits
-
-
Kirill Smelkov authored
Because otherwise we bug on pybuf->ob_refcnt != 1. Such cycles might happen if inside loadblk implementation an exception is internally raised and then caught even in deeply internal function which does not receive pybuf as argument or by some other way: After _, _, exc_traceback = sys.exc_info() there is a reference loop created: exc_traceback | ^ | | v .f_localsplus frame and since exc_traceback object holds reference to deepest frame, which via f_back will be holding reference to frames up to frame with pybuf argument, it will result in additional reference to pybuf being held until the above cycle is garbage collected. So to solve the problem while leaving loadblk, if pybuf->ob_refcnt != let's first do garbage-collection, and only then recheck left references. After GC reference-loops created by exceptions should go away. NOTE PyGC_Collect() (C way to call gc.collect()) always performs GC - it is not affected by gc.disable() which disables only _automatic_ garbage collection. NOTE it turned out out storeblk logic to unpin pybuf (see 6da5172e "bigfile/py: Teach storeblk() how to correctly propagate traceback on error") is flawed, because when e.g. creating memoryview from pybuf internal pointer is copied and then clearing original buf does not result in clearing the copy. NOTE it is ok to do gc.collect() from under sighandler - at least we are already doing it for a long time via running non-trivial python code which for sure triggers automatic GC from time to time (see also 786d418d "bigfile: Simple test that we can handle GC from-under sighandler" for the reference) Fixes: nexedi/wendelin.core#7
-
Kirill Smelkov authored
In the next patch we will need to use this from several places.
-
- 10 Jan, 2017 3 commits
-
-
Kirill Smelkov authored
Like with loadblk (see f49c11a3 "bigfile/virtmem: Do loadblk() with virtmem lock released" for the reference) storeblk() calls are potentially slow and external code that serves the call can take other locks in addition to virtmem lock taken by virtmem subsystem. If that "other locks" are also taken before external code calls e.g. with fileh_invalidate_page() in different codepath - a deadlock can happen: T1 T2 commit invalidation-from-server received V -> storeblk Z <- ClientStorage.invalidateTransaction() Z -> zeo.store V <- fileh_invalidate_page (of unrelated page) The solution to avoid deadlock, like for loadblk case, is to call storeblk() with virtmem lock released. However unlike loadblk which can be invoked at any time, storeblk is invoked at commit time only so for storeblk case we handle rules for making sure virtmem stays consistent after virtmem lock is retaken differently: 1. We disallow several parallel writeouts for one fileh. This way dirty pages handling logic can not mess up. This restriction is also consistent with ZODB 2 phase commit protocol where for a transaction commit logic is invoked/handled from only 1 thread. 2. For the same reason we disallow discard while writeout is in progress. This is also consistent with ZODB 2 phase commit protocol where txn.tpc_abort() is not expected to be called at the same time with txn.commit(). 3. While writeout is in progress, for that fileh we disallow pages modifications and pages invalidations - because both operations would change at least fileh dirty pages list which is iterated over by writeout code with releasing/retaking the virtmem lock. By disallowing them we make sure fileh dirty pages list stays constant during whole fileh writeout. This restrictions are also consistent with ZODB commit semantics: - while an object is being stored into ZODB it is not expected it will be further modified or explicitly invalidated by client via ._p_invalidate() - server initiated invalidations come into effect only at transaction boundaries - when new transaction is started, not during commit time. Also since now storeblk is called with virtmem lock released, for buffer to store we no longer can use present page mapping in some vma directly, because while virtmem lock is released that mappings can go away. Fixes: nexedi/wendelin.core#6
-
Kirill Smelkov authored
bigfile/tests/thread: Don't invalidate exactly same page to test general virtmem deadlock on loadblk The main deadlock described in f49c11a3 (bigfile/virtmem: Do loadblk() with virtmem lock released) (V,Z in T1; Z,V in T2) can happen if in T2 V is taken for whatever reason - e.g. for invalidating completely unrelated page to what is being loaded in T1. For invalidation of the same page we have explicit separate test_thread_load_vs_invalidate() which verifies how loadblk handles this situation. This patch prepares general test_thread_lock_vs_virtmem_lock() to also test V vs Z deadlock for storeblk() case - when it will be called with virtmem lock released: for storeblk it will be forbidden by virtmem rules to invalidate pages of fileh for which writeout is in progress. Updates: nexedi/wendelin.core#6
-
Kirill Smelkov authored
This allows writeout code not to scan whole pagemap to find dirty pages to write out, which should be faster. But more importantly iterating whole pagemap on writeout would become unsafe, when in upcoming patch storeblk() will be called with virt_lock released: because there pagemap could be modified e.g. due to processing other read accesses. So maintain fileh->dirty_pages list and use it when we need to go through dirtied pages. Updates: nexedi/wendelin.core#6
-
- 09 Jan, 2017 1 commit
-
-
Kirill Smelkov authored
Currently fileh_dirty_writeout() writes page via storeblk() in order - - those with lower ->f_pgoffset are stored first. This happens because current fileh_dirty_writeout() iterates whole pagemap to find dirty pages and pagemap iteration is ordered by f_pgoffset. In upcoming patch we'll rework writeout code not to iterate through whole pagemap, but only through dirty pages. However the property that pages are emitted in canonical order is useful, so let's make sure via tests this will stay preserved: In mkdirty2() we modify pages in 2, 0 order, but the latter code checks (via storeblk_trace()) they were actually stored in 0, 2 order.
-
- 28 Sep, 2016 2 commits
-
-
Kirill Smelkov authored
-
Kirill Smelkov authored
Just update to latest CCAN for it to be a fresh one.
-
- 14 Aug, 2016 1 commit
-
-
Kirill Smelkov authored
13c0c17c (bigfile/zodb: Format #1 which is optimized for small changes) used BTree to organize ZBlk1 block's chunks and for loadblkdata() added "TODO we are missing to free internal BTree structures on data load". nexedi/wendelin.core#3 besides other things showed that even when we deactivate ZData objects, we are still keeping them as ghosts occupying memory and the same for IOBucket objects. This all happens because there is no proper way to deactivate whole btree - including internal buckets objects. And since internal buckets are not deactivated, they stay in picklecache and thus hold a reference to ZData objects and ZData objects in turn, even if explicitly deactivated, stay in memory. We can fix this all via implementing whole-btree deactivation procedure. To do so we need to iterate over all btree buckets recursively, but unfortunately there is no BTree API to access/iterate btree's buckets. We can however still get reference to first top-level buckets via gc.get_referents(btree) and then scan buckets further without hacks. gc.get_referents(btree) is a hack, but - it works in O(1) (we only get pointers from btree, not scanning all gcable objects and deducing them) - it works reliable if we filter out non-interesting objects. So in the end it works. Before the patch loading more and more ZBlk1 data with objgraph instrumentation was showing itself like # Nobj δ wendelin.bigfile.file_zodb.ZData 7168 +512 BTrees.IOBTree.IOBucket 238 +17 BTrees.IOBTree.IOBTree 14 +1 and after this patch we now have BTrees.IOBTree.IOBTree 14 +1 we cannot remove that "IOBTree + 1", since ZBlk1 is holding direct reference on it (via .chunktab) and we have to keep ZBlk1 live with ._v_zfile and ._v_zblk set for invalidation to work. "+1 IOBtree" is however small - 144 bytes per 2M (= 0.006%) so we can neglect that the same way we neglect keeping ZBlk1 staying live for each block.
-
- 14 Jul, 2016 4 commits
-
-
Kirill Smelkov authored
-
Kirill Smelkov authored
The following started to appear after recent gcc upgrade on my host: bigfile/virtmem.c: In function `vma_on_pagefault': bigfile/virtmem.c:696:9: warning: implicit declaration of function `usleep' [-Wimplicit-function-declaration] usleep(10000); // XXX with 1000 uslepp still busywaits
-
Kirill Smelkov authored
This updates and fixes 487e5226 (setup: specify setuptools location explicitly when calling make.) to use @kazuhiko original idea to propagate only setuptools location. The reason is - when propagating whole sys.path things break under tox tests: ---- 8< ---- ========================================================================== test session starts =========================================================================== platform linux2 -- Python 2.7.12, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 rootdir: /home/kirr/src/wendelin/release/wendelin.core, inifile: collected 33 items bigarray/tests/test_arrayzodb.py ....... bigarray/tests/test_basic.py ........ bigfile/tests/test_basic.py .... bigfile/tests/test_filefile.py . bigfile/tests/test_filezodb.py ........ bigfile/tests/test_thread.py .... lib/tests/test_calc.py . ======================================================================= 33 passed in 14.14 seconds ======================================================================= x86_64-linux-gnu-gcc -pthread -g -Wall -D_GNU_SOURCE -std=gnu99 -fplan9-extensions -Wno-declaration-after-statement -Wno-error=declaration-after-statement -Iinclude -I3rdparty/ccan -I3rdparty/include bigfile/tests/tfault.c lib/bug.c lib/utils.c 3rdparty/ccan/ccan/tap/tap.c -o bigfile/tests/tfault.t t/tfault-run bigfile/tests/tfault.t faultr on_pagefault ok 1 - !pagefault_init() Fatal Python error: Py_Initialize: Unable to get the locale encoding File ".../wendelin.core/.tox/py27-ZODB3-zblk0-fs-numpy110/lib/python2.7/encodings/__init__.py", line 123 raise CodecRegistryError,\ ^ SyntaxError: invalid syntax Current thread 0x00007f9b80024780 (most recent call first): t/tfault-run: line 28: 21521 Аварийный останов (core dumped) gdb -q -batch $tfault core > core.info E: can't gdb(core) Makefile:189: ошибка выполнения рецепта для цели «faultr.tfault» make: *** [faultr.tfault] Ошибка 1 rm bigfile/tests/test_virtmem.t bigfile/tests/test_ram.t bigfile/tests/tfault.t bigfile/tests/test_pagemap.t error: Failed to execute `make test` ERROR: InvocationError: '.../wendelin.core/.tox/py27-ZODB3-zblk0-fs-numpy110/bin/python setup.py test' ________________________________________________________________________________ summary _________________________________________________________________________________ ERROR: py27-ZODB3-zblk0-fs-numpy110: commands failed ---- 8< ---- What happens here is: - gdb is used in automated tests - gdb is linked with libpython3.5 - tox is currently running tests with python27 - setup.py sets PYTHONPATH to whole path from python27 - gdb, upon starting, initializes python runtime, which tries to load py27 modules under py35 -> oops. So propagating only setuptools location practically solves the issue for now, but still there is potential risk that in future, there will be other modules put in the same location as setuptools (location is parent dir of a module/package) which python tries to load on startup and which might be incompatible between 2 & 3. Thus not setting PYTHONPATH at all - e.g. creating environments virtualenv way - would be better, but buildout fundamentally works the other way. We can not also use -c 'buildout sys.path hack' in $PYTHON itself, as $PYTHON is used in general way inside Makefile. So let the hack with setuptools location in PYTHONPATH stay there until it practically works.
-
Kazuhiko authored
If wendelin.core is built under buildout and setuptools exists only in buildout environment, 'python setup.py' called inside make will fail without this change. Building 'wendelin.core' Running easy_install: "/path/to/python2.7" "-c" "import sys; sys.path[0:0] = ['/path/to/setuptools-19.6.2-py2.7.egg']; from setuptools.command.easy_install import main; main()"... path_list=['/path/to/setuptools-19.6.2-py2.7.egg'] ... <<< setup.py: os.system('make %s PYTHON="%s"' % (target, sys.executable)) ... make[1]: Leaving directory '/tmp/xxx/wendelin.core-0.6/3rdparty/ccan' /path/to/python2.7 setup.py ll_build_ext --inplace Traceback (most recent call last): File "setup.py", line 18, in <module> from setuptools import setup, Extension, Command, find_packages ImportError: No module named setuptools Makefile:40: recipe for target 'bigfile/_bigfile.so' failed make: *** [bigfile/_bigfile.so] Error 1 error: Setup script exited with error: Failed to execute `make all` [ @kirr: as a solution we are propagating whole python path via make. This should cover both setuptools case, and any other future potential "preloaded-by-buildout" egg. ] /reviewed-on nexedi/wendelin.core!1
-
- 06 Jul, 2016 1 commit
-
-
Kirill Smelkov authored
@kazuhiko reports that wendelin.core build is currently broken on Python 3.5. Indeed it was: In file included from bigfile/_bigfile.c:37:0: ./include/wendelin/compat_py2.h: In function ‘_PyThreadState_UncheckedGetx’: ./include/wendelin/compat_py2.h:66:28: warning: implicit declaration of function ‘_Py_atomic_load_relaxed’ [-Wimplicit-function-declaration] return (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); ^ ./include/wendelin/compat_py2.h:66:53: error: ‘_PyThreadState_Current’ undeclared (first use in this function) return (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); ^ ./include/wendelin/compat_py2.h:66:53: note: each undeclared identifier is reported only once for each function it appears in ./include/wendelin/compat_py2.h:67:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ The story here is that in 3.5 they decided to remove direct access to _PyThreadState_Current and atomic implementations - because that might semantically conflict with other headers implementing atomics - and provide only access by function. Starting from Python 3.5.2rc1 the function to get current thread state without asserting it is !NULL - _PyThreadState_UncheckedGet() - was added: https://github.com/python/cpython/commit/df858591 so for those python versions we can directly use it. After the fix wendelin.core tox tests pass under all python2.7, python3.4 and python3.5. More context here: https://bugs.python.org/issue26154 https://bugs.python.org/issue25150 Fixes: nexedi/wendelin.core#1
-
- 01 Jul, 2016 2 commits
-
-
Kirill Smelkov authored
_PyThreadState_Current_GET() is a function to get current python thread state without asserting it is !NULL. It was added as part of d53271b9 (bigfile/virtmem: Big Virtmem lock) We are going to adapt it to Python 3.5 (see next patch), so before doing so move it to our compatibility place. In the new place the name is _PyThreadState_UncheckedGet -- like such function is named in Python 3.5 (again, see next patch). Updates: nexedi/wendelin.core#1
-
Kirill Smelkov authored
Now that ZODB 5.0 eggs are starting to appear (see e.g. [1] for context) let's limit ZODB4 test setup to actually install ZODB4, not 5. [1] https://groups.google.com/forum/#!topic/zodb/P05S0pyUbAM
-
- 27 Jun, 2016 2 commits
-
-
Kirill Smelkov authored
Upon @jp request.
-
Kirill Smelkov authored
The link is absolute URL, since the readme can be shown in a lot of places (on lab.nexedi.com, on pypi, on github, etc...) We might also change the link to demo_zbigarray.py to be absolute URL because of pypi case in the future.
-
- 24 Jun, 2016 1 commit
-
-
Kirill Smelkov authored
Since the beginning of pagemap (45af76e6 "bigfile/pagemap: specialized {} uint64 -> void * mapping") we had a bug sitting in __pagemap_for_each_leaftab() (non-leaf iterating logic behind pagemap_for_each): After entry to stack-down was found, we did not updated tailv[l] accordingly. Thus if there are non-adjacent entries an entry could be e.g. emitted many times: l 3 __down 0x7f79da1ee000 tailv[4]: 0x7f79da1ee000 -> tailv[4] 0x7f79da1ee000 __down 0x7f79da1ed000 l 4 __down 0x7f79da1ed000 tailv[5]: 0x7f79da1ed000 h 5 l 5 leaftab: 0x7f79da1ed000 <-- lvl 5 idx 169 page 0x55aa ok 9 - pagemap_for_each(0) == 21930 l 5 __down (nil) tailv[4]: 0x7f79da1ee008 -> tailv[4] 0x7f79da1ee008 __down 0x7f79da1ed000 l 4 __down 0x7f79da1ed000 tailv[5]: 0x7f79da1ed000 h 5 l 5 leaftab: 0x7f79da1ed000 <-- lvl 5 idx 169 page 0x55aa not ok 10 - pagemap_for_each(1) == 140724106500272 And many-time-emitted entries are not only incorrect, but can also lead to not-handled segmentation faults in e.g. fileh_close(): https://lab.nexedi.com/nexedi/wendelin.core/blob/v0.6-1-gb0b2c52/bigfile/virtmem.c#L179 /* drop all pages (dirty or not) associated with this fileh */ pagemap_for_each(page, &fileh->pagemap) { /* it's an error to close fileh to mapping of which an access is * currently being done in another thread */ BUG_ON(page->state == PAGE_LOADING); page_drop_memory(page); list_del(&page->lru); <-- HERE bzero(page, sizeof(*page)); /* just in case */ free(page); } ( because after first bzero of a page, the page is all 0 bytes including page->lru{.next,.prev} so on the second time when the same page is emitted by pagemap_for_each, list_del(&page->lru) will try to set page->lru.next = ... which will segfault. ) So fix it by properly updating tailv[l] while we scan/iterate current level. NOTE This applies only to non-leaf pagemap levels, as leaf level is scanned with separate loop in pagemap_for_each. That's why we probably did not noticed this earlier - up until now our usual workloads was to change data in adjacent batches and that means adjacent pages. Though today @Tyagov was playing with wendelin.core in some other way and it uncovered the bug.
-
- 13 Jun, 2016 5 commits
-
-
Kirill Smelkov authored
In the time when README.rst was initially introduced (58279ac7 "readme: Initial draft") GitLab was not handling relative links well and it was necessary to construct them properly by hand. Nowdays GitLab automatically adds namespace and project and blob/ref/ prefix to relative URL link, so there is no need to specify them manually. Actually specifying the prefix manually makes URL invalid, as it becomes something like https://lab.nexedi.com/nexedi/wendelin.core/blob/master/wendelin.core/blob/master/demo/demo_zbigarray.py Fix it.
-
Kirill Smelkov authored
-
Kirill Smelkov authored
This continues c7750965 (changelog: Convert it to pretty rst) - without .rst extension gitlab shows this file as plain text.
-
Kirill Smelkov authored
>= 1.6 was already using latest in 1.6 series, but >= 1.6.2 is more explicit. Also: in 1.6.2 NEO switched from MySQL-python to mysqlclient: nexedi/neoppod@5f0c93f5 so we switch it too.
-
Kirill Smelkov authored
Namely 1.8.x, 1.9.x -> 1.10.x -> 1.11.x
-
- 12 Jun, 2016 1 commit
-
-
Kirill Smelkov authored
Just update to latest CCAN for it to be a fresh one. Throught the modules we use there are no real updates, just a fix for one warning in array_size.
-
- 20 Apr, 2016 1 commit
-
-
Kirill Smelkov authored
For ZBlk1 we already compare ZData content about whether it was changed compared to data already stored to DB, and do not store it twice if data is the same. However ZBlk itself is always marked as changed, if corresponding memory page was dirtied. This results in transactions like Trans #33915309 tid=03b6944919befeee time=2016-04-17 22:01:06.034237 offset=140320105842 status=' ' user='...' description='...' # ... other parts, but no ZData here data #00002 oid=000000000026fc4c size=79 class=wendelin.bigfile.file_zodb.ZBlk1 where ZBlk1 is committed the same without necessity. NOTE we cannot avoid committing ZBlk in all cases, because it is used to signal other DB clients that a ZBlk needs to be invalidated and this way associated fileh pages are invalidated too. This cannot work via ZData, because ZData don't have back-pointer to ZBlk1 or to corresponding zfile.
-
- 05 Apr, 2016 1 commit
-
-
Kirill Smelkov authored
Starting from setuptools 19.4, more concrete from the following commit: https://github.com/pypa/setuptools/commit/ebc54982 setuptools sorts namespaced packages .__path__ to be in sync with sys.path . That however breaks for wendelin.core used from in-tree or installed in development mode, because we are doing tricks in top-level import redirector (see e870781d "Top-level in-tree import redirector"): (z+numpy.v2)kirr@teco:~/tmp/trashme/wendelin.core$ python -c 'import wendelin' Traceback (most recent call last): File "<string>", line 1, in <module> File "wendelin.py", line 39, in <module> __import__('pkg_resources').declare_namespace(__name__) File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2081, in declare_namespace _handle_ns(packageName, path_item) File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2026, in _handle_ns _rebuild_mod_path(path, packageName, module) File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2050, in _rebuild_mod_path orig_path.sort(key=position_in_sys_path) File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2045, in position_in_sys_path return sys_path.index(_normalize_cached(os.sep.join(parts))) ValueError: '/home/kirr/tmp/trashme' is not in list Here wendelin.py added /home/kirr/tmp/trashme/wendelin.core to .__path__ and setuptools' _handle_ns() wants to order that dir's parent in correspondence with sys.path, but parent path is not there - oops. We can workaround the problem, by first not initializing .__path__ and letting __import__('pkg_resources').declare_namespace(__name__) fully handle and initialize it, and only after it is done we make the correction for wendelin modules located not under .../wendelin.core/wendelin/ but under .../wendelin.core/ . Importing was tested to work with the fix with both setuptools 20.6.7 and older setuptools 17.1.1, i.e. here we should not be breaking backward compatibility. /reported-by @tatuya, @Camata, @Tyagov /reviewed-on kirr/wendelin.core!1
-
- 18 Dec, 2015 1 commit
-
-
Kirill Smelkov authored
Commit ab9ca2df (bigarray: Add support for FORTRAN ordering) added ability to define array order, but there I made a mistake of not caring about how previously-saved to DB arrays would be read back. The thing is BigArray gained new data member ._order which is automatically saved to DB thanks to ZBigArray inheriting from Persistent; on load-from-db path we just read object state from DB, which for ZBigArray is dict, and restore object attributes from it. But for previously-saved data, obviously, there is no 'order' entry and thus this way restored objects are restored not in full to current code expectations and it can boom e.g. this way: zarray.resize((new_one,old_shape[1])) Module wendelin.bigarray, line 190, in resize self._init0(new_shape, self.dtype, order=self._order) AttributeError: 'ZBigArray' object has no attribute '_order' Solution to fix is: on restore-from-DB path, see if a data member is not present on restored object, and if it has default value in BigArray set it to that. ( code to get function defaults is from http://stackoverflow.com/questions/12627118/get-a-function-arguments-default-value ) /cc @Tyagov, @klaus
-
- 15 Dec, 2015 4 commits
-
-
Kirill Smelkov authored
-
Kirill Smelkov authored
loadblk() calls are potentially slow and external code that serve the cal can take other locks in addition to virtmem lock taken by virtmem subsystem. If that "other locks" are also taken before external code calls e.g. fileh_invalidate_page() in different codepath a deadlock can happen, e.g. T1 T2 page-access invalidation-from-server received V -> loadblk Z <- ClientStorage.invalidateTransaction() Z -> zeo.load V <- fileh_invalidate_page The solution to avoid deadlock is to call loadblk() with virtmem lock released and upon loadblk() completion recheck virtmem data structures carefully. To make that happen: - new page state is introduces: PAGE_LOADING (file content loading is in progress) - virtmem releases virt_lock before calling loadblk() when serving pagefault - because loading is now done with virtmem lock released, now: 1. After loading completes we need to recheck fileh/vma data structures The recheck is done in full - vma_on_pagefault() just asks its driver (see VM_RETRY and VM_HANDLED codes) to retry handling the fault completely. This should work as the freshly loaded page was just inserted into fileh->pagemap and should be found there in the cache on next lookup. On the other hand this also works correctly, if there was concurrent change - e.g. vma was unmapped while we were loading the data - in that case the fault will be also processed correctly - but loaded data will stay in fileh->pagemap (and if not used will be evicted as not-needed eventually by RAM reclaim). 2. Similar to retrying mechanism is used for cases when two threads concurrently access the same page and would both try to load corresponding block - only one thread issues the actual loadblk() and another waits for load to complete with polling and VM_RETRY. 3. To correctly invalidate loading-in-progress pages another new page state is introduced: PAGE_LOADING_INVALIDATED (file content loading was in progress while request to invalidate the page came in) which fileh_invalidate_page() uses to propagate invalidation message to loadblk() caller. 4. Blocks loading can now happen in parallel with other block loading and other virtmem operations - e.g. invalidation. For such cases tests are added to test_thread.py 5. virtmem lock now becomes just regular lock, instead of being previously recursive. For virtmem lock to be recursive was needed for cases, when code under loadblk() could trigger other virtmem calls, e.g. due to GC and calling another VMA dtor that would want to lock virtmem, but virtmem lock was already held. This is no longer needed. 6. To catch double faults we now cannot use just on static variable in_on_pagefault. That variable thus becomes thread-local. 7. Old test in test_thread to "test that access vs access don't overlap" no longer holds true - and is thus removed. /cc @Tyagov, @klaus
-
Kirill Smelkov authored
Previously we were doing virt_lock() / virt_unlock() which automatically were making sure to unlock GIL before locking virtmem, and to restore GIL state to previous after virtmem lock happened. virt_unlock() was unlocking just the virtmem lock without touching GIL at all - that works because the running code would eventually release GIL as python regularly does so to allowing multiple threads to run. In the next patch however, we'll need to wait for in-progress-loading page to complete, and that wait has to be done with GIL released (so other python threads could run), and for doing so we'll need functionality to make sure GIL is unlocked and retake it back, not tied to virt_lock(). So factor it out.
-
Kirill Smelkov authored
NotifyChannel was introduced in c7c01ce4 (bigfile/zodb: ZODB.Connection can migrate between threads on close/open and we have to care) to test thread interaction specific to ZODB. We'll however need NotifyChannel to do more threading test of virtmem core, and this way the proper place for NotifyChannel is test_thread.py itself. Move it.
-