1. 01 Apr, 2021 3 commits
    • Kirill Smelkov's avatar
      tests: Reset transaction synchronizers before every test run · fe369d32
      Kirill Smelkov authored
      Else, e.g. after a failing test, that closed its storage and DB, but not
      all Connections, another test, just by starting new transaction, would
      invoke synchronization on that unclosed connection, which will try to
      access closed storage and likely fail.
      
      Fixes e.g. https://nexedijs.erp5.net/#/test_result_module/20210401-31B27B3D/5
      
      Crash scenariou is the same as described in 5a5ed2c7 (tests: Force-close
      ZODB connections in teardown, that testing code forgot to explicitly
      close). Only now we try to isolate tests from each other not only for
      different modules, but also for tests inside the same module.
      fe369d32
    • Kirill Smelkov's avatar
      lib/zodb: Add tests for critical ZODB properties that Wendelin.core 2 will depend on · c37a989d
      Kirill Smelkov authored
      The tests verify that there is no concurrency bugs around load,
      Connection.open and invalidations. See e.g.
      
      https://github.com/zopefoundation/ZODB/issues/290
      https://github.com/zopefoundation/ZEO/issues/155
      
      By including the tests into wendelin.core, we will have CI coverage for
      all supported storages (FileStorage, ZEO, NEO), and for all supported
      ZODB (currently ZODB4, ZODB4-wc2 and ZODB5).
      
      ZEO5 is know to currently fail zloadrace.
      However, even though ZODB#290 was fixed, ZEO5 turned out to also fail on zopenrace:
      
              def test_zodb_zopenrace():
                  # exercises ZODB.Connection + particular storage implementation
          >       zopenrace.main()
      
          lib/tests/test_zodb.py:382:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          <decorator-gen-1>:2: in main
              ???
          ../../tools/go/pygolang/golang/__init__.py:103: in _
              return f(*argv, **kw)
          lib/tests/testprog/zopenrace.py:115: in main
              test(zstor)
          <decorator-gen-2>:2: in test
              ???
          ../../tools/go/pygolang/golang/__init__.py:103: in _
              return f(*argv, **kw)
          lib/tests/testprog/zopenrace.py:201: in test
              wg.wait()
          golang/_sync.pyx:246: in golang._sync.PyWorkGroup.wait
              ???
          golang/_sync.pyx:226: in golang._sync.PyWorkGroup.go.pyrunf
              ???
          lib/tests/testprog/zopenrace.py:165: in T1
              t1()
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
              def t1():
                  transaction.begin()
                  zconn = db.open()
      
                  root = zconn.root()
                  obj1 = root['obj1']
                  obj2 = root['obj2']
      
                  # obj1 - reload it from zstor
                  # obj2 - get it from zconn cache
                  obj1._p_invalidate()
      
                  # both objects must have the same values
                  i1 = obj1.i
                  i2 = obj2.i
                  if i1 != i2:
          >           raise AssertionError("T1: obj1.i (%d)  !=  obj2.i (%d)" % (i1, i2))
          E           AssertionError: T1: obj1.i (3)  !=  obj2.i (2)
      
          lib/tests/testprog/zopenrace.py:156: AssertionError
      c37a989d
    • Kirill Smelkov's avatar
      *: tests: don't hang on exception in non-main thread · 08e0c9fb
      Kirill Smelkov authored
      Previously if an assert or something failed in spawned thread, the main
      thread was usually spinning indefinitely = tests hang. -> Switch all
      threading places to use sync.WorkGroup and this way if a thread fails,
      all other threads are canceled and the exception is reported back to
      wg.wait in main thread.
      
      Since we start to go this route, NotifyChannel is reworked to fully use
      channels instead of busy-waiting.
      08e0c9fb
  2. 26 Mar, 2021 1 commit
  3. 08 Mar, 2021 3 commits
    • Kirill Smelkov's avatar
      tox: v↑ NEO (1.9 -> 1.12) · 95b012d3
      Kirill Smelkov authored
      NEO 1.9 was released in 2018 and is outdated by now. NEO 1.12 is
      currently the latest NEO release.
      95b012d3
    • Kirill Smelkov's avatar
      Require Zodbtools · d62a297c
      Kirill Smelkov authored
      After switching to ZODB >= 4 in the previous commit, we can safely
      require zodbtools, because there is now no conflict in between
      ZODB3/ZODB eggs.
      d62a297c
    • Kirill Smelkov's avatar
      Drop support for ZODB3 · 0802da2b
      Kirill Smelkov authored
      It's been a while since last ZODB3 3.10.7 release in 2016 and the last
      commit in upstream ZODB3 repository (3.10 branch) is from 2017. The
      world switched since then to ZODB4 and to ZODB5 after that.
      
      We were still requiring ZODB3, because ZODB3 3.11 egg was just a
      dependency on newer ZODB, ZEO, BTrees and persistent; and this way we
      could be supporting all ZODB3.10.x and  ZODB4 and ZODB5 via ZODB3.11.
      
      However upcoming Wendelin.core 2, for its proper working, needs MVCC
      semantic as implemented in ZODB5. This forces us, even for ZODB4, to
      backport non-trivial bits from ZODB5 (see [1]). Maintaining ZODB3
      support at this point becomes non-practical, because, to our knowledge,
      there is no wendelin.core user that plans to continue using ZODB3
      without switching to at least ZODB4 in the near future.
      
      So goodbye ZODB3. Even though ZODB still stays with us, it gives a
      feeling similar to [2], because in 2014, when I was myself learning
      ZODB, it was through ZODB3 - still at the time when all ZODB bits were
      living together in one place.
      
      [1] nexedi/ZODB!1
      [2] https://lists.osuosl.org/pipermail/darcs-users/2008-September/014095.html
      0802da2b
  4. 11 Dec, 2020 1 commit
    • Kirill Smelkov's avatar
      tests: Don't try to access db.storage when automatically closing connections · fd6b5252
      Kirill Smelkov authored
      DB.close() does `del self.storage`.
      
      https://github.com/zopefoundation/ZODB/blob/5.6.0-14-g0eae10cd0/src/ZODB/DB.py#L646
      
      This way if DB was closed, but some conn(s) were not, it will crash in
      teardown as e.g. below:
      
          _____________ ERROR at teardown of test_bigfile_zblk1_zdata_reuse ______________
      
              def teardown_module():
          >       testdb.teardown()
      
          bigfile/tests/test_filezodb.py:58:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          self = <wendelin.lib.testing.TestDB_ZEO object at 0x7fb9c0216350>
      
              def teardown(self):
                  # close connections that test code forgot to close
                  for connref, tb in self.connv:
                      conn = connref()
                      if conn is None:
                          continue
                      if not conn.opened:
                          continue    # still alive, but closed
                      print("W: testdb: teardown: %s left not closed by test code"
                            "; opened by:\n%s" % (conn, tb), file=sys.stderr)
      
                      db = conn.db()
          >           stor = db.storage
          E           AttributeError: 'DB' object has no attribute 'storage'
      
          lib/testing.py:217: AttributeError
      
      The fix is simple - don't use db.storage at all, because it is not actually used in that code.
      fd6b5252
  5. 17 Nov, 2020 2 commits
  6. 03 Nov, 2020 2 commits
    • Kirill Smelkov's avatar
      t/tfault-run: Require bash · a702d410
      Kirill Smelkov authored
      Otherwise when /bin/sh is dash it fails with
      
          t/tfault-run: 35: test: on_pagefault: unexpected operator
      a702d410
    • Kirill Smelkov's avatar
      t/tfault-run: Clear state from previous run before starting · cf92dfca
      Kirill Smelkov authored
      Otherwise, if previous test.fault failed, tfault-run fails to start, e.g.
      
          >>> test.fault
          $ make test.fault # MAKEFLAGS=-j1
          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
          mkdir: cannot create directory ‘t/tfault-run.faultr’: File exists
          Makefile:186: recipe for target 'faultr.tfault' failed
          make: *** [faultr.tfault] Error 1
          rm bigfile/tests/tfault.t
          error   test.fault      0.433s  # 1t 1e 0f 0s
      cf92dfca
  7. 02 Nov, 2020 1 commit
  8. 11 Sep, 2020 1 commit
  9. 17 May, 2020 2 commits
  10. 17 Apr, 2020 1 commit
  11. 15 Apr, 2020 10 commits
    • Kirill Smelkov's avatar
      setup: Fix hooking of git_lsfiles in PEP517 mode · bd1fb19e
      Kirill Smelkov authored
      In PEP517 mode setup.py is sourced - not executed - and the build fails
      with ImportError like this:
      
          Preparing wheel metadata ... error
          ERROR: Command errored out with exit status 1:
           command: /home/kirr/src/wendelin/venv/z-dev/bin/python2 /home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmp2F3aEs
               cwd: /home/kirr/src/wendelin/wendelin.core
          Complete output (53 lines):
          running dist_info
          creating /tmp/pip-modern-metadata-sPiqUt/wendelin.core.egg-info
          writing requirements to /tmp/pip-modern-metadata-sPiqUt/wendelin.core.egg-info/requires.txt
          writing /tmp/pip-modern-metadata-sPiqUt/wendelin.core.egg-info/PKG-INFO
          writing top-level names to /tmp/pip-modern-metadata-sPiqUt/wendelin.core.egg-info/top_level.txt
          writing dependency_links to /tmp/pip-modern-metadata-sPiqUt/wendelin.core.egg-info/dependency_links.txt
          writing entry points to /tmp/pip-modern-metadata-sPiqUt/wendelin.core.egg-info/entry_points.txt
          writing manifest file '/tmp/pip-modern-metadata-sPiqUt/wendelin.core.egg-info/SOURCES.txt'
          package init file '__init__.py' not found (or not a regular file)
          Traceback (most recent call last):
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py", line 257, in <module>
              main()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py", line 240, in main
              json_out['return_val'] = hook(**hook_input['kwargs'])
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py", line 110, in prepare_metadata_for_build_wheel
              return hook(metadata_directory, config_settings)
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/build_meta.py", line 155, in prepare_metadata_for_build_wheel
              self.run_setup()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/build_meta.py", line 234, in run_setup
              self).run_setup(setup_script=setup_script)
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/build_meta.py", line 141, in run_setup
              exec(compile(code, __file__, 'exec'), locals())
            File "setup.py", line 374, in <module>
              """.splitlines()]
            File "/home/kirr/src/tools/go/pygolang/golang/pyx/build.py", line 118, in setup
              setuptools_dso.setup(**kw)
            File "/home/kirr/src/tools/py/pypa/setuptools_dso/src/setuptools_dso/__init__.py", line 37, in setup
              _setup(**kws)
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/__init__.py", line 145, in setup
              return distutils.core.setup(**attrs)
            File "/usr/lib/python2.7/distutils/core.py", line 151, in setup
              dist.run_commands()
            File "/usr/lib/python2.7/distutils/dist.py", line 953, in run_commands
              self.run_command(cmd)
            File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
              cmd_obj.run()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/command/dist_info.py", line 31, in run
              egg_info.run()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/command/egg_info.py", line 296, in run
              self.find_sources()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/command/egg_info.py", line 303, in find_sources
              mm.run()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/command/egg_info.py", line 534, in run
              self.add_defaults()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/command/egg_info.py", line 574, in add_defaults
              rcfiles = list(walk_revctrl())
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/setuptools/command/sdist.py", line 20, in walk_revctrl
              for item in ep.load()(dirname):
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2434, in load
              return self.resolve()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2444, in resolve
              raise ImportError(str(exc))
          ImportError: 'module' object has no attribute 'git_lsfiles'
      
      See comments added to register_as_entrypoint for explanation of what
      happens.
      
      Wendelin.core will soon switch to PEP517 mode (by adding pyproject.toml)
      to build-require Cython, Pygolang and friends.
      bd1fb19e
    • Kirill Smelkov's avatar
      lib/zodb: Add zstor_2zurl - way to convert a ZODB storage into URL to access it · 6637d216
      Kirill Smelkov authored
      Wendelin.core 2 will need to spawn WCFS filesystem server that accesses
      the same ZODB database as the program that spawns it. The database
      argument passed to WCFS is passed in the form of URL[1,2].  Even though
      zodburi provides way to convert an URL into ZODB storage instance, there
      is currently no way for reverse operation - to convert ZODB storage
      instance into URL to access it(*). So we have to build it by our own.
      
      Provide zstor_2zurl stub that currently works for FileStorage only.
      ZEO and NEO support is TODO.
      
      In the future we might want to move this functionality into
      zodbtools/py.
      
      [1] https://lab.nexedi.com/nexedi/zodbtools/blob/a2e4dd23/zodbtools/help.py#L27-53
      [2] https://lab.nexedi.com/kirr/neo/blob/3d909114/go/zodb/zodbtools/help.go#L25-51
      
      (*) contrary to ZODB/go where this functionality is provided out of the box:
          https://godoc.org/lab.nexedi.com/kirr/neo/go/zodb#IStorage
      6637d216
    • Kirill Smelkov's avatar
      lib/zodb: Add patch to ZODB.Connection to support callback on connection DB view change · 959ae2d0
      Kirill Smelkov authored
      Wendelin.core 2 will need to hook into when client ZODB.Connection
      changes its database view and readjust WCFS-level client connection
      accordingly.
      
      ZODB.Connection can change its view on either connection reopen, or even
      without reopen on start of new transaction.
      
      This patch implements ZODB.Connection.onResyncCallback for ZODB5 only.
      
      ZODB4 and ZODB3 support is TODO.
      959ae2d0
    • Kirill Smelkov's avatar
      lib/zodb: Add zconn_at draft (ZODB5 only) · 3bd82127
      Kirill Smelkov authored
      For wendelin.core v2 we need a way to know at which particular database
      state application-level ZODB connection is viewing the database. Knowing
      that state, WCFS client library will interact with WCFS filesystem server
      and, in simple terms, request the server to provide data as of that
      particular database state.
      
      Contrary to ZODB/go[1] ZODB/py does not provide the functionality to
      obtain DB state of connection view, so we have to build it ourselves.
      Let us call the function that for a client ZODB connection returns
      database state corresponding to its database view as zconn_at.
      
      It is relatively easy to implement zconn_at for ZODB5, since ZODB5
      adopted MVCC uniformly and this patch does just that. However even with
      ZODB5 currently all released ZODB5 versions have race in
      Connection.open() vs invalidations[2], and so the first ZODB5 release
      with which zconn_at implemented here will work reliable should be
      upcoming ZODB 5.5.2
      
      It is TODO to implement zconn_at for ZODB4 and ZODB3, which organize
      things differently.
      
      Please note what would happen if zconn_at gives, even a bit, incorrect
      answer: wcfs client will ask wcfs server to provide array data as of
      different database state compared to current on-client ZODB connection.
      This will result in that data accessed via ZBigArray will _not_
      correspond to all other data accessed via regular ZODB mechanism.
      It is, in other words, would be a data corruptions.
      
      [1] https://godoc.org/lab.nexedi.com/kirr/neo/go/zodb#Connection
      [2] https://github.com/zopefoundation/ZODB/issues/290
      3bd82127
    • Kirill Smelkov's avatar
      lib/zodb: Add zmajor - way to know under which ZODB 3, 4 or 5 we are running · 8c0b7471
      Kirill Smelkov authored
      This will be needed in the following patches to know how to inject
      zconn_at or zconn resync functionality into particular ZODB version.
      8c0b7471
    • Kirill Smelkov's avatar
      bigfile/zodb: Cosmetics · c671aaea
      Kirill Smelkov authored
      - mention in comments that _ZBigFileH not only proxies changes from
        virtmem -> ZODB, but also the other way: virtmem <- ZODB.
      - refresh comments, fix typo.
      c671aaea
    • Kirill Smelkov's avatar
      bigfile/file.h: Cosmetics · 927458f6
      Kirill Smelkov authored
      - Provide brief top-level overview + refresh loadblk/storeblk/release comments.
      - Add `typedef struct bigfile_ops bigfile_ops` that we usually add for all structs.
      927458f6
    • Kirill Smelkov's avatar
      bigfile/virtmem: vma_page_addr: Kill wrong XXX · 34ed82c6
      Kirill Smelkov authored
      It is valid to compare a Page and a VMA only if they belong to the same
      fileh.
      34ed82c6
    • Kirill Smelkov's avatar
      bigfile/virtmem: Factor-out checking whether `page->fpgoffset` is in file-range covered by `vma` · d53a480f
      Kirill Smelkov authored
      -> into vma_page_infilerange().
      
      We will soon need to use this functionality from several places.
      d53a480f
    • Kirill Smelkov's avatar
      bigfile/virtmem: fileh_mmap: Refactor a bit · 516f4625
      Kirill Smelkov authored
      Start preparing vma early, not after the call to mem_valloc.
      This codeflow will be more convenient when we add mmap-through-wcfs codepath.
      516f4625
  12. 14 Apr, 2020 4 commits
  13. 01 Apr, 2020 2 commits
  14. 18 Dec, 2019 7 commits
    • Kirill Smelkov's avatar
      bigfile/py: Move data structures to public .h file · 907bd9d4
      Kirill Smelkov authored
      This is needed so that e.g. a Python class implemented in C or Cython
      (cdef class) could inherit from PyBigFile.
      
      Don't put _bigfile.h into separate include/ directory, and keep it along
      main .c file, similarly to how pygolang is organized.
      907bd9d4
    • Kirill Smelkov's avatar
      bigfile/py: Provide package-level documentation · 3684d164
      Kirill Smelkov authored
      Provide package-level documentation that gives brief overview of what
      this package does. Split internal notes into separate comment.
      3684d164
    • Kirill Smelkov's avatar
      bigfile/py: Stop using Plan9 C extensions · bf44905b
      Kirill Smelkov authored
      Starting from 5755a6b3 (Basic setup.py / Makefile to build/install/sdist
      stuff + bigfile.so skeleton) and 35eb95c2 (bigfile: Python wrapper
      around virtual memory subsystem) we were using Plan9 C extensions[1] for
      simple inheritance. Those extensions are supported by GCC with
      -fplan9-extensions option. However that option is supported only for C,
      while for C++ it does not work at all with error produced by the compiler
      on Plan9 syntax.
      
      Soon we'll need to add another extension - written in C++ - to
      wendelin.core . This extension will be providing client side of WCFS and
      integrating that with virtmem. In that extension we'll need to use
      _bigfile data structures - in particular we'll need to use PyBigFile and
      extend it with another `cdef class` children written in Cython/C++.
      
      This patch prepares for that: first stop using Plan9 C extensions in
      _bigfile py module data structures and adapt the code correspondingly.
      In the next patch we'll move those data structures into an .h file.
      
      We don't drop -fplan9-extensions from setup.py, because Plan9-style
      inheritance continues to be used internally by virtmem - e.g. in
      ram_shmfs.c and friends.
      
      A bit pity to drop that good stuff, but given that we'll need to use C++
      for WCFS client for other good stuff provided by pygolang[2], it is a
      reasonable compromise.
      
      [1] http://9p.io/sys/doc/comp.html  "Extensions" section
      [2] https://pypi.org/project/pygolang
      bf44905b
    • Kirill Smelkov's avatar
      bigfile/zodb: Factor-out LivePersistent into -> lib/zodb · c02776e9
      Kirill Smelkov authored
      It was from long-ago marked as "XXX move to common place".
      c02776e9
    • Kirill Smelkov's avatar
      bigfile/zodb: FIXME invalidations are not working correctly on blocks topology change · 8c32c9f6
      Kirill Smelkov authored
      I noticed this while working on WCFS: if file blocks topology change,
      the invalidation process is not working correctly. It is also not
      correct with respect to live cache pressure.
      
      Add FIXME in the code and test for live cache pressure.
      
      kirr/wendelin.core@5a4562fc
      kirr/wendelin.core@48eb692f
      kirr/wendelin.core@d1a579b2
      kirr/wendelin.core@69c94fbc
      8c32c9f6
    • Kirill Smelkov's avatar
      bigfile/zodb: Explain why we always mark ZBlk object changed if block data change · d27ade8e
      Kirill Smelkov authored
      For ZBlk0 this is trivial, but for ZBlk1 it may seem that we could avoid
      changing ZBlk object itself and mark only pointed-to ZData object as
      changed. However that would be not correct to do if we consider
      invalidations.
      
      Noticed while working on WCFS.
      d27ade8e
    • Kirill Smelkov's avatar
      *: Add package-level documentation to ZODB-related packages · d5e0d2f9
      Kirill Smelkov authored
      Add package-level documentation to
      
        - bigfile/file_zodb.py,
        - bigarray/array_zodb.py, and
        - lib/zodb.py
      
      The most interesting read is file_zodb.py .
      
      Slightly improve documenation for functions in a couple of places.
      
      Improving documentation was long overdue and it is improved only slightly by this commit.
      d5e0d2f9