-
Notifications
You must be signed in to change notification settings - Fork 434
REF Job stores; move large parts of memory.py into jobstore.py #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 0.5.X
Are you sure you want to change the base?
Conversation
Yes, I prefer this design too. I can't do a real review right now, but a few remarks just by glancing at the code: I'd like 'jobstore.py' to be named 'job_store.py'. I am an underscore freak: I want underscores to separate words, if they are not CamelCase. I'd like a few unit tests of the job_store functionality in a tests/test_job_store.py directory. It would help teasing out failures in job_store from the bigger coder base. Aslo, it would probably help increasing the test coverage of job_store which is at 88% currently. I get some test failures. Mostly in the documentation, but they worry me, as they mean that some of the functionality is no longer working the way it should. If you run 'nosetests' in the base directory, nose will run automatically using the settings from the ====================================================================== ERROR: Failure: IndexError (list index out of range) ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/lib/pymodules/python2.6/nose/loader.py", line 224, in generate for test in g(): File "/home/varoquau/dev/joblib/joblib/test/test_memory.py", line 246, in test_memory_warning_collision_detection "cannot detect" in str(w[-1].message).lower() IndexError: list index out of range ====================================================================== FAIL: Doctest: memory.rst ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/lib/python2.6/doctest.py", line 2163, in runTest raise self.failureException(self.format_failure(new.getvalue())) AssertionError: Failed doctest test for memory.rst File "/home/varoquau/dev/joblib/doc/memory.rst", line 0 ---------------------------------------------------------------------- File "/home/varoquau/dev/joblib/doc/memory.rst", line 218, in memory.rst Failed example: func2(1) Expected: memory.rst:0: JobLibCollisionWarning: Cannot detect name collisions for function 'func' Running func(1) Got: memory.py:0: JobLibCollisionWarning: Cannot detect name collisions for function 'func' Clearing cache /tmp/tmp6YyPJp/joblib/func-alias Running func(1) ---------------------------------------------------------------------- File "/home/varoquau/dev/joblib/doc/memory.rst", line 221, in memory.rst Failed example: func(1) Expected: Running a different func(1) Got: Clearing cache /tmp/tmp6YyPJp/joblib/func-alias Running a different func(1) ---------------------------------------------------------------------- File "/home/varoquau/dev/joblib/doc/memory.rst", line 223, in memory.rst Failed example: func2(1) Expected: Running func(1) Got: Clearing cache /tmp/tmp6YyPJp/joblib/func-alias Running func(1) ---------------------------------------------------------------------- File "/home/varoquau/dev/joblib/doc/memory.rst", line 237, in memory.rst Failed example: g() Expected: memory.rst:0: JobLibCollisionWarning: Cannot detect name collisions for function '' 2 Got: memory.py:0: JobLibCollisionWarning: Cannot detect name collisions for function '' Clearing cache /tmp/tmp6YyPJp/joblib/ 2 ---------------------------------------------------------------------- File "/home/varoquau/dev/joblib/doc/memory.rst", line 241, in memory.rst Failed example: f() Expected: 1 Got: Clearing cache /tmp/tmp6YyPJp/joblib/ 1 >> raise self.failureException(self.format_failure(.getvalue())) ====================================================================== FAIL: Check that collisions impossible to detect will raise appropriate ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/lib/pymodules/python2.6/nose/case.py", line 183, in runTest self.test(*self.arg) AssertionError: 0 != 1 >> raise self.failureException, \ (None or '%r != %r' % (0, 1)) |
Depending on your answer I'd like to change the logic a bit (would that be a new pull request?). Here's the deal:
So what I'd like to do is:
This has a better feel IMO. But if we want to transparently re-store result on unpickling errors, attempt_compute_lock must keep doing the unpickling.
Yes, I tried with a new cachedir in that single test, and also with -vv, but the difference is still there. And the cache dir looks the same in both cases AFAICT. Can you think of anything? |
a), b) and c): the main motivation is that joblib should never fail. I
No. Not in the default behavior. Number 1 problem with joblib in its In my view, the job store is not an ACID database, and is simply a
This does seem better. I am a bit worried about the disk usage. How do
nose does magic with import paths. joblib uses import paths to detect |
OK, in light of your comments I pushed a change that is more explicit about leaving transactional things optionals.
All callers should still use commit/rollback because subclasses/other configurations can support being transactional. |
[For some reason my email reply yesterday did not show up in the web interface, reposting through web interface.]. On 05/02/2011 11:55 AM, GaelVaroquaux wrote:
Ahh. Good example.
I'm not sure if error handling would be different than in 0.5.X, which seems to do no exception catching in the pickling stage. The difference in disk usage with the scheme I want to do with today is:
Worst case both jobs fail because of out-of-space, when one could have succeeded. (Really long-term, this can be mitigated with pessimistic locking.)
Of course, we can make an effort to clean the garbage at the next call, to get the same behaviour as today. In return:
Conclusion: Given your input I'd be a bit uncomfortable myself making this change at this time. But it does depend on the current disk usage behaviour during a race condition. Do you happen to know? If pessimistic locking proves itself down the line, it should be possible to mitigate all ill effects caused by this change. |
Also fix some minor issues with how the store argument was interpreted.
This is a pretty big refactor (based on 0.5.X), introducing job stores. I had to cut a few corners in the end and hack a few small things (commented in source), since I'm not sure when I'll be able to get back to this.
AFAIK it shouldn't change any behaviour, it is a pure refactor.
It may look a bit overdesigned with the "attempt_compute_lock" which may return WAIT etc.; this is because it started out as my branch to do more failsafe + pessimistic locking. That part is ripped out of this commit (because it has a bug, and to keeps things isolated). I promise that the design looks saner in the presence of pessimistic locking + more logic against races embedded.
I will need the pessimistic locking (with WAIT etc.) in my own subclass of DirectoryStore, so it'd be good to have this API in even if it isn't used directly.
I really went through a lot of rounds with this refactoring, and in the end, I'm not 100% happy, but I submit it because I think it is a good start. The really important thing for me was to rip a lot of the logic out of MemoryFunc, so that it can also be used with caching futures-style executors (which don't use memory.cache). It could be argued that some of the logic should be further split up and refactored out of JobStore; I'm just saying that this Works For Me, and seems convenient enough to extend for custom purposes.
Tests pass for me, I haven't tested it with any production/research code.