subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From v...@apache.org
Subject svn commit: r1425415 [1/13] - in /subversion/branches/javahl-ra: ./ build/generator/templates/ notes/ notes/directory-index/ subversion/bindings/swig/python/svn/ subversion/bindings/swig/ruby/test/ subversion/include/ subversion/include/private/ subver...
Date Sun, 23 Dec 2012 06:03:17 GMT
Author: vmpn
Date: Sun Dec 23 06:03:14 2012
New Revision: 1425415

URL: http://svn.apache.org/viewvc?rev=1425415&view=rev
Log:
On the javahl-ra branch:

Bring up-to-date with trunk@1366020

Added:
    subversion/branches/javahl-ra/subversion/libsvn_subr/utf_width.c
      - copied unchanged from r1366020, subversion/trunk/subversion/libsvn_subr/utf_width.c
    subversion/branches/javahl-ra/subversion/svn/file-merge.c
      - copied unchanged from r1366020, subversion/trunk/subversion/svn/file-merge.c
    subversion/branches/javahl-ra/subversion/tests/cmdline/wc_tests.py
      - copied unchanged from r1366020, subversion/trunk/subversion/tests/cmdline/wc_tests.py
    subversion/branches/javahl-ra/subversion/tests/libsvn_subr/io-test.c
      - copied unchanged from r1366020, subversion/trunk/subversion/tests/libsvn_subr/io-test.c
Modified:
    subversion/branches/javahl-ra/   (props changed)
    subversion/branches/javahl-ra/CHANGES
    subversion/branches/javahl-ra/COMMITTERS
    subversion/branches/javahl-ra/INSTALL
    subversion/branches/javahl-ra/LICENSE
    subversion/branches/javahl-ra/NOTICE
    subversion/branches/javahl-ra/build.conf
    subversion/branches/javahl-ra/build/generator/templates/svn_config.vcxproj.ezt
    subversion/branches/javahl-ra/configure.ac
    subversion/branches/javahl-ra/get-deps.sh
    subversion/branches/javahl-ra/notes/authz_policy.txt
    subversion/branches/javahl-ra/notes/directory-index/dirindex.py
    subversion/branches/javahl-ra/notes/directory-index/schema.sql
    subversion/branches/javahl-ra/subversion/bindings/swig/python/svn/fs.py
    subversion/branches/javahl-ra/subversion/bindings/swig/ruby/test/test_client.rb
    subversion/branches/javahl-ra/subversion/include/private/svn_delta_private.h
    subversion/branches/javahl-ra/subversion/include/private/svn_skel.h
    subversion/branches/javahl-ra/subversion/include/private/svn_wc_private.h
    subversion/branches/javahl-ra/subversion/include/svn_error_codes.h
    subversion/branches/javahl-ra/subversion/include/svn_fs.h
    subversion/branches/javahl-ra/subversion/include/svn_io.h
    subversion/branches/javahl-ra/subversion/include/svn_path.h
    subversion/branches/javahl-ra/subversion/include/svn_ra.h
    subversion/branches/javahl-ra/subversion/include/svn_utf.h
    subversion/branches/javahl-ra/subversion/libsvn_client/checkout.c
    subversion/branches/javahl-ra/subversion/libsvn_client/client.h
    subversion/branches/javahl-ra/subversion/libsvn_client/externals.c
    subversion/branches/javahl-ra/subversion/libsvn_client/log.c
    subversion/branches/javahl-ra/subversion/libsvn_client/merge.c
    subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c
    subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h
    subversion/branches/javahl-ra/subversion/libsvn_client/switch.c
    subversion/branches/javahl-ra/subversion/libsvn_client/update.c
    subversion/branches/javahl-ra/subversion/libsvn_delta/svndiff.c
    subversion/branches/javahl-ra/subversion/libsvn_diff/parse-diff.c
    subversion/branches/javahl-ra/subversion/libsvn_fs/fs-loader.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/bdb-err.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/changes-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/checksum-reps-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/copies-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/lock-tokens-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/locks-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/miscellaneous-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/node-origins-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/nodes-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/reps-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/rev-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/strings-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/txn-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/bdb/uuids-table.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/fs.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/lock.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_base/trail.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs.h
    subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_fs/rep-cache.c
    subversion/branches/javahl-ra/subversion/libsvn_fs_fs/structure
    subversion/branches/javahl-ra/subversion/libsvn_fs_fs/tree.c
    subversion/branches/javahl-ra/subversion/libsvn_ra/ra_loader.h
    subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c
    subversion/branches/javahl-ra/subversion/libsvn_repos/dump.c
    subversion/branches/javahl-ra/subversion/libsvn_repos/fs-wrap.c
    subversion/branches/javahl-ra/subversion/libsvn_repos/repos.c
    subversion/branches/javahl-ra/subversion/libsvn_subr/deprecated.c
    subversion/branches/javahl-ra/subversion/libsvn_subr/io.c
    subversion/branches/javahl-ra/subversion/libsvn_subr/path.c
    subversion/branches/javahl-ra/subversion/libsvn_subr/simple_providers.c
    subversion/branches/javahl-ra/subversion/libsvn_subr/skel.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/adm_ops.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/conflicts.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/conflicts.h
    subversion/branches/javahl-ra/subversion/libsvn_wc/copy.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/crop.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/entries.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/externals.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/info.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/lock.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/merge.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/node.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/props.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/props.h
    subversion/branches/javahl-ra/subversion/libsvn_wc/questions.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/status.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/tree_conflicts.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/update_editor.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/upgrade.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/util.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/wc-metadata.sql
    subversion/branches/javahl-ra/subversion/libsvn_wc/wc-queries.sql
    subversion/branches/javahl-ra/subversion/libsvn_wc/wc.h
    subversion/branches/javahl-ra/subversion/libsvn_wc/wc_db.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/wc_db.h
    subversion/branches/javahl-ra/subversion/libsvn_wc/workqueue.c
    subversion/branches/javahl-ra/subversion/libsvn_wc/workqueue.h
    subversion/branches/javahl-ra/subversion/mod_dav_svn/liveprops.c
    subversion/branches/javahl-ra/subversion/po/de.po
    subversion/branches/javahl-ra/subversion/po/fr.po
    subversion/branches/javahl-ra/subversion/svn/cl.h
    subversion/branches/javahl-ra/subversion/svn/conflict-callbacks.c
    subversion/branches/javahl-ra/subversion/svn/export-cmd.c
    subversion/branches/javahl-ra/subversion/svn/log-cmd.c
    subversion/branches/javahl-ra/subversion/svn/main.c
    subversion/branches/javahl-ra/subversion/svn/merge-cmd.c
    subversion/branches/javahl-ra/subversion/svn/notify.c
    subversion/branches/javahl-ra/subversion/svn/resolve-cmd.c
    subversion/branches/javahl-ra/subversion/svn/switch-cmd.c
    subversion/branches/javahl-ra/subversion/svn/update-cmd.c
    subversion/branches/javahl-ra/subversion/svnadmin/main.c
    subversion/branches/javahl-ra/subversion/svnlook/main.c
    subversion/branches/javahl-ra/subversion/tests/cmdline/basic_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/commit_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/copy_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/davautocheck.sh
    subversion/branches/javahl-ra/subversion/tests/cmdline/depth_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/merge_reintegrate_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tree_conflict_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/special_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/svnlook_tests.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/svntest/main.py
    subversion/branches/javahl-ra/subversion/tests/cmdline/update_tests.py
    subversion/branches/javahl-ra/subversion/tests/libsvn_diff/diff-diff3-test.c
    subversion/branches/javahl-ra/subversion/tests/libsvn_fs_fs/fs-pack-test.c
    subversion/branches/javahl-ra/subversion/tests/libsvn_subr/   (props changed)
    subversion/branches/javahl-ra/subversion/tests/libsvn_subr/skel-test.c
    subversion/branches/javahl-ra/subversion/tests/libsvn_wc/conflict-data-test.c
    subversion/branches/javahl-ra/subversion/tests/libsvn_wc/db-test.c
    subversion/branches/javahl-ra/subversion/tests/libsvn_wc/op-depth-test.c
    subversion/branches/javahl-ra/subversion/tests/libsvn_wc/wc-queries-test.c
    subversion/branches/javahl-ra/tools/dev/benchmarks/suite1/benchmark.py
    subversion/branches/javahl-ra/tools/dev/benchmarks/suite1/run
    subversion/branches/javahl-ra/tools/dev/benchmarks/suite1/run.bat
    subversion/branches/javahl-ra/tools/dev/gdb-py/svndbg/printers.py
    subversion/branches/javahl-ra/win-tests.py

Propchange: subversion/branches/javahl-ra/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1355759-1366020

Modified: subversion/branches/javahl-ra/CHANGES
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/CHANGES?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/CHANGES (original)
+++ subversion/branches/javahl-ra/CHANGES Sun Dec 23 06:03:14 2012
@@ -26,6 +26,7 @@ http://svn.apache.org/repos/asf/subversi
     * ra_serf avoids re-downloading content present in pristine store (r1333936)
     * 'svn mergeinfo' now honors the --revision (-r) option (issue #4199)
     * new --search and --isearch options for 'svn log' (r1354666, -830)
+    * new built-in interactive text conflict merge tool (r1357864, et al)
 
   - Client-side bugfixes:
     *
@@ -47,6 +48,41 @@ http://svn.apache.org/repos/asf/subversi
     *
 
 
+Version 1.7.6
+(XX YYY 2012, from /branches/1.7.x)
+http://svn.apache.org/repos/asf/subversion/tags/1.7.6
+
+ User-visible changes:
+  - Client- and server-side bugfixes:
+
+  - Client-side bugfixes:
+    * Fix "svn status -u --depth empty FILE" (r1348822, r1349215)
+    * Fix example output of 'svn help status' (issue #3962)
+    * svn propset of svn:eol-style might not notice related text changes (r1353572)
+    * sort output of 'svn propget -R' (r1355699)
+    * sort output of 'svn proplist' (r1355698)
+    * sort output of 'svn status' (r1341012)
+    * avoid a filestat per working copy find operation (r1340556)
+    * optimize 'svn upgrade' performance on large working copies (r1342984)
+    * allow 'file:///C:\repos' style arguments on Windows, like 1.6 (r1346765)
+    * fix ra_serf against Subversion 1.2 servers (r1349367)
+    * fix 'svn upgrade' on working copies with certain tree conflicts (r1345482)
+
+  - Server-side bugfixes:
+    * partial sync drops properties when converting to adds (issue #4184)
+    * replaying a copy and delete of an unreadable child fails (issue #4121)
+
+  - Other tool improvements and bugfixes:
+
+ Developer-visible changes:
+  - General:
+    * fix running tests against httpd 2.4 (r1291594)
+
+  - Bindings:
+    * JavaHL: Don't assert on some invalid input (r1354626, r1354652)
+    * JavaHL: Add missing new in 1.7 notifications (r1351772)
+
+
 Version 1.7.5
 (17 May 2012, from /branches/1.7.x)
 http://svn.apache.org/repos/asf/subversion/tags/1.7.5

Modified: subversion/branches/javahl-ra/COMMITTERS
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/COMMITTERS?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/COMMITTERS [UTF-8] (original)
+++ subversion/branches/javahl-ra/COMMITTERS [UTF-8] Sun Dec 23 06:03:14 2012
@@ -39,7 +39,7 @@ Blanket commit access:
         pburba   Paul Burba <pburba@collab.net>
        glasser   David Glasser <glasser@davidglasser.net>
            lgo   Lieven Govaerts <lgo@mobsol.be>
-       hwright   Hyrum Wright <hyrum.wright@wandisco.com>
+       hwright   Hyrum Wright <hyrum@hyrumwright.org>
     vgeorgescu   Vlad Georgescu <vgeorgescu@gmail.com>
        kameshj   Kamesh Jayachandran <kamesh@collab.net>
       markphip   Mark Phippard <mphippard@collab.net>

Modified: subversion/branches/javahl-ra/INSTALL
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/INSTALL?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/INSTALL (original)
+++ subversion/branches/javahl-ra/INSTALL Sun Dec 23 06:03:14 2012
@@ -96,29 +96,23 @@ I.    INTRODUCTION
          These diff streams are used everywhere -- over the network,
          in the repository, and in the client's working copy.
 
-      * libserf or libneon  (OPTIONAL for client)
+      * libserf  (OPTIONAL for client)
 
-         The Serf and Neon libraries both allow the Subversion client
-         to send HTTP requests.  This is necessary if you want your
-         client to access a repository served by the Apache HTTP
-         server.  There is an alternate 'svnserve' server as well,
-         though, and clients automatically know how to speak the
-         svnserve protocol.  Thus it's not strictly necessary for your
-         client to be able to speak HTTP... though we still recommend
-         that your client be built to speak both HTTP and svnserve
-         protocols.  Your client can be compiled against either
-         libserf or libneon (or both), as they offer competing
-         implementations.
+         The Serf library allows the Subversion client to send HTTP
+         requests.  This is necessary if you want your client to access
+         a repository served by the Apache HTTP server.  There is an
+         alternate 'svnserve' server as well, though, and clients
+         automatically know how to speak the svnserve protocol.
+         Thus it's not strictly necessary for your client to be able
+         to speak HTTP... though we still recommend that your client
+         be built to speak both HTTP and svnserve protocols.
 
       * OpenSSL (OPTIONAL for client and server)
 
          OpenSSL enables your client to access SSL-encrypted https://
-         URLs (using libserf or libneon) in addition to unencrypted
-         http:// URLs.  To use SSL with Subversion's WebDAV server,
-         Apache needs to be compiled with OpenSSL as well.
-
-         The Neon library can use the GnuTLS library as an alternative
-         to OpenSSL.
+         URLs (using libserf) in addition to unencrypted http:// URLs.
+         To use SSL with Subversion's WebDAV server, Apache needs to be
+         compiled with OpenSSL as well.
 
       * Berkeley DB (OPTIONAL for client and server)
 
@@ -177,10 +171,10 @@ I.    INTRODUCTION
       team has created a script that downloads the minimal prerequisite
       libraries (Apache Portable Runtime, Sqlite, and Zlib).  The script,
       'get-deps.sh', is available in the same directory as this file.
-      When run, it will place 'apr', 'apr-util', 'serf', 'neon',
-      'zlib', and 'sqlite-amalgamation' directories directly into your
-      unpacked Subversion distribution, where they will be automatically
-      configured and built by Subversion's build process.
+      When run, it will place 'apr', 'apr-util', 'serf', 'zlib', and
+      'sqlite-amalgamation' directories directly into your unpacked Subversion
+      distribution, where they will be automatically configured and built by
+      Subversion's build process.
 
       Note: there are optional dependencies (such as openssl, swig, and httpd)
       which get-deps.sh does not download and Subversion does not attempt to
@@ -313,44 +307,22 @@ I.    INTRODUCTION
       newer. The autogen.sh script knows about that.
 
 
-      5.  An HTTP client library:  serf or neon.  (OPTIONAL)
+      5.  Serf library 1.1 or newer (http://code.google.com/p/serf/) (OPTIONAL)
 
       If you want your client to be able to speak to an Apache
       server (via a http:// or https:// URL), you must link against
-      at least one of these libraries.  Though optional, we strongly
-      recommend this.
+      serf.  Though optional, we strongly recommend this.
 
-      (If you link against both, Subversion will use ra_serf by
-      default.  Add "http-library = neon" to the [global] section of
-      your ~/.subversion/servers file to use ra_neon instead.)
-
-        a. Serf library 1.1.0 or newer (http://code.google.com/p/serf/)
-
-           In order to use ra_serf, you must install serf, and run
-           Subversion's ./configure with the argument --with-serf.  If
-           serf is installed in a non-standard place, you should use
+      In order to use ra_serf, you must install serf, and run Subversion's
+      ./configure with the argument --with-serf.  If serf is installed in a
+      non-standard place, you should use
 
                --with-serf=/path/to/serf/install
 
-           instead.
-
-           For more information on serf and Subversion's ra_serf, see
-           the file subversion/libsvn_ra_serf/README.
-
-        b. Neon library 0.25 through 0.29 (http://www.webdav.org/neon/)
-
-           In order to use ra_neon, you must install neon, and run
-           Subversion's ./configure with the argument --with-neon.
-           Subversion's configuration mechanism should then detect the
-           installed Neon.  If it does not, you may need to set the
-           LDFLAGS environment variable when you run "./configure", or
-           specify Neon's location by passing the "--with-neon="
-           option to "./configure".  Look for the "neon-config" script
-           in a "bin/" subdirectory of the target of "--with-neon".
-           For example, if you pass "--with-neon=/usr/local/myneon/",
-           then there should be a file
-           "/usr/local/myneon/bin/neon-config".
+      instead.
 
+      For more information on serf and Subversion's ra_serf, see the file
+      subversion/libsvn_ra_serf/README.
 
       6. OpenSSL  (OPTIONAL)
 
@@ -358,28 +330,19 @@ I.    INTRODUCTION
       ### finding OpenSSL, but we may need more docco here. and w.r.t
       ### zlib.
 
-      The Serf and Neon libraries have support for SSL encryption by
-      relying on the OpenSSL library.
+      The Serf library has support for SSL encryption by relying on the
+      OpenSSL library.
 
         a. Using OpenSSL on the client through Serf
 
-        b. Using OpenSSL on the client through Neon
-
-          When Neon is created with this dependency, then the Subversion
-          client inherits the ability to support SSL connections.  Neon
-          also has support for sending compressed data using the zlib
-          library which a Subversion client can take advantage of.
-
-          On Unix systems, to build Neon with OpenSSL, you need OpenSSL
+          On Unix systems, to build Serf with OpenSSL, you need OpenSSL
           installed on your system, and you must add "--with-ssl" as a
           "./configure" parameter.  If your OpenSSL installation is hard
-          for Neon to find, you may need to use "--with-libs=/path/to/lib"
+          for Serf to find, you may need to use "--with-libs=/path/to/lib"
           in addition.  In particular, on Red Hat (but not Fedora Core) it
           is necessary to specify "--with-libs=/usr/kerberos" for OpenSSL
           to be found.  You can also specify a path to the zlib library
-          using "--with-libs".  Consult the Neon documentation for more
-          information on how to use these parameters and versions of
-          libraries you need.
+          using "--with-libs".
 
           Under Windows, you can specify the paths to these libraries by
           passing the options --with-zlib and --with-openssl to gen-make.py.
@@ -651,7 +614,6 @@ II.   INSTALLATION
           db*.i386.rpm     (Version 4.0.14 or greater; version 4.3.27 or
                             4.2.52 is preferred however)
           expat            (Comes with RedHat)
-          neon             (Version 0.25.5)
 
       After downloading, install it (as root user):
 
@@ -683,7 +645,7 @@ II.   INSTALLATION
           # rm -f /usr/local/lib/libsvn*
           # rm -f /usr/local/lib/libapr*
           # rm -f /usr/local/lib/libexpat*
-          # rm -f /usr/local/lib/libneon*
+          # rm -f /usr/local/lib/libserf*
 
       Start the process by running "autogen.sh":
 
@@ -849,11 +811,6 @@ II.   INSTALLATION
         needed to compile Apache or APR.  Note that this is the actual awk
         program, not an installer - just rename it to awk.exe and it is
         ready to use.
-      * Neon 0.26.1 or higher, downloaded from
-        http://www.webdav.org/neon/neon-0.26.1.tar.gz which is required
-        for building the client components.  Neon is included in the zip file
-        distribution.  (0.25.0+ compiles, but does not properly support all
-        HTTP auth types.)
       * Apache apr, apr-util, and optionally apr-iconv libraries, version
         0.9.12 or later. Included in both the Subversion dependencies ZIP file
         and the Apache 2 source zip.  If you are building from a Subversion
@@ -907,7 +864,7 @@ II.   INSTALLATION
 
   E.2 Notes
 
-      The Neon library supports secure connections with OpenSSL and
+      The Serf library supports secure connections with OpenSSL and
       on-the-wire compression with zlib. If you want to use the
       secure connections feature, you should pass the option
       "--with-openssl" to the gen-make.py script. See Section I.11 for
@@ -955,9 +912,8 @@ II.   INSTALLATION
         server dso modules and are using Visual Studio 6.  You must build
         and install it from source if you are not using Visual Studio 6 and
         want to build and/or test the server modules.
-      * If you checked out Subversion from the repository then extract neon
-        into SVN\src-trunk\neon, the zip file source distribution includes
-        neon.
+      * If you checked out Subversion from the repository then install the serf
+        sources into SVN\src-trunk\serf.
       * If you want BDB backend support, extract the Berkeley DB files
         into SVN\src-trunk\db4-win32. It's a good idea to add
         SVN\src-trunk\db4-win32\bin to your PATH, so that Subversion can find

Modified: subversion/branches/javahl-ra/LICENSE
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/LICENSE?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/LICENSE (original)
+++ subversion/branches/javahl-ra/LICENSE Sun Dec 23 06:03:14 2012
@@ -260,3 +260,11 @@ subversion/bindings/swig/python/tests/tr
      IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
      IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+For the file subversion/libsvn_subr/utf_width.c
+
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.

Modified: subversion/branches/javahl-ra/NOTICE
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/NOTICE?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/NOTICE (original)
+++ subversion/branches/javahl-ra/NOTICE Sun Dec 23 06:03:14 2012
@@ -13,4 +13,6 @@ For more information, see LICENSE.
 This product includes software developed under the X Consortium License
 see: build/install-sh
 
+This product includes software developed by Markus Kuhn under a permissive
+license, see LICENSE.
 

Modified: subversion/branches/javahl-ra/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/build.conf?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/build.conf (original)
+++ subversion/branches/javahl-ra/build.conf Sun Dec 23 06:03:14 2012
@@ -770,6 +770,14 @@ sources = hashdump-test.c
 install = test
 libs = libsvn_test libsvn_subr apriconv apr
 
+[io-test]
+description = Test I/O Operations
+type = exe
+path = subversion/tests/libsvn_subr
+sources = io-test.c
+install = test
+libs = libsvn_test libsvn_subr apriconv apr
+
 [opt-test]
 description = Test options library
 type = exe
@@ -1153,7 +1161,7 @@ libs = __ALL__
        opt-test path-test stream-test string-test time-test utf-test
        target-test error-test cache-test spillbuf-test crypto-test
        named_atomic-test named_atomic-proc-test revision-test
-       subst_translate-test
+       subst_translate-test io-test
        translate-test
        random-test window-test
        diff-diff3-test

Modified: subversion/branches/javahl-ra/build/generator/templates/svn_config.vcxproj.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/build/generator/templates/svn_config.vcxproj.ezt?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/build/generator/templates/svn_config.vcxproj.ezt (original)
+++ subversion/branches/javahl-ra/build/generator/templates/svn_config.vcxproj.ezt Sun Dec 23 06:03:14 2012
@@ -26,6 +26,7 @@
     </ProjectConfiguration>
 [end][end]  </ItemGroup>
   <PropertyGroup Label="Globals">
+    <ProjectName>svn_config</ProjectName>
     <ProjectGuid>[project_guid]</ProjectGuid>
     <Keyword>MakeFileProj</Keyword>
   </PropertyGroup>
@@ -34,6 +35,7 @@
     <ConfigurationType>Utility</ConfigurationType>
     <UseDebugLibraries>[is configs "Debug"]true[else]false[end]</UseDebugLibraries>
     <PlatformToolset>[toolset_version]</PlatformToolset>
+    <CLRSupport>false</CLRSupport>
   </PropertyGroup>
 [end][end]  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -67,6 +69,9 @@
 [end][end]
     </CustomBuild>
 [end]  </ItemGroup>
+  <ItemGroup>
+[for sql][for sql.dependencies]    <None Include="$(SolutionDir)\[sql.dependencies]" />
+[end][end]  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

Modified: subversion/branches/javahl-ra/configure.ac
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/configure.ac?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/configure.ac (original)
+++ subversion/branches/javahl-ra/configure.ac Sun Dec 23 06:03:14 2012
@@ -1192,7 +1192,8 @@ SVN_CHECK_CTYPESGEN
 dnl decide whether we want to link against the RA/FS libraries
 AC_ARG_ENABLE(runtime-module-search,
 AS_HELP_STRING([--enable-runtime-module-search],
-               [Turn on dynamic loading of RA/FS libraries]),
+               [Turn on dynamic loading of RA/FS libraries including
+                third-party FS libraries]),
 [
     if test "$enableval" = "yes"; then
       use_dso=yes

Modified: subversion/branches/javahl-ra/get-deps.sh
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/get-deps.sh?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/get-deps.sh (original)
+++ subversion/branches/javahl-ra/get-deps.sh Sun Dec 23 06:03:14 2012
@@ -48,7 +48,7 @@ APACHE_MIRROR=http://archive.apache.org/
 # helpers
 usage() {
     echo "Usage: $0"
-    echo "Usage: $0 [ apr | neon | serf | zlib | sqlite ] ..."
+    echo "Usage: $0 [ apr | serf | zlib | sqlite ] ..."
     exit $1
 }
 

Modified: subversion/branches/javahl-ra/notes/authz_policy.txt
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/notes/authz_policy.txt?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/notes/authz_policy.txt (original)
+++ subversion/branches/javahl-ra/notes/authz_policy.txt Sun Dec 23 06:03:14 2012
@@ -111,6 +111,21 @@ WHAT USERS SHOULD EXPECT FROM PATH-BASED
    This situation is quite annoying for people who can't read all the
    changed-paths.
 
+   Notice that for the purposes of gating read and write access to
+   revision properties, Subversion never considers the user's *write*
+   access to the changed-paths.  To understand the reason behind this,
+   it helps to understand why revprop access is gated at all.
+   Subversion assumes that revprops for a given revision -- especially
+   the log message (svn:log) property -- are likely to reveal paths
+   modified in that revision.  It is precisely because Subversion
+   tries not to reveal unreadable paths to users that revprop access
+   is limited as described above.  So as long as the user has the
+   requisite read access to the changed-paths, it's okay if he or she
+   lacks write access to one or more of those paths when attempting to
+   set or change revprops -- the information Subversion is trying to
+   protect through its revprop access control is considered safe to
+   reveal to that user.
+
 
 6. KNOWN LEAKAGE OF UNREADABLE PATHS
 

Modified: subversion/branches/javahl-ra/notes/directory-index/dirindex.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/notes/directory-index/dirindex.py?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/notes/directory-index/dirindex.py (original)
+++ subversion/branches/javahl-ra/notes/directory-index/dirindex.py Sun Dec 23 06:03:14 2012
@@ -15,44 +15,49 @@
 # specific language governing permissions and limitations
 # under the License.
 
+from __future__ import division, with_statement
 
-import collections
 import datetime
 import logging
+import re
 import sqlite3
+import unicodedata
 
 
 class Error(Exception):
     def __init__(self, msg, *args, **kwargs):
-        opcode = kwargs.pop("action", None)
-        if opcode is not None:
-            msg = Dirent._opname(opcode) + msg
+        action = kwargs.pop("action", None)
+        if action is not None:
+            msg = "%s %s" % (NodeRev._opname(action), msg)
         super(Error, self).__init__(msg, *args, **kwargs)
 
 
-class SQL(object):
+class SQLclass(object):
     """Named index of SQL schema definitions and statements.
 
     Parses "schema.sql" and creates a class-level attribute for each
     script and statement in that file.
     """
 
-    @classmethod
-    def _load_statements(cls):
+    def __init__(self):
         import cStringIO
         import pkgutil
         import re
 
         comment_rx = re.compile(r"\s*--.*$")
-        header_rx = re.compile(r"^---(STATEMENT|SCRIPT)"
+        header_rx = re.compile(r"^---(?P<kind>STATEMENT|SCRIPT)"
                                r"\s+(?P<name>[_A-Z]+)$")
 
+        kind = None
         name = None
         content = None
 
         def record_current_statement():
             if name is not None:
-                setattr(cls, name, content.getvalue())
+                if kind == "SCRIPT":
+                    self.__record_script(name, content.getvalue())
+                else:
+                    self.__record_statement(name, content.getvalue())
 
         schema = cStringIO.StringIO(pkgutil.get_data(__name__, "schema.sql"))
         for line in schema:
@@ -63,6 +68,7 @@ class SQL(object):
             header = header_rx.match(line)
             if header:
                 record_current_statement()
+                kind = header.group("kind")
                 name = header.group("name")
                 content = cStringIO.StringIO()
                 continue
@@ -75,159 +81,554 @@ class SQL(object):
                 content.write(line)
                 content.write("\n")
         record_current_statement()
-SQL._load_statements()
 
+    class __statement(object):
+        __slots__ = ("execute", "query")
+        def __init__(self, sql, query):
+            self.execute = sql._execute
+            self.query = query
+
+        def __call__(self, cursor, **kwargs):
+            if len(kwargs):
+                return self.execute(cursor, self.query, kwargs)
+            return self.execute(cursor, self.query)
+
+    def __record_statement(self, name, statement):
+        setattr(self, name, self.__statement(self, statement))
+
+    class __script(object):
+        __slots__ = ("execute", "query")
+        def __init__(self, sql, query):
+            self.execute = sql._executescript
+            self.query = query
+
+        def __call__(self, cursor):
+            return self.execute(cursor, self.query)
+
+    def __record_script(self, name, script):
+        setattr(self, name, self.__script(self, script))
+
+    LOGLEVEL = (logging.NOTSET + logging.DEBUG) // 2
+    if logging.getLevelName(LOGLEVEL) == 'Level %s' % LOGLEVEL:
+        logging.addLevelName(LOGLEVEL, 'SQL')
+
+    def _log(self, *args, **kwargs):
+        return logging.log(self.LOGLEVEL, *args, **kwargs)
 
-class SQLobject(object):
+    __stmt_param_rx = re.compile(r':([a-z]+)')
+    def _execute(self, cursor, statement, parameters=None):
+        if parameters is not None:
+            fmt = statement.replace("%", "%%")
+            fmt = self.__stmt_param_rx.sub(r'%(\1)r', fmt)
+            self._log("EXECUTE: " + fmt, parameters)
+            return cursor.execute(statement, parameters)
+        else:
+            self._log("EXECUTE: %s", statement)
+            return cursor.execute(statement)
+
+    def _executescript(self, cursor, script):
+        self._log("EXECUTE: %s", script)
+        return cursor.executescript(script)
+SQL = SQLclass()
+
+
+class SQLobject(dict):
     """Base for ORM abstractions."""
 
-    __slots__ = ()
     def __init__(self, **kwargs):
-        for name, val in kwargs.items():
-            setattr(self, name, val)
-        for name in self.__slots__:
-            if not hasattr(self, name):
-                setattr(self, name, None)
-
-    def _put(self, cursor):
-        raise NotImplementedError("SQLobject._insert")
+        super(SQLobject, self).__init__(**kwargs)
+        for name in self._columns:
+            super(SQLobject, self).setdefault(name, None)
+
+    def __getattr__(self, name):
+        return self.__getitem__(name)
+
+    def __setattr__(self, name, value):
+        return self.__setitem__(name, value)
+
+    def __delattr__(self, name):
+        return self.__delitem__(name)
+
+    def _put(self, _cursor):
+        self._put_statement(_cursor, **self)
+        if self.id is None:
+            self.id = _cursor.lastrowid
+        else:
+            assert self.id == _cursor.lastrowid
 
     @classmethod
-    def _get(self, cursor, pkey):
-        raise NotImplementedError("SQLobject._insert")
+    def _get(self, _cursor, pkey):
+        self._get_statement(_cursor, id=pkey)
+        return cls._from_row(_cursor.fetchone())
 
     @classmethod
     def _from_row(cls, row):
         if row is not None:
-            return cls(**dict((col, row[col]) for col in row.keys()))
+            return cls(**row)
         return None
 
-    LOGLEVEL = (logging.NOTSET + logging.DEBUG) // 2
-    if logging.getLevelName(LOGLEVEL) == 'Level %s' % LOGLEVEL:
-        logging.addLevelName(LOGLEVEL, 'SQL')
+    def _clone(self):
+        return self.__class__(**self)
 
-    @classmethod
-    def _log(cls, *args, **kwargs):
-        return logging.log(cls.LOGLEVEL, *args, **kwargs)
 
-    @classmethod
-    def _execute(cls, cursor, statement, parameters=None):
-        if parameters is not None:
-            fmt = statement.replace("%", "%%").replace("?", "%r")
-            cls._log("EXECUTE: " + fmt, *parameters)
-            return cursor.execute(statement, parameters)
-        else:
-            cls._log("EXECUTE: %s", statement)
-            return cursor.execute(statement)
+class Txn(SQLobject):
+    """O/R mapping for the "txn" table."""
 
+    _columns = ("id", "treeid", "revision", "created", "author", "state")
+    _put_statement = SQL.TXN_INSERT
+    _get_statement = SQL.TXN_GET
 
-class Revent(SQLobject):
-    """O/R mapping for the "revision" table."""
+    # state
+    TRANSIENT = "T"
+    PERMANENT = "P"
+    DEAD = "D"
 
-    __slots__ = ("version", "created", "author", "log")
+    def __init__(self, **kwargs):
+        super(Txn, self).__init__(**kwargs)
+        if self.state is None:
+            self.state = self.TRANSIENT
+
+    def __str__(self):
+        return "%d/%d %c %s" % (self.revision, self.treeid,
+                                self.state, self.created)
+
+    @property
+    def _committed(self):
+        return self.state == self.PERMANENT
+
+    @property
+    def _uncommitted(self):
+        return self.state == self.TRANSIENT
+
+    @property
+    def _dead(self):
+        return self.state == self.DEAD
+
+    @staticmethod
+    def _now():
+        now = datetime.datetime.utcnow()
+        return (now.strftime("%Y%m%dT%H%M%S.%%03dZ")
+                % ((now.microsecond + 500) // 1000))
 
     def _put(self, cursor):
         if self.created is None:
-            now = datetime.datetime.utcnow()
-            self.created = now.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
-        self._execute(cursor, SQL.INSERT_REVISION_RECORD,
-                      [self.version, self.created, self.author, self.log])
+            self.created = self._now()
+        super(Txn, self)._put(cursor)
+        if self.treeid is None:
+            SQL.TXN_UPDATE_INITIAL_TREEID(cursor, id = self.id)
+            self.treeid = self.id
 
     @classmethod
-    def _get(cls, cursor, pkey):
-        cursor.execute(SQL.GET_REVENT_BY_VERSION, [pkey])
+    def _find_newest(cls, cursor):
+        SQL.TXN_FIND_NEWEST(cursor)
         return cls._from_row(cursor.fetchone())
 
+    @classmethod
+    def _find_by_revision(cls, cursor, revision):
+        SQL.TXN_FIND_BY_REVISION(cursor, revision = revision)
+        return cls._from_row(cursor.fetchone())
 
-class Strent(SQLobject):
-    """O/R mapping for the "strindex" table."""
+    @classmethod
+    def _find_by_revision_timestamp(cls, cursor, revision, created):
+        SQL.TXN_FIND_BY_REVISION_AND_TIMESTAMP(
+            cursor, revision = revision, created = creted)
+        return cls._from_row(cursor.fetchone())
 
-    __slots__ = ("strid", "content")
+    def _commit(self, cursor, revision):
+        assert self._uncommitted
+        now = self._now()
+        SQL.TXN_COMMIT(cursor, id = self.id,
+                       revision = revision, created = now)
+        self.revision = revision
+        self.created = now
+        self.state = self.PERMANENT
+
+    def _abort(self, cursor):
+        assert self._uncommitted
+        SQL.TXN_ABORT(cursor, id = self.id)
+        self.state = self.DEAD
+
+    def _cleanup(self, cursor):
+        assert self._dead
+        SQL.TXN_CLEANUP(cursor, id = self.id)
+
+
+class Branch(SQLobject):
+    """O/R mapping for the "branch" table."""
+
+    _columns = ("id", "treeid", "nodeid", "origin", "state")
+    _put_statement = SQL.BRANCH_INSERT
+    _get_statement = SQL.BRANCH_GET
+
+    # state
+    TRANSIENT = "T"
+    PERMANENT = "P"
+
+    def __init__(self, **kwargs):
+        super(Branch, self).__init__(**kwargs)
+        if self.state is None:
+            self.state = self.TRANSIENT
 
     def _put(self, cursor):
-        self._execute(cursor, SQL.INSERT_STRINDEX_RECORD, [self.content])
-        self.strid = cursor.lastrowid
+        super(Branch, self)._put(cursor)
+        if self.nodeid is None:
+            SQL.BRANCH_UPDATE_INITIAL_NODEID(cursor, id = self.id)
+            self.nodeid = self.id
 
     @classmethod
-    def _get(cls, cursor, pkey):
-        cls._execute(cursor, SQL.GET_STRENT_BY_STRID, [pkey])
-        return cls._from_row(cursor.fetchone())
+    def _update_treeid(cls, cursor, new_txn, old_txn):
+        SQL.BRANCH_UPDATE_TREEID(cursor,
+                                 new_treeid = new_txn.treeid,
+                                 old_treeid = old_txn.treeid)
 
     @classmethod
-    def _find(cls, cursor, content):
-        cls._execute(cursor, SQL.GET_STRENT_BY_CONTENT, [content])
-        return cls._from_row(cursor.fetchone())
+    def _history(cls, cursor, nodeid):
+        SQL.BRANCH_HISTORY(cursor, nodeid = nodeid)
+        for row in cursor:
+            yield cls._from_row(row)
+
+    @classmethod
+    def _commit(cls, cursor, txn):
+        SQL.BRANCH_COMMIT(cursor, treeid = txn.treeid)
+
+    @classmethod
+    def _cleanup(cls, cursor, txn):
+        SQL.BRANCH_CLEANUP(cursor, treeid = txn.treeid)
 
 
-class Dirent(SQLobject):
-    """O/R mapping for a virtual non-materialized view representing
-    a join of the "dirindex" and "strindex" tables."""
-
-    __slots__ = ("rowid", "origin", "pathid", "version",
-                 "kind", "opcode", "subtree",
-                 "abspath")
+class NodeRev(SQLobject):
+    """O/R mapping for the noderev/string/nodeview table."""
 
-    # Kinds
+    _columns = ("id", "treeid", "nodeid", "origin", "parent", "branch",
+                "nameid", "name", "denameid", "dename",
+                "kind", "opcode", "state")
+    _put_statement = SQL.NODEREV_INSERT
+    _get_statement = SQL.NODEVIEW_GET
+
+    # kind
     DIR = "D"
     FILE = "F"
 
-    # Opcodes
+    # opcode
     ADD = "A"
     REPLACE = "R"
     MODIFY = "M"
     DELETE = "D"
     RENAME = "N"
+    BRANCH = "B"
+    LAZY = "L"
+    BREPLACE = "X"
+    LAZY_BREPLACE = "Z"
+
+    # state
+    TRANSIENT = "T"
+    PERMANENT = "P"
+
+    def __init__(self, **kwargs):
+        super(NodeRev, self).__init__(**kwargs)
+        if self.state is None:
+            self.state = self.TRANSIENT
+
+    def __str__(self):
+        return "%d %c %s%s" % (self.treeid, self.opcode, self.name,
+                               self._isdir and '/' or '')
 
     # Opcode names
     __opnames = {ADD: "add",
                  REPLACE: "replace",
                  MODIFY: "modify",
                  DELETE: "delete",
-                 RENAME: "rename"}
+                 RENAME: "rename",
+                 BRANCH: "branch",
+                 LAZY: "branch",
+                 BREPLACE: "branch/replace",
+                 LAZY_BREPLACE: "branch/replace"}
 
     @classmethod
-    def _opname(cls, opcode):
+    def _opname(cls, change):
         return cls.__opnames.get(opcode)
 
     @property
     def _deleted(self):
         return (self.opcode == self.DELETE)
 
-    def __str__(self):
-        return "%d %c%c%c %c %s" % (
-            self.version,
-            self.subtree and "(" or " ",
-            self.opcode,
-            self.subtree and ")" or " ",
-            self.kind, self.abspath)
+    @property
+    def _lazy(self):
+        return (self.opcode in (self.LAZY, self.LAZY_BREPLACE))
+
+    @property
+    def _transient(self):
+        return (self.state == self.TRANSIENT)
+
+    @property
+    def _isdir(self):
+        return (self.kind == self.DIR)
+
+    @staticmethod
+    def __stringid(cursor, val):
+        SQL.STRING_FIND(cursor, val = val)
+        row = cursor.fetchone()
+        if row is not None:
+            return row['id']
+        SQL.STRING_INSERT(cursor, val = val)
+        return cursor.lastrowid
 
     def _put(self, cursor):
-        strent = Strent._find(cursor, self.abspath)
-        if strent is None:
-            strent = Strent(content = self.abspath)
-            strent._put(cursor)
-        self._execute(cursor, SQL.INSERT_DIRINDEX_RECORD,
-                      [self.origin, strent.strid, self.version,
-                       self.kind, self.opcode,self.subtree])
-        self.rowid = cursor.lastrowid
-        self.pathid = strent.strid
+        if self.nameid is None:
+            assert self.name is not None
+            self.nameid = self.__stringid(cursor, self.name)
+        if self.denameid is None:
+            if self.dename == self.name:
+                self.denameid = self.nameid
+            else:
+                assert self.dename is not None
+                self.denameid = self.__stringid(cursor, self.dename)
+        super(NodeRev, self)._put(cursor)
 
     @classmethod
-    def _get(cls, cursor, pkey):
-        cls._execute(cursor, SQL.GET_DIRENT_BY_ROWID, [pkey])
-        return cls._from_row(cursor.fetchone())
+    def _update_treeid(cls, cursor, new_txn, old_txn):
+        SQL.NODEREV_UPDATE_TREEID(cursor,
+                                  new_treeid = new_txn.treeid,
+                                  old_treeid = old_txn.treeid)
+
+    def _delazify(self, cursor):
+        assert self._lazy and self._isdir
+        opcode = self.opcode == self.LAZY and self.BRANCH or self.BREPLACE
+        SQL.NODEREV_UPDATE_OPCODE(cursor, id = self.id, opcode = opcode)
+        self.opcode = opcode
+
+    @classmethod
+    def _commit(cls, cursor, txn):
+        SQL.NODEREV_COMMIT(cursor, treeid = txn.treeid)
 
     @classmethod
-    def _find(cls, cursor, abspath, version):
-        cls._execute(cursor,
-                     SQL.GET_DIRENT_BY_ABSPATH_AND_VERSION,
-                     [abspath, version])
+    def _cleanup(cls, cursor, txn):
+        SQL.NODEREV_CLEANUP(cursor, treeid = txn.treeid)
+
+    @classmethod
+    def __find(cls, cursor, parent, name, txn):
+        if txn.state != txn.PERMANENT:
+            if parent is None:
+                finder = SQL.NODEVIEW_FIND_TRANSIENT_ROOT
+            else:
+                finder = SQL.NODEVIEW_FIND_TRANSIENT_BY_NAME
+        else:
+            if parent is None:
+                finder = SQL.NODEVIEW_FIND_ROOT
+            else:
+                finder = SQL.NODEVIEW_FIND_BY_NAME
+        finder(cursor, name = name, parent = parent, treeid = txn.treeid)
         return cls._from_row(cursor.fetchone())
 
+    @classmethod
+    def _find(cls, cursor, parent, name, txn):
+        return cls.__find(cursor, parent, cls.__normtext(name), txn)
+
+    @classmethod
+    def _commonprefix(cls, *args):
+        args = [arg.split('/') for arg in args]
+        prefix = []
+        arglen = min(len(parts) for parts in args)
+        while arglen > 0:
+            same = set(cls.__normtext(parts[0]) for parts in args)
+            if len(same) > 1:
+                break
+            for parts in args:
+                del parts[0]
+            prefix.append(same.pop())
+            arglen -= 1
+        return '/'.join(prefix), ['/'.join(parts) for parts in args]
+
+    @classmethod
+    def _lookup(cls, cursor, track, relpath, txn):
+        if track is None or track.path is None:
+            # Lookup from root
+            track = Track()
+            parent = cls.__find(cursor, None, "", txn)
+            if not relpath:
+                track.close(parent)
+                return track
+            track.append(parent)
+        else:
+            assert track.found
+            track = Track(track)
+            if not relpath:
+                track.close()
+                return track
+            parent = track.noderev
+        parts = cls.__normtext(relpath).split("/")
+        for name in parts[:-1]:
+            if not parent._isdir:
+                raise Error("ENOTDIR: " + track.path)
+            while parent._lazy:
+                parent = cls._get(cursor, id = parent.origin)
+            node = cls.__find(cursor, parent.branch, name, txn)
+            if node is None:
+                raise Error("ENODIR: " +  track.path + '/' + name)
+            parent = node
+            track.append(parent)
+        while parent._lazy:
+            parent = cls._get(cursor, id = parent.origin)
+        track.close(cls.__find(cursor, parent.branch, parts[-1], txn))
+        return track
+
+    def _count_successors(self, cursor):
+        SQL.NODEREV_COUNT_SUCCESSORS(cursor, origin = self.id)
+        return int(cursor.fetchone()[0])
+
+    def _listdir(self, cursor, txn):
+        assert self._isdir
+        if txn.state != txn.PERMANENT:
+            lister = SQL.NODEVIEW_LIST_TRANSIENT_DIRECTORY
+        else:
+            lister = SQL.NODEVIEW_LIST_DIRECTORY
+        lister(cursor, parent = self.id, treeid = txn.treeid)
+        for row in cursor:
+            yield self._from_row(row)
+
+    def _bubbledown(self, cursor, txn):
+        assert txn._uncommitted
+        assert self._lazy and self._isdir and self.origin is not None
+        originmap = dict()
+        origin = self
+        while origin._lazy:
+            origin = self._get(cursor, id = origin.origin)
+        for node in origin._listdir(cursor, txn):
+            newnode = node._branch(cursor, self, txn)
+            originmap[newnode.origin] == newnode
+        self._delazify(cursor)
+        return originmap
+
+    def _branch(self, cursor, parent, txn, replaced=False):
+        assert txn._uncommitted
+        branch = Branch(treeid = txn.treeid,
+                        nodeid = self.nodeid,
+                        origin = self.branch)
+        branch._put(cursor)
+        if self._isdir:
+            opcode = replaced and self.LAZY_BREPLACE or self.LAZY
+        else:
+            opcode = replaced and self.BREPLACE or self.BRANCH
+        node = self._revise(opcode, txn)
+        node.parent = parent.id
+        node.branch = branch.id
+        node._put(cursor)
+        return node
+
+    def _revise(self, opcode, txn):
+        assert txn._uncommitted
+        noderev = NodeRev._clone(self)
+        noderev.treeid = txn.treeid
+        noderev.opcode = opcode
+
+    __readonly = frozenset(("name",))
+    def __setitem__(self, key, value):
+        if key in self.__readonly:
+            raise Error("NodeRev.%s is read-only" % key)
+        if key == "dename":
+            name = self.__normtext(value)
+            value = self.__text(value)
+            super(NodeRev, self).__setitem__("name", name)
+        super(NodeRev, self).__setitem__(key, value)
+
+    def __getitem__(self, key):
+        if key == "dename":
+            dename = super(NodeRev, self).__getitem__(key)
+            if dename is not None:
+                return dename
+            key = "name"
+        return super(NodeRev, self).__getitem__(key)
+
+    @classmethod
+    def __text(cls, name):
+        if not isinstance(name, unicode):
+            return name.decode("UTF-8")
+        return name
+
+    @classmethod
+    def __normtext(cls, name):
+        return unicodedata.normalize('NFC', cls.__text(name))
+
+
+class Track(object):
+    __slots__ = ("nodelist", "noderev", "lazy")
+    def __init__(self, other=None):
+        if other is None:
+            self.nodelist = list()
+            self.noderev = None
+            self.lazy = None
+        else:
+            self.nodelist = list(other.nodelist)
+            self.noderev = other.noderev
+            self.lazy = other.lazy
+
+    def __str__(self):
+        return "%c%c %r" % (
+            self.found and self.noderev.kind or '-',
+            self.lazy is not None and 'L' or '-',
+            self.path)
+
+    @property
+    def found(self):
+        return (self.noderev is not None)
+
+    @property
+    def parent(self):
+        if self.noderev is not None:
+            index = len(self.nodelist) - 2;
+        else:
+            index = len(self.nodelist) - 1;
+        if index >= 0:
+            return self.nodelist[index]
+        return None
+
+    @property
+    def path(self):
+        if len(self.nodelist):
+            return '/'.join(n.name for n in self.nodelist[1:])
+        return None
+
+    @property
+    def open(self):
+        return not isinstance(self.nodelust, tuple)
+
+    def append(self, noderev):
+        if self.lazy is None and noderev._lazy:
+            self.lazy = len(self.nodelist)
+        self.nodelist.append(noderev)
+
+    def close(self, noderev=None):
+        if noderev is not None:
+            self.append(noderev)
+            self.noderev = noderev
+        self.nodelist = tuple(self.nodelist)
+
+    def bubbledown(self, cursor, txn):
+        if self.lazy is None:
+            return
+        closed = not self.open
+        if closed:
+            self.nodelist = list(self.nodelist)
+        tracklen = len(self.nodelist)
+        index = self.lazy
+        node = self.nodelist[index]
+        originmap = node._bubbledown(cursor, txn)
+        while index < tracklen:
+            node = originmap[self.nodelist[index].id]
+            self.nodelist[index] = node
+            if node._isdir:
+                originmap = node._bubbledown(cursor, txn)
+            else:
+                originmap = None
+            index += 1
+        self.lazy = None
+        if closed:
+            self.close()
+
 
 class Index(object):
     def __init__(self, database):
-        self.conn = sqlite3.connect(database, isolation_level = "IMMEDIATE")
+        self.conn = sqlite3.connect(database, isolation_level = "DEFERRED")
         self.conn.row_factory = sqlite3.Row
         self.cursor = self.conn.cursor()
         self.cursor.execute("PRAGMA page_size = 4096")
@@ -236,337 +637,194 @@ class Index(object):
         self.cursor.execute("PRAGMA case_sensitive_like = ON")
         self.cursor.execute("PRAGMA encoding = 'UTF-8'")
 
-    @staticmethod
-    def normpath(abspath):
-        return abspath.rstrip("/")
-
-    @staticmethod
-    def subtree_pattern(abspath):
-        return (abspath.rstrip("/")
-                .replace("#", "##")
-                .replace("%", "#%")
-                .replace("_", "#_")) + "/%"
-
     def initialize(self):
         try:
-            SQLobject._log("%s", SQL.CREATE_SCHEMA)
-            self.cursor.executescript(SQL.CREATE_SCHEMA)
+            SQL.CREATE_SCHEMA(self.cursor)
+            SQL._execute(
+                self.cursor,
+                "UPDATE txn SET created = :created WHERE id = 0",
+                {"created": Txn._now()})
             self.commit()
-        finally:
+        except:
             self.rollback()
+            raise
+
+    def begin(self):
+        SQL._execute(self.cursor, "BEGIN")
 
     def commit(self):
-        SQLobject._log("COMMIT")
-        return self.conn.commit()
+        SQL._log("COMMIT")
+        self.conn.commit()
 
     def rollback(self):
-        SQLobject._log("ROLLBACK")
-        return self.conn.rollback()
+        SQL._log("ROLLBACK")
+        self.conn.rollback()
 
     def close(self):
         self.rollback()
-        SQLobject._log("CLOSE")
-        return self.conn.close()
+        SQL._log("CLOSE")
+        self.conn.close()
 
-    def get_revision(self, version):
-        return Revent._get(self.cursor, version)
+    def get_txn(self, revision=None):
+        if revision is None:
+            return Txn._find_newest(self.cursor)
+        return Txn._find_by_revision(self.cursor, revision)
+
+    def new_txn(self, revision, created=None, author=None, base_txn = None):
+        assert base_txn is None or base_txn.revision == revision
+        txn = Txn(revision = revision, created = created, author = author,
+                  treeid = base_txn is not None and base_txn.treeid or None)
+        txn._put(self.cursor)
+        return txn
+
+    def commit_txn(self, txn, revision):
+        txn._commit(self.cursor, revision)
+        NodeRev._commit(self.cursor, txn)
+        Branch._commit(self.cursor, txn)
+
+    def abort_txn(self, txn):
+        txn._abort(self.cursor)
+        NodeRev._cleanup(self.cursor, txn)
+        Branch._cleanup(self.cursor, txn)
+        txn._cleanup(self.cursor)
+
+    def listdir(self, txn, noderev):
+        # FIXME: Query seems OK but no results returned?
+        return noderev._listdir(self.conn.cursor(), txn)
+
+    def lookup(self, txn, track=None, relpath=""):
+        return NodeRev._lookup(self.cursor, track, relpath, txn)
+
+    def __add(self, txn, track, name, kind, opcode, origintrack=None):
+        assert kind in (NodeRev.FILE, NodeRev.DIR)
+        assert opcode in (NodeRev.ADD, NodeRev.REPLACE)
+        if not txn._uncommitted:
+            raise Error("EREADONLY: txn " + str(txn))
+        if not track.found:
+            raise Error("ENOENT: " +  track.path)
+        if not track.noderev._isdir:
+            raise Error("ENOTDIR: " +  track.path)
+
+        parent = track.noderev
+        oldnode = NodeRev._find(self.cursor, parent.id, name, txn)
+        if opcode == NodeRev.ADD and oldnode is not None:
+            raise Error("EEXIST: " +  track.path + '/' + name)
+
+        if origintrack is not None:
+            # Treat add as copy
+            if not origintrack.found:
+                raise Error("ENOENT: (origin) " +  origintrack.path)
+            origin = origintrack.noderev
+            if origin.kind != kind:
+                raise Error("ENOTSAME: origin %c -> copy %c"
+                            % (origin.kind, kind))
+            ### Rename detection heuristics here ...
+            rename = False
+        else:
+            origin = None
+            rename = False
 
-    def new_revision(self, version, created=None, author=None, log=None):
-        revent = Revent(version = version,
-                        created = created,
-                        author = author,
-                        log = log)
-        revent._put(self.cursor)
-        return revent
-
-    def insert(self, dirent):
-        assert isinstance(dirent, Dirent)
-        dirent._put(self.cursor)
-        return dirent
-
-    def lookup(self, abspath, version):
-        SQLobject._execute(
-            self.cursor,
-            SQL.LOOKUP_ABSPATH_AT_REVISION,
-            [abspath, version])
-        row = self.cursor.fetchone()
-        if row is not None:
-            dirent = Dirent._from_row(row)
-            if not dirent._deleted:
-                return dirent
-        return None
+        if rename:
+            raise NotImplementedError("Rename detection heuristics")
 
-    def subtree(self, abspath, version):
-        SQLobject._execute(
-            self.cursor,
-            SQL.LIST_SUBTREE_AT_REVISION,
-            [version, self.subtree_pattern(abspath)])
-        for row in self.cursor:
-            yield Dirent._from_row(row)
-
-    def predecessor(self, dirent):
-        assert isinstance(dirent, Dirent)
-        if dirent.origin is None:
-            return None
-        return Dirent._get(self.cursor, dirent.origin)
-
-    def successors(self, dirent):
-        assert isinstance(dirent, Dirent)
-        SQLobject._execute(
-            self.cursor,
-            SQL.LIST_DIRENT_SUCCESSORS,
-            [dirent.rowid])
-        for row in self.cursor:
-            yield Dirent._from_row(row)
-
-
-class Revision(object):
-    def __init__(self, index, version,
-                 created=None, author=None, log=None):
-        self.index = index
-        self.version = version
-        self.revent = index.get_revision(version)
-        self.__created = created
-        self.__author = author
-        self.__log = log
-        self.__context = None
-        index.rollback()
+        track = Track(track)
+        track.bubbledown(self.cursor, txn)
+        if oldnode:
+            if parent.id != track.noderev.id:
+                # Bubbledown changed the track
+                parent = track.noderev
+                oldnode = NodeRev._find(self.cursor, parent.id, name, txn)
+                assert oldnode is not None
+            tombstone = oldnode._revise(oldnode.DELETE, txn)
+            tombstone.parent = parent.id
+            tombstone._put(self.cursor)
+        parent = track.noderev
+        if origin is not None:
+            newnode = origin._branch(self.cursor, parent.id, txn,
+                                     replaced = (oldnode is not None))
+        else:
+            branch = Branch(treeid = txn.treeid)
+            branch._put(self.cursor)
+            newnode = NodeRev(treeid = txn.treeid,
+                              nodeid = branch.nodeid,
+                              branch = branch.id,
+                              parent = parent.id,
+                              kind = kind,
+                              opcode = opcode)
+            newnode.dename = name
+            newnode._put(self.cursor)
+        track.close(newnode)
+        return track
+
+    def add(self, txn, track, name, kind, origintrack=None):
+        return self.__add(txn, track, name, kind, NodeRev.ADD, origintrack)
+
+    def replace(self, txn, track, name, kind, origintrack=None):
+        return self.__add(txn, track, name, kind, NodeRev.REPLACE, origintrack)
+
+#    def modify(self, txn, track):
+#        if not txn._uncommitted
+#            raise Error("EREADONLY: txn " + str(txn))
+#        if not track.found:
+#            raise Error("ENOENT: " +  track.path)
 
-    class __Context(object):
-        def __init__(self, version, connection):
-            self.version = version
-            self.conn = connection
-            self.cursor = connection.cursor()
-            SQLobject._execute(self.cursor, SQL.CREATE_TRANSACTION_CONTEXT)
-
-        def clear(self):
-            SQLobject._execute(self.cursor, SQL.REMOVE_TRANSACTION_CONTEXT)
-
-        def __iter__(self):
-            SQLobject._execute(self.cursor, SQL.LIST_TRANSACTION_RECORDS)
-            for row in self.cursor:
-                dirent = Dirent._from_row(row)
-                dirent.version = self.version
-                yield dirent
-
-        def lookup(self, abspath):
-            SQLobject._execute(self.cursor,
-                               SQL.GET_TRANSACTION_RECORD,
-                               [abspath])
-            row = self.cursor.fetchone()
-            if row is not None:
-                dirent = Dirent._from_row(row)
-                dirent.version = self.version
-                return dirent
-            return None
-
-        def remove(self, abspath, purge=False):
-            target = self.lookup(abspath)
-            if not target:
-                raise Error("txn context: remove nonexistent " + abspath)
-            logging.debug("txn context: remove %s", abspath)
-            SQLobject._execute(self.cursor,
-                               SQL.REMOVE_TRANSACTION_RECORD,
-                               [abspath])
-            if purge:
-                logging.debug("txn context: purge %s/*", abspath)
-                SQLobject._execute(self.cursor,
-                                   SQL.REMOVE_TRANSACTION_SUBTREE,
-                                   [Index.subtree_pattern(abspath)])
-
-        def record(self, dirent, replace=False, purge=False):
-            target = self.lookup(dirent.abspath)
-            if target is not None:
-                if not replace:
-                    raise Error("txn context: record existing "
-                                + dirent.abspath)
-                elif not target.subtree:
-                    raise Error("txn context: replace conflict "
-                                + dirent.abspath)
-                self.remove(target.abspath, purge and target.kind == Dirent.DIR)
-            SQLobject._execute(self.cursor,
-                               SQL.INSERT_TRANSACTION_RECORD,
-                               [dirent.origin, dirent.abspath,
-                                dirent.kind, dirent.opcode, dirent.subtree])
-
-    def __enter__(self):
-        if self.revent is not None:
-            raise Error("revision is read-only")
-        self.__context = self.__Context(self.version, self.index.conn)
-        SQLobject._execute(self.index.cursor, "BEGIN")
-        self.revent = self.index.new_revision(
-            self.version, self.__created, self.__author, self.__log)
-        return self
 
-    def __exit__(self, exc_type, exc_value, traceback):
-        try:
-            if exc_type is None:
-                for dirent in self.__context:
-                    self.index.insert(dirent)
-                    logging.debug("insert: %s", dirent)
-                self.index.commit()
-            else:
-                self.index.rollback()
-        except:
-            self.index.rollback()
-            raise
-        finally:
-            self.__context.clear()
-            self.__context = None
-
-    def __record(self, dirent, replace=False, purge=False):
-        self.__context.record(dirent, replace, purge)
-        logging.debug("record: %s", dirent)
-
-    def __check_writable(self, opcode):
-        if self.__context is None:
-            raise Error(" requires a transaction", action=opcode)
-
-    def __check_not_root(self, abspath, opcode):
-        if abspath.rstrip("/") == "":
-            raise Error(" not allowed on /", action=opcode)
-
-    def __find_target(self, abspath, opcode):
-        target = self.__context.lookup(abspath)
-        if target is not None:
-            if not target.subtree:
-                raise Error(" overrides explicit " + abspath, action=opcode)
-            return target, target.origin
-        target = self.index.lookup(abspath, self.version - 1)
-        if target is None:
-            raise Error(" target does not exist: " + abspath, action=opcode)
-        return target, target.rowid
 
-    def lookup(self, abspath):
-        try:
-            return self.index.lookup(self.index.normpath(abspath),
-                                     self.version)
-        finally:
-            if self.__context is None:
-                self.index.rollback()
-
-    def __add(self, opcode, abspath, kind, frompath, fromver):
-        origin = None
-        if frompath is not None:
-            frompath = self.index.normpath(frompath)
-            fromver = int(fromver)
-            origin = self.index.lookup(frompath, fromver)
-            if origin is None:
-                raise Error(" source does not exist: " + frompath, action=opcode)
-            if origin.kind != kind:
-                raise Error(" changes the source object kind", action=opcode)
-            origin = origin.rowid
-        dirent = Dirent(origin = origin,
-                        abspath = abspath,
-                        version = self.version,
-                        kind = kind,
-                        opcode = opcode,
-                        subtree = 0)
-        self.__record(dirent,
-                      replace=(opcode == Dirent.REPLACE),
-                      purge=(opcode == Dirent.REPLACE))
-        if frompath is not None and dirent.kind == Dirent.DIR:
-            prefix = dirent.abspath
-            offset = len(frompath)
-            for source in list(self.index.subtree(frompath, fromver)):
-                abspath = prefix + source.abspath[offset:]
-                self.__record(Dirent(origin = source.rowid,
-                                     abspath = abspath,
-                                     version = self.version,
-                                     kind = source.kind,
-                                     opcode = opcode,
-                                     subtree = 1))
-
-    def add(self, abspath, kind, frompath=None, fromver=None):
-        opcode = Dirent.ADD
-        abspath = self.index.normpath(abspath)
-        self.__check_writable(opcode)
-        self.__check_not_root(abspath, opcode)
-        return self.__add(opcode, abspath, kind, frompath, fromver)
-
-    def replace(self, abspath, kind, frompath=None, fromver=None):
-        opcode = Dirent.REPLACE
-        abspath = self.index.normpath(abspath)
-        self.__check_writable(opcode)
-        self.__check_not_root(abspath, opcode)
-        self.__find_target(abspath, opcode)
-        return self.__add(opcode, abspath, kind, frompath, fromver)
-
-    def modify(self, abspath):
-        opcode = Dirent.MODIFY
-        abspath = self.index.normpath(abspath)
-        self.__check_writable(opcode)
-        target, origin = self.__find_target(abspath, opcode)
-        dirent = Dirent(origin = origin,
-                        abspath = abspath,
-                        version = self.version,
-                        kind = target.kind,
-                        opcode = opcode,
-                        subtree = 0)
-        self.__record(dirent, replace=True)
-
-    def delete(self, abspath):
-        opcode = Dirent.DELETE
-        abspath = self.index.normpath(abspath)
-        self.__check_writable(opcode)
-        self.__check_not_root(abspath, opcode)
-        target, origin = self.__find_target(abspath, opcode)
-        dirent = Dirent(origin = origin,
-                        abspath = abspath,
-                        version = self.version,
-                        kind = target.kind,
-                        opcode = opcode,
-                        subtree = 0)
-        self.__record(dirent, replace=True, purge=True)
-        if target.version < self.version and dirent.kind == Dirent.DIR:
-            for source in self.index.subtree(abspath, self.version - 1):
-                self.__record(Dirent(origin = source.rowid,
-                                     abspath = source.abspath,
-                                     version = self.version,
-                                     kind = source.kind,
-                                     opcode = opcode,
-                                     subtree = 1))
+class Tree(object):
+    def __init__(self, index):
+        self.index = index
+        self.context = None
+        index.rollback()
 
 
 def simpletest(database):
     ix = Index(database)
     ix.initialize()
-    with Revision(ix, 1) as rev:
-        rev.add(u'/A', Dirent.DIR)
-        rev.add(u'/A/B', Dirent.DIR)
-        rev.add(u'/A/B/c', Dirent.FILE)
-    with Revision(ix, 2) as rev:
-        rev.add(u'/A/B/d', Dirent.FILE)
-    with Revision(ix, 3) as rev:
-        rev.add(u'/X', Dirent.DIR, u'/A', 1)
-        rev.add(u'/X/B/d', Dirent.FILE, u'/A/B/d', 2)
-    with Revision(ix, 4) as rev:
-        # rev.rename(u'/X/B/d', u'/X/B/x')
-        rev.delete(u'/X/B/d')
-        rev.add(u'/X/B/x', Dirent.FILE, u'/X/B/d', 3)
-    with Revision(ix, 5) as rev:
-        rev.delete(u'/A')
-
-    for r in (0, 1, 2, 3, 4, 5):
-        print "Revision: %d" % r
-        for dirent in list(ix.subtree('/', r)):
-            origin = ix.predecessor(dirent)
-            if origin is None:
-                print "   " + str(dirent)
-            else:
-                print "   %-17s  <- %s" % (dirent, origin)
-
-    dirent = ix.lookup('/A/B/c', 4)
-    print "/A/B/c@4 -> %s@%d" % (dirent.abspath, dirent.version)
-    for succ in ix.successors(dirent):
-        print "%11s %s %s@%d" % (
-            "", succ._deleted and "x_x" or "-->",
-            succ.abspath, succ.version)
 
-    ix.close()
+    try:
+        print "Lookup root"
+        tx = ix.get_txn()
+        print "transaction:", tx
+        root = ix.lookup(tx)
+        print "root track:", root
+        print "root noderev", root.noderev
+
+        print "Add A/foo"
+        tx = ix.new_txn(0)
+        print "transaction:", tx
+        parent = ix.add(tx, root, "A", NodeRev.DIR)
+        print "A track:", parent
+        print "A noderev", parent.noderev
+
+        node = ix.add(tx, parent, "foo", NodeRev.FILE)
+        print "foo track:", node
+        print "foo noderev", node.noderev
+        ix.commit_txn(tx, 1)
+        ix.commit()
+
+        print "List contents"
+        tx = ix.get_txn()
+        print "transaction:", tx
+        root = ix.lookup(tx)
+        print str(root.noderev)
+        for n1 in ix.listdir(tx, root.noderev):
+            print " ", str(n1)
+            if n1._isdir:
+                for n2 in ix.listdir(tx, n1):
+                    print "   ", str(n2)
+
+        print "Lookup A"
+        track = ix.lookup(tx, None, "A")
+        print str(track.noderev)
+
+        print "Lookup A/foo"
+        track = ix.lookup(tx, None, "A/foo")
+        print str(track.noderev)
+    finally:
+        ix.close()
 
 def loggedsimpletest(database):
     import sys
-    logging.basicConfig(level=logging.DEBUG, #SQLobject.LOGLEVEL,
+    logging.basicConfig(level=SQL.LOGLEVEL,
                         stream=sys.stderr)
     simpletest(database)

Modified: subversion/branches/javahl-ra/notes/directory-index/schema.sql
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/notes/directory-index/schema.sql?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/notes/directory-index/schema.sql (original)
+++ subversion/branches/javahl-ra/notes/directory-index/schema.sql Sun Dec 23 06:03:14 2012
@@ -19,165 +19,305 @@
 
 ---SCRIPT CREATE_SCHEMA
 
-DROP TABLE IF EXISTS dirindex;
-DROP TABLE IF EXISTS strindex;
-DROP TABLE IF EXISTS revision;
-
--- Revision record
-
-CREATE TABLE revision (
-  version integer NOT NULL PRIMARY KEY,
-  created timestamp NOT NULL,
-  author  varchar NULL,
-  log     varchar NULL
-);
-
--- Path lookup table
-
-CREATE TABLE strindex (
-  strid   integer NOT NULL PRIMARY KEY,
-  content varchar NOT NULL UNIQUE
-);
-
--- Versioned directory tree
-
-CREATE TABLE dirindex (
-  -- unique id of this node revision, used for
-  -- predecessor/successor links
-  rowid   integer NOT NULL PRIMARY KEY,
-
-  -- link to this node's immediate predecessor
-  origin  integer NULL REFERENCES dirindex(rowid),
-
-  -- absolute (repository) path
-  pathid  integer NOT NULL REFERENCES strindex(strid),
-
-  -- revision number
-  version integer NOT NULL REFERENCES revision(version),
-
-  -- node kind (D = dir, F = file, etc.)
-  kind    character(1) NOT NULL,
+DROP VIEW IF EXISTS nodeview;
+DROP TABLE IF EXISTS noderev;
+DROP TABLE IF EXISTS string;
+DROP TABLE IF EXISTS branch;
+DROP TABLE IF EXISTS txn;
+
+
+-- Transactions
+CREATE TABLE txn (
+  -- transaction number
+  id        integer NOT NULL PRIMARY KEY,
+
+  -- the version of the tree associated with this transaction;
+  -- initially the same as id, but may refer to the originator
+  -- transaction when tracking revprop changes and/or modified trees
+  -- (q.v., obliterate)
+  treeid    integer NULL REFERENCES txn(id),
+
+  -- the revision that this transaction represents; for uncommitted
+  -- transactions, the revision in which it was created
+  revision  integer NULL,
+
+  -- creation date, independent of the svn:date property
+  created   timestamp NOT NULL,
+
+  -- transaction author, independent of the svn:author property; may
+  -- be null if the repository allows anonymous modifications
+  author    varchar NULL,
+
+  -- transaction state
+  -- T = transient (uncommitted), P = permanent (committed), D = dead
+  state     character(1) NOT NULL DEFAULT 'T',
 
-  -- the operation that produced this entry:
-  -- A = add, R = replace, M = modify, D = delete, N = rename
-  opcode  character(1) NOT NULL,
+  -- sanity check: enumerated value validation
+  CONSTRAINT enumeration_validation CHECK (state IN ('T', 'P', 'D'))
 
-  -- the index entry is the result of an implicit subtree operation
-  subtree boolean NOT NULL
+  -- other attributes:
+     -- revision properties
 );
-CREATE UNIQUE INDEX dirindex_versioned_tree ON dirindex(pathid, version DESC);
-CREATE INDEX dirindex_successor_list ON dirindex(origin);
-CREATE INDEX dirindex_operation ON dirindex(opcode);
-
--- Repository root
-
-INSERT INTO revision (version, created, author, log)
-  VALUES (0, 'EPOCH', NULL, NULL);
-INSERT INTO strindex (strid, content) VALUES (0, '/');
-INSERT INTO dirindex (rowid, origin, pathid, version, kind, opcode, subtree)
-  VALUES (0, NULL, 0, 0, 'D', 'A', 0);
-
-
----STATEMENT INSERT_REVISION_RECORD
-
-INSERT INTO revision (version, created, author, log)
-  VALUES (?, ?, ?, ?);
-
----STATEMENT GET_REVENT_BY_VERSION
-
-SELECT * FROM revision WHERE version = ?;
-
----STATEMENT INSERT_STRINDEX_RECORD
-
-INSERT INTO strindex (content) VALUES (?);
 
----STATEMENT GET_STRENT_BY_STRID
+CREATE INDEX txn_revision_idx ON txn(revision);
 
-SELECT * FROM strindex WHERE strid = ?;
 
----STATEMENT GET_STRENT_BY_CONTENT
+-- Branches -- unique forks in the nodes' history
+CREATE TABLE branch (
+  -- branch identifier
+  id        integer NOT NULL PRIMARY KEY,
 
-SELECT * FROM strindex WHERE content = ?;
+  -- the transaction in which the branch was created
+  treeid    integer NOT NULL REFERENCES txn(id),
 
----STATEMENT INSERT_DIRINDEX_RECORD
+  -- the node to which this branch belongs; refers to the initial
+  -- branch of the node
+  nodeid    integer NULL REFERENCES branch(id),
 
-INSERT INTO dirindex (origin, pathid, version, kind, opcode, subtree)
-  VALUES (?, ?, ?, ?, ?, ?);
+  -- the source branch from which this branch was forked
+  origin    integer NULL REFERENCES branch(id),
 
----STATEMENT GET_DIRENT_BY_ROWID
+  -- mark branches in uncommitted transactions so that they can be
+  -- ignored by branch traversals
+  -- T = transient (uncommitted), P = permanent (committed)
+  state     character(1) NOT NULL DEFAULT 'T',
 
-SELECT dirindex.*, strindex.content FROM dirindex
-  JOIN strindex ON dirindex.pathid = strindex.strid
-WHERE dirindex.rowid = ?;
+  -- sanity check: enumerated value validation
+  CONSTRAINT enumeration_validation CHECK (state IN ('T', 'P')),
 
----STATEMENT GET_DIRENT_BY_ABSPATH_AND_VERSION
-
-SELECT dirindex.*, strindex.content AS abspath FROM dirindex
-  JOIN strindex ON dirindex.pathid = strindex.strid
-WHERE abspath = ? AND dirindex.version = ?;
-
----STATEMENT LOOKUP_ABSPATH_AT_REVISION
-
-SELECT dirindex.*, strindex.content AS abspath FROM dirindex
-  JOIN strindex ON dirindex.pathid = strindex.strid
-WHERE abspath = ? AND dirindex.version <= ?
-ORDER BY abspath ASC, dirindex.version DESC
-LIMIT 1;
-
----STATEMENT LIST_SUBTREE_AT_REVISION
-
-SELECT dirindex.*, strindex.content AS abspath FROM dirindex
-  JOIN strindex ON dirindex.pathid = strindex.strid
-  JOIN (SELECT pathid, MAX(version) AS maxver FROM dirindex
-        WHERE version <= ? GROUP BY pathid)
-    AS filtered
-    ON dirindex.pathid == filtered.pathid
-        AND dirindex.version == filtered.maxver
-WHERE abspath LIKE ? ESCAPE '#'
-      AND dirindex.opcode <> 'D'
-ORDER BY abspath ASC;
-
----STATEMENT LIST_DIRENT_SUCCESSORS
-
-SELECT dirindex.*, strindex.content AS abspath FROM dirindex
-  JOIN strindex ON dirindex.pathid = strindex.strid
-WHERE dirindex.origin = ?
-ORDER BY abspath ASC, dirindex.version ASC;
-
-
--- Temporary transaction
-
----SCRIPT CREATE_TRANSACTION_CONTEXT
-
-CREATE TEMPORARY TABLE txncontext (
-  origin  integer NULL,
-  abspath varchar NOT NULL UNIQUE,
-  kind    character(1) NOT NULL,
-  opcode  character(1) NOT NULL,
-  subtree boolean NOT NULL
+  -- sanity check: ye can't be yer own daddy
+  CONSTRAINT genetic_diversity CHECK (id <> origin)
 );
 
----SCRIPT REMOVE_TRANSACTION_CONTEXT
-
-DROP TABLE IF EXISTS temp.txncontext;
-
----STATEMENT INSERT_TRANSACTION_RECORD
-
-INSERT INTO temp.txncontext (origin, abspath, kind, opcode, subtree)
-  VALUES (?, ?, ?, ?, ?);
-
----STATEMENT GET_TRANSACTION_RECORD
+CREATE INDEX branch_txn_idx ON branch(treeid);
+CREATE INDEX branch_node_idx ON branch(nodeid);
 
-SELECT * FROM temp.txncontext WHERE abspath = ?;
 
----STATEMENT REMOVE_TRANSACTION_RECORD
-
-DELETE FROM temp.txncontext WHERE abspath = ?;
-
----STATEMENT REMOVE_TRANSACTION_SUBTREE
+-- File names -- lookup table of strings
+CREATE TABLE string (
+  id        integer NOT NULL PRIMARY KEY,
+  val       varchar NOT NULL UNIQUE
+);
 
-DELETE FROM temp.txncontext WHERE abspath LIKE ? ESCAPE '#';
 
----STATEMENT LIST_TRANSACTION_RECORDS
+-- Node revisions -- DAG of versioned node changes
+CREATE TABLE noderev (
+  -- node revision identifier
+  id        integer NOT NULL PRIMARY KEY,
+
+  -- the transaction in which the node was changed
+  treeid    integer NOT NULL REFERENCES txn(id),
+
+  -- the node identifier; a new node will get the ID of its initial
+  -- branch
+  nodeid    integer NOT NULL REFERENCES branch(id),
+
+  -- this node revision's immediate predecessor
+  origin    integer NULL REFERENCES noderev(id),
+
+  -- the parent (directory) of this node revision -- tree graph
+  parent    integer NULL REFERENCES branch(id),
+
+  -- the branch that this node revision belongs to -- history graph
+  branch    integer NOT NULL REFERENCES branch(id),
+
+  -- the indexable, NFC-normalized name of this noderev within its parent
+  nameid    integer NOT NULL REFERENCES string(id),
+
+  -- the original, denormalized, non-indexable name
+  denameid  integer NOT NULL REFERENCES string(id),
+
+  -- the node kind; immutable within the node
+  -- D = directory, F = file, etc.
+  kind      character(1) NOT NULL,
+
+  -- the change that produced this node revision
+  -- A = added, D = deleted, M = modified, N = renamed, R = replaced
+  -- B = branched (added + origin <> null)
+  -- L = lazy branch, indicates that child lookup should be performed
+  --     on the origin (requires kind=D + added + origin <> null)
+  -- X = replaced by branch (R + B)
+  -- Z = lazy replace by branch (Like L but implies X instead of B)
+  opcode    character(1) NOT NULL,
+
+  -- mark noderevs of uncommitted transactions so that they can be
+  -- ignored by tree traversals
+  -- T = transient (uncommitted), P = permanent (committed)
+  state     character(1) NOT NULL DEFAULT 'T',
+
+  -- sanity check: enumerated value validation
+  CONSTRAINT enumeration_validation CHECK (
+    kind IN ('D', 'F')
+    AND state IN ('T', 'P')
+    AND opcode IN ('A', 'D', 'M', 'N', 'R', 'B', 'L', 'X', 'Z')),
+
+  -- sanity check: only directories can be lazy
+  CONSTRAINT lazy_copies_make_more_work CHECK (
+    opcode NOT IN ('B', 'L', 'X', 'Z')
+    OR (opcode IN ('B', 'X') AND origin IS NOT NULL)
+    OR (opcode IN ('L', 'Z') AND kind = 'D' AND origin IS NOT NULL)),
+
+  -- sanity check: ye can't be yer own daddy
+  CONSTRAINT genetic_diversity CHECK (id <> origin),
+
+  -- sanity check: ye can't be yer own stepdaddy, either
+  CONSTRAINT escher_avoidance CHECK (parent <> branch)
+
+  -- other attributes:
+     -- versioned properties
+     -- contents reference
+);
 
-SELECT * FROM temp.txncontext ORDER BY abspath ASC;
+CREATE UNIQUE INDEX noderev_tree_idx ON noderev(parent,nameid,treeid,opcode);
+CREATE INDEX noderev_txn_idx ON noderev(treeid);
+CREATE INDEX nodefev_node_idx ON noderev(nodeid);
+CREATE INDEX noderev_successor_idx ON noderev(origin);
+
+
+CREATE VIEW nodeview AS
+  SELECT
+    noderev.*,
+    ns.val AS name,
+    ds.val AS dename
+  FROM
+    noderev JOIN string AS ns ON noderev.nameid = ns.id
+    JOIN string AS ds ON noderev.denameid = ds.id;
+
+
+-- Root directory
+
+INSERT INTO txn (id, treeid, revision, created, state)
+  VALUES (0, 0, 0, 'EPOCH', 'P');
+INSERT INTO branch (id, treeid, nodeid, state) VALUES (0, 0, 0, 'P');
+INSERT INTO string (id, val) VALUES (0, '');
+INSERT INTO noderev (id, treeid, nodeid, branch,
+                     nameid, denameid, kind, opcode, state)
+  VALUES (0, 0, 0, 0, 0, 0, 'D', 'A', 'P');
+
+
+---STATEMENT TXN_INSERT
+INSERT INTO txn (treeid, revision, created, author)
+  VALUES (:treeid, :revision, :created, :author);
+
+---STATEMENT TXN_UPDATE_INITIAL_TREEID
+UPDATE txn SET treeid = :id WHERE id = :id;
+
+---STATEMENT TXN_GET
+SELECT * FROM txn WHERE id = :id;
+
+---STATEMENT TXN_FIND_NEWEST
+SELECT * FROM txn WHERE state = 'P' ORDER BY id DESC LIMIT 1;
+
+---STATEMENT TXN_FIND_BY_REVISION
+SELECT * FROM txn WHERE revision = :revision AND state = 'P'
+ORDER BY id DESC LIMIT 1;
+
+---STATEMENT TXN_FIND_BY_REVISION_AND_TIMESTAMP
+SELECT * FROM txn
+WHERE revision = :revision AND created <= :created AND state = 'P'
+ORDER BY id DESC LIMIT 1;
+
+---STATEMENT TXN_COMMIT
+UPDATE txn SET
+  revision = :revision,
+  created = :created,
+  state = 'P'
+WHERE id = :id;
+
+---STATEMENT TXN_ABORT
+UPDATE txn SET state = 'D' WHERE id = :id;
+
+---STATEMENT TXN_CLEANUP
+DELETE FROM txn WHERE id = :id;
+
+---STATEMENT BRANCH_INSERT
+INSERT INTO branch (nodeid, treeid, origin)
+  VALUES (:nodeid, :treeid, :origin);
+
+---STATEMENT BRANCH_UPDATE_INITIAL_NODEID
+UPDATE branch SET nodeid = :id WHERE id = :id;
+
+---STATEMENT BRANCH_UPDATE_TREEID
+UPDATE branch SET treeid = :new_treeid WHERE treeid = :old_treeid;
+
+---STATEMENT BRANCH_GET
+SELECT * FROM branch WHERE id = :id;
+
+---STATEMENT BRANCH_HISTORY
+SELECT * from branch WHERE nodeid = :nodeid ORDER BY id ASC;
+
+---STATEMENT BRANCH_COMMIT
+UPDATE branch SET state = 'P' WHERE treeid = :treeid;
+
+---STATEMENT BRANCH_CLEANUP
+DELETE FROM branch WHERE treeid = :treeid;
+
+---STATEMENT STRING_INSERT
+INSERT INTO string (val) VALUES (:val);
+
+---STATEMENT STRING_FIND
+SELECT * FROM string WHERE val = :val;
+
+---STATEMENT NODEREV_INSERT
+INSERT INTO noderev (nodeid, treeid, origin, parent, branch,
+                     nameid, denameid, kind, opcode)
+  VALUES (:nodeid, :treeid, :origin, :parent, :branch,
+          :nameid, :denameid, :kind, :opcode);
+
+---STATEMENT NODEREV_UPDATE_TREEID
+UPDATE noderev SET treeid = :new_treeid WHERE treeid = :old_treeid;
+
+---STATEMENT NODEREV_UPDATE_OPCODE
+UPDATE noderev SET opcode = :opcode WHERE id = :id;
+
+---STATEMENT NODEVIEW_GET
+SELECT * FROM nodeview WHERE id = :id;
+
+---STATEMENT NODEREV_COUNT_SUCCESSORS
+SELECT COUNT(id) FROM noderev WHERE origin = :origin;
+
+---STATEMENT NODEREV_COMMIT
+UPDATE noderev SET state = 'P' WHERE treeid = :treeid;
+
+---STATEMENT NODEREV_CLEANUP
+DELETE FROM noderev WHERE treeid = :treeid;
+
+---STATEMENT NODEVIEW_FIND_ROOT
+SELECT * FROM nodeview
+WHERE parent IS NULL AND name = ''
+      AND treeid <= :treeid AND state = 'P'
+ORDER BY treeid DESC LIMIT 1;
+
+---STATEMENT NODEVIEW_FIND_BY_NAME
+SELECT * FROM nodeview
+WHERE parent = :parent AND name = :name
+      AND treeid <= :treeid AND state = 'P'
+ORDER BY treeid DESC LIMIT 1;
+
+---STATEMENT NODEVIEW_FIND_TRANSIENT_ROOT
+SELECT * FROM nodeview
+WHERE parent IS NULL AND name = ''
+      AND (treeid < :treeid AND state = 'P' OR treeid = :treeid)
+ORDER BY treeid DESC LIMIT 1;
+
+---STATEMENT NODEVIEW_FIND_TRANSIENT_BY_NAME
+SELECT * FROM nodeview
+WHERE parent = :parent AND name = :name
+      AND (treeid < :treeid AND state = 'P' OR treeid = :treeid)
+ORDER BY treeid DESC LIMIT 1;
+
+---STATEMENT NODEVIEW_LIST_DIRECTORY
+SELECT * FROM nodeview
+  JOIN (SELECT nameid, MAX(treeid) AS treeid FROM noderev
+        WHERE treeid <= :treeid AND state = 'P') AS filter
+    ON nodeview.nameid = filter.nameid AND nodeview.treeid = filter.treeid
+WHERE parent = :parent AND opcode <> 'D'
+ORDER BY nodeview.name ASC;
+
+---STATEMENT NODEVIEW_LIST_TRANSIENT_DIRECTORY
+SELECT * FROM nodeview
+  JOIN (SELECT nameid, MAX(treeid) AS treeid FROM noderev
+        WHERE treeid < :treeid AND state = 'P' OR treeid = :treeid) AS filter
+    ON nodeview.nameid = filter.name AND nodeview.treeid = filter.treeid
+WHERE parent = :parent AND opcode <> 'D'
+ORDER BY nodeview.name ASC;

Modified: subversion/branches/javahl-ra/subversion/bindings/swig/python/svn/fs.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/bindings/swig/python/svn/fs.py?rev=1425415&r1=1425414&r2=1425415&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/bindings/swig/python/svn/fs.py (original)
+++ subversion/branches/javahl-ra/subversion/bindings/swig/python/svn/fs.py Sun Dec 23 06:03:14 2012
@@ -115,7 +115,7 @@ class FileDiff:
           + [self.tempfile1, self.tempfile2]
 
     # open the pipe, and return the file object for reading from the child.
-    p = _subprocess.Popen(cmd, stdout=_subprocess.PIPE,
+    p = _subprocess.Popen(cmd, stdout=_subprocess.PIPE, bufsize=-1,
                           close_fds=_sys.platform != "win32")
     return p.stdout
 



Mime
View raw message