You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by wo...@apache.org on 2017/07/18 07:45:05 UTC

[couchdb] 01/01: Fix _local_docs end-point

This is an automated email from the ASF dual-hosted git repository.

wohali pushed a commit to branch jenkins-packages-2
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit c40f66d06bafbeb2e04c989e1a3ecfe5c034fde4
Author: Eric Avdey <ei...@eiri.ca>
AuthorDate: Mon May 1 10:27:31 2017 -0300

    Fix _local_docs end-point
    
    This is a second attempt to fix _local_docs end-point. The previous one didn't
    work on big enough btree_local, because local btree doesn't have reduction fun,
    so reuse of couch_db_updater:btree_by_id_reduce/2 was crashing on a bad match
    as soon as btree_local was getting kp_node. Also using full fold to calculate
    total_rows value turned out to be resource expensive when a database have
    significant number of local documents.
    
    This fix avoids calculating of total_rows and offset instead always setting
    them to null and also setting to null update_seq when requested, since it
    doesn't have meaning in context of local documents.
    
    A fabric module fabric_view_all_docs.erl was copied and modified as
    fabric_view_local_docs.erl, because re-using it for processing of both types of
    the documents was getting rather convoluted.
    
    Jira: COUCHDB-3337
---
 Jenkinsfile                                        | 313 +++++++++++++++------
 src/couch/src/couch_db.erl                         |   2 +-
 src/couch_mrview/src/couch_mrview.erl              |  34 ++-
 src/couch_mrview/src/couch_mrview_http.erl         |   2 +
 src/couch_mrview/src/couch_mrview_util.erl         |  13 +-
 .../test/couch_mrview_local_docs_tests.erl         |  24 +-
 src/fabric/src/fabric_view_all_docs.erl            |  59 ++--
 7 files changed, 320 insertions(+), 127 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 6fbb7e7..88401b8 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -26,21 +26,25 @@ pipeline {
     stage('Build') {
       agent {
         docker {
-          /* This image has the oldest Erlang we support, 16B03 */
+          label 'ubuntu'
+          // This image has the oldest Erlang we support, 16B03
           image 'couchdbdev/ubuntu-14.04-erlang-default'
-          /* We need the jenkins user mapped inside of the image */
-          args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group'
+          // https://github.com/jenkins-infra/jenkins.io/blob/master/Jenkinsfile#64
+          // We need the jenkins user mapped inside of the image
+          args '-e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group'
         }
       }
       steps {
         timeout(time: 15, unit: "MINUTES") {
-          /* npm config cache below is required because /home/jenkins doesn't
-             ACTUALLY exist in the image */
-          /* sh 'git clone --depth 10 https://github.com/apache/couchdb .' */
+          // npm config cache below is required because /home/jenkins doesn't
+          // ACTUALLY exist in the image
           sh '''
-              export npm_config_cache=$(mktemp -d)
-              ./configure --with-curl
-              make dist
+            set
+            rm -rf apache-couchdb-*.tar.gz
+            #export npm_config_cache=$(mktemp -d)
+            ./configure --with-curl
+            make dist
+            chmod -R a+w *
           '''
           stash includes: 'apache-couchdb-*.tar.gz', name: 'tarball'
           archiveArtifacts artifacts: 'apache-couchdb-*.tar.gz', fingerprint: true
@@ -49,44 +53,69 @@ pipeline {
       }
     }
 
-    /* TODO rework this once JENKINS-41334 is released
-       https://issues.jenkins-ci.org/browse/JENKINS-41334 */
-    /* The builddir stuff is to prevent all 10 builds from live syncing
-       their build results to each other during the build. Moving the
-       build outside of the workdir should speed up the build process too,
-       though it does mean we pollute /tmp whenever a build fails. */
+    // TODO rework this once JENKINS-41334 is released
+    // https://issues.jenkins-ci.org/browse/JENKINS-41334
+
+    // The builddir stuff is to prevent all 10 builds from live syncing
+    // their build results to each other during the build. Moving the
+    // build outside of the workdir should speed up the build process, too
+
+    // we run all package builds as root inside the Docker container
+    
+    // Build packages on supported platforms using esl's erlang
     stage('Test') {
       steps {
         parallel(centos6erlang183: {
           node(label: 'ubuntu') {
-            timeout(time: 45, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 60, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/centos-6-erlang-18.3'
-              withDockerContainer(image: 'couchdbdev/centos-6-erlang-18.3', args: '-e LD_LIBRARY_PATH=/usr/local/bin --user 0:0') {
+              withDockerContainer(image: 'couchdbdev/centos-6-erlang-18.3', args: '-e LD_LIBRARY_PATH=/usr/local/bin -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group --user 0:0') {
                 sh '''
                   cwd=$(pwd)
-                  rm -rf /tmp/couchjslogs
-                  mkdir -p /tmp/couchjslogs
+                  umask 0
+                  rm -rf /tmp/couchjslogs && mkdir -p /tmp/couchjslogs
+
+                  # Build CouchDB from tarball
                   builddir=$(mktemp -d)
                   cd $builddir
                   tar -xf $cwd/apache-couchdb-*.tar.gz
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
+
+                  # Build CouchDB packages
+                  cd $builddir
+                  git clone https://github.com/apache/couchdb-pkg
+                  mkdir couchdb
+                  cd couchdb
+                  cp $cwd/apache-couchdb-*.tar.gz .
+                  tar -xf apache-couchdb-*.tar.gz
+                  cd ../couchdb-pkg
+                  # centos only
+                  platform=centos6
+                  make $platform PLATFORM=$platform
+                  rm -rf $cwd/pkgs/$platform && mkdir -p $cwd/pkgs/$platform
+                  # CentOS variant
+                  mv ~/rpmbuild/RPMS/x86_64/*rpm $cwd/pkgs/$platform || true
+
+                  # Cleanup
+                  cd $cwd && rm -rf $builddir
+                  chown -R jenkins:jenkins *
                 '''
               } // withDocker
             } // timeout
+            archiveArtifacts artifacts: 'pkgs/**', fingerprint: true
+            deleteDir()
           } // node
         },
         centos7erlangdefault: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 45, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/centos-7-erlang-default'
-              withDockerContainer(image: 'couchdbdev/centos-7-erlang-default', args: '-e LD_LIBRARY_PATH=/usr/local/bin --user 0:0') {
+              withDockerContainer(image: 'couchdbdev/centos-7-erlang-default', args: '-e LD_LIBRARY_PATH=/usr/local/bin -e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group') {
                 sh '''
                   cwd=$(pwd)
                   rm -rf /tmp/couchjslogs
@@ -97,42 +126,64 @@ pipeline {
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
                 '''
               } // withDocker
             } // timeout
+            deleteDir()
           } // node
         },
         centos7erlang183: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 60, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/centos-7-erlang-18.3'
-              withDockerContainer(image: 'couchdbdev/centos-7-erlang-18.3', args: '-e LD_LIBRARY_PATH=/usr/local/bin --user 0:0') {
+              withDockerContainer(image: 'couchdbdev/centos-7-erlang-18.3', args: '-e LD_LIBRARY_PATH=/usr/local/bin -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group --user 0:0') {
                 sh '''
                   cwd=$(pwd)
-                  rm -rf /tmp/couchjslogs
-                  mkdir -p /tmp/couchjslogs
+                  umask 0
+                  rm -rf /tmp/couchjslogs && mkdir -p /tmp/couchjslogs
+
+                  # Build CouchDB from tarball
                   builddir=$(mktemp -d)
                   cd $builddir
                   tar -xf $cwd/apache-couchdb-*.tar.gz
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
+
+                  # Build CouchDB packages
+                  cd $builddir
+                  git clone https://github.com/apache/couchdb-pkg
+                  mkdir couchdb
+                  cd couchdb
+                  cp $cwd/apache-couchdb-*.tar.gz .
+                  tar -xf apache-couchdb-*.tar.gz
+                  cd ../couchdb-pkg
+                  # centos only
+                  platform=centos7
+                  make $platform PLATFORM=$platform
+                  rm -rf $cwd/pkgs/$platform && mkdir -p $cwd/pkgs/$platform
+                  # CentOS variant
+                  mv ~/rpmbuild/RPMS/x86_64/*rpm $cwd/pkgs/$platform || true
+
+                  # Cleanup
+                  cd $cwd && rm -rf $builddir
+                  chown -R jenkins:jenkins *
                 '''
               } // withDocker
             } // timeout
+            archiveArtifacts artifacts: 'pkgs/**', fingerprint: true
+            deleteDir()
           } // node
         },
         ubuntu1204erlang183: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 45, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/ubuntu-12.04-erlang-18.3'
-              withDockerContainer(image: 'couchdbdev/ubuntu-12.04-erlang-18.3', args: '--user 0:0') {
+              withDockerContainer(image: 'couchdbdev/ubuntu-12.04-erlang-18.3', args: '-e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group') {
                 sh '''
                   cwd=$(pwd)
                   rm -rf /tmp/couchjslogs
@@ -143,19 +194,19 @@ pipeline {
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
                 '''
               } // withDocker
             } // timeout
+            deleteDir()
           } // node
         },
         ubuntu1404erlangdefault: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 45, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/ubuntu-14.04-erlang-default'
-              withDockerContainer(image: 'couchdbdev/ubuntu-14.04-erlang-default', args: '--user 0:0') {
+              withDockerContainer(image: 'couchdbdev/ubuntu-14.04-erlang-default', args: '-e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group') {
                 sh '''
                   cwd=$(pwd)
                   rm -rf /tmp/couchjslogs
@@ -166,42 +217,65 @@ pipeline {
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
                 '''
               } // withDocker
             } // timeout
+            deleteDir()
           } // node
         },
         ubuntu1404erlang183: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 60, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/ubuntu-14.04-erlang-18.3'
-              withDockerContainer(image: 'couchdbdev/ubuntu-14.04-erlang-18.3', args: '--user 0:0') {
+              withDockerContainer(image: 'couchdbdev/ubuntu-14.04-erlang-18.3', args: '-v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group --user 0:0') {
                 sh '''
                   cwd=$(pwd)
-                  rm -rf /tmp/couchjslogs
-                  mkdir -p /tmp/couchjslogs
+                  umask 0
+                  rm -rf /tmp/couchjslogs && mkdir -p /tmp/couchjslogs
+
+                  # Build CouchDB from tarball
                   builddir=$(mktemp -d)
                   cd $builddir
                   tar -xf $cwd/apache-couchdb-*.tar.gz
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
+
+                  # Build CouchDB packages
+                  cd $builddir
+                  git clone https://github.com/apache/couchdb-pkg
+                  mkdir couchdb
+                  cd couchdb
+                  cp $cwd/apache-couchdb-*.tar.gz .
+                  tar -xf apache-couchdb-*.tar.gz
+                  cd ../couchdb-pkg
+                  # debian/ubuntu only
+                  sudo apt-get install -y libmozjs185-dev
+                  platform=$(lsb_release -cs)
+                  make $platform PLATFORM=$platform
+                  rm -rf $cwd/pkgs/$platform && mkdir -p $cwd/pkgs/$platform
+                  # Ubuntu/Debian variant
+                  mv ../couchdb/*deb $cwd/pkgs/$platform || true
+
+                  # Cleanup
+                  cd $cwd && rm -rf $builddir
+                  chown -R jenkins:jenkins *
                 '''
               } // withDocker
             } // timeout
+            archiveArtifacts artifacts: 'pkgs/**', fingerprint: true
+            deleteDir()
           } // node
         },
         ubuntu1604erlangdefault: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 45, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/ubuntu-16.04-erlang-default'
-              withDockerContainer(image: 'couchdbdev/ubuntu-16.04-erlang-default', args: '--user 0:0') {
+              withDockerContainer(image: 'couchdbdev/ubuntu-16.04-erlang-default', args: '-e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group') {
                 sh '''
                   cwd=$(pwd)
                   rm -rf /tmp/couchjslogs
@@ -212,42 +286,65 @@ pipeline {
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
                 '''
               } // withDocker
             } // timeout
+            deleteDir()
           } // node
         },
         ubuntu1604erlang183: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 60, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/ubuntu-16.04-erlang-18.3'
-              withDockerContainer(image: 'couchdbdev/ubuntu-16.04-erlang-18.3', args: '--user 0:0') {
+              withDockerContainer(image: 'couchdbdev/ubuntu-16.04-erlang-18.3', args: '-v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group --user 0:0') {
                 sh '''
                   cwd=$(pwd)
-                  rm -rf /tmp/couchjslogs
-                  mkdir -p /tmp/couchjslogs
+                  umask 0
+                  rm -rf /tmp/couchjslogs && mkdir -p /tmp/couchjslogs
+
+                  # Build CouchDB from tarball
                   builddir=$(mktemp -d)
                   cd $builddir
                   tar -xf $cwd/apache-couchdb-*.tar.gz
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
+
+                  # Build CouchDB packages
+                  cd $builddir
+                  git clone https://github.com/apache/couchdb-pkg
+                  mkdir couchdb
+                  cd couchdb
+                  cp $cwd/apache-couchdb-*.tar.gz .
+                  tar -xf apache-couchdb-*.tar.gz
+                  cd ../couchdb-pkg
+                  # debian/ubuntu only
+                  sudo apt-get install -y libmozjs185-dev
+                  platform=$(lsb_release -cs)
+                  make $platform PLATFORM=$platform
+                  rm -rf $cwd/pkgs/$platform && mkdir -p $cwd/pkgs/$platform
+                  # Ubuntu/Debian variant
+                  mv ../couchdb/*deb $cwd/pkgs/$platform || true
+
+                  # Cleanup
+                  cd $cwd && rm -rf $builddir
+                  chown -R jenkins:jenkins *
                 '''
               } // withDocker
             } // timeout
+            archiveArtifacts artifacts: 'pkgs/**', fingerprint: true
+            deleteDir()
           } // node
         },
         debian8erlangdefault: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 45, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/debian-8-erlang-default'
-              withDockerContainer(image: 'couchdbdev/debian-8-erlang-default', args: '--user 0:0') {
+              withDockerContainer(image: 'couchdbdev/debian-8-erlang-default', args: '-e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group') {
                 sh '''
                   cwd=$(pwd)
                   rm -rf /tmp/couchjslogs
@@ -258,33 +355,57 @@ pipeline {
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
                 '''
               } // withDocker
             } // timeout
+            deleteDir()
           } // node
         },
         debian8erlang183: {
           node(label: 'ubuntu') {
-            timeout(time: 30, unit: "MINUTES") {
-              sh 'rm *.tar.gz || true'
+            timeout(time: 60, unit: "MINUTES") {
               unstash 'tarball'
               sh 'docker pull couchdbdev/debian-8-erlang-18.3'
-              withDockerContainer(image: 'couchdbdev/debian-8-erlang-18.3', args: '--user 0:0') {
+              // must run as root because of sudo step below
+              withDockerContainer(image: 'couchdbdev/debian-8-erlang-18.3', args: '-v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group --user 0:0') {
                 sh '''
                   cwd=$(pwd)
-                  rm -rf /tmp/couchjslogs
-                  mkdir -p /tmp/couchjslogs
+                  rm -rf /tmp/couchjslogs && mkdir -p /tmp/couchjslogs
+
+                  # Build CouchDB from tarball
                   builddir=$(mktemp -d)
                   cd $builddir
                   tar -xf $cwd/apache-couchdb-*.tar.gz
                   cd apache-couchdb-*
                   ./configure --with-curl
                   make all
-                  make check || (build-aux/logfile-uploader.py && false)
+                  #make check || (build-aux/logfile-uploader.py && false)
+
+                  # Build CouchDB packages
+                  cd $builddir
+                  git clone https://github.com/apache/couchdb-pkg
+                  mkdir couchdb
+                  cd couchdb
+                  cp $cwd/apache-couchdb-*.tar.gz .
+                  tar -xf apache-couchdb-*.tar.gz
+                  cd ../couchdb-pkg
+                  # debian/ubuntu only
+                  sudo apt-get install -y libmozjs185-dev
+                  platform=$(lsb_release -cs)
+                  make $platform PLATFORM=$platform
+                  rm -rf $cwd/pkgs/$platform && mkdir -p $cwd/pkgs/$platform
+                  # Ubuntu/Debian variant
+                  mv ../couchdb/*deb $cwd/pkgs/$platform || true
+
+                  # Cleanup
+                  cd $cwd && rm -rf $builddir
+                  chown -R jenkins:jenkins *
                 '''
               } // withDocker
             } // timeout
+            archiveArtifacts artifacts: 'pkgs/**', fingerprint: true
+            deleteDir()
           } // node
         }
         ) // parallel
@@ -293,22 +414,56 @@ pipeline {
 
     stage('Publish') {
       when {
-        branch '*(master|2.0.x|2.1.x)'
+        expression { return env.BRANCH_NAME ==~ /master|2.0.x|2.1.x|jenkins-.*/ }
       }
-      agent any
-      steps {
-        /* Push it somewhere useful other than Jenkins, maybe? */
-        /* echo 'Publishing tarball...'
-        unstash 'tarball' */
-        echo 'Triggering Debian .deb builds...'
-        echo 'Triggering Ubuntu .deb builds...'
-        echo 'Triggering Ubuntu snap builds...'
-        echo 'Triggering CentOS .rpm builds...'
-        echo 'Cleaning workspace...'
-        sh 'rm -rf * .[a-zA-Z]*'
+      agent {
+        docker {
+          // This image has the deb AND rpm repo tools installed in it
+          image 'couchdbdev/debian-8-base'
+          // We need the jenkins user mapped inside of the image
+          args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group'
+          label 'ubuntu'
+        }
       }
-    }
-  }
+      steps {
+        withCredentials([file(credentialsId: 'jenkins-key', variable: 'KEY')]) {
+          sh 'rm -rf pkgs'
+          unarchive mapping: ['pkgs/' : '.']
+          echo 'Building Debian repo...'
+          sh '''
+            git clone https://github.com/apache/couchdb-pkg
+            reprepro -b couchdb-pkg/repo includedeb jessie pkgs/jessie/*deb
+            reprepro -b couchdb-pkg/repo includedeb trusty pkgs/trusty/*deb
+            reprepro -b couchdb-pkg/repo includedeb xenial pkgs/xenial/*deb
+          '''
+          echo 'Building CentOS repos...'
+          sh '''
+            cd pkgs/centos6 && createrepo --database .
+            cd ../centos7 && rm js* && createrepo --database .
+          '''
+          echo 'rsyncing repos to couchdb-vm2...'
+          sh '''
+            mkdir -p $BRANCH_NAME/debian $BRANCH_NAME/el6 $BRANCH_NAME/el7
+            mv couchdb-pkg/repo/pool $BRANCH_NAME/debian
+            mv couchdb-pkg/repo/dists $BRANCH_NAME/debian
+            mv pkgs/centos6/* $BRANCH_NAME/el6
+            mv pkgs/centos7/* $BRANCH_NAME/el7
+            rsync -avz --delete -e "ssh -i $KEY" $BRANCH_NAME username@couchdb-vm2.apache.org:/var/www/html
+          '''
+          // cronjob on couchdb-vm2 cleans up old tarballs (keeps latest 10)
+          echo 'rsyncing source tarball to couchdb-vm2...'
+          unstash 'tarball'
+          sh '''
+            rm -rf $BRANCH_NAME
+            mkdir -p $BRANCH_NAME/source
+            mv apache-couchdb-*.tar.gz $BRANCH_NAME/source
+            rsync -avz -e "ssh -i $KEY" $BRANCH_NAME username@couchdb-vm2.apache.org:/var/www/html
+          '''
+          deleteDir()
+        } // withCredentials
+      } // steps
+    } // stage
+  } // stages
 
   post {
     success {
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index 51c8172..7a1afa7 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -1288,7 +1288,7 @@ enum_docs(Db, <<"_local">>, InFun, InAcc, Options) ->
     FoldFun = pipe([fun skip_deleted/4], InFun),
     {ok, _LastReduce, OutAcc} = couch_btree:fold(
         Db#db.local_tree, FoldFun, InAcc, Options),
-    {ok, 0, OutAcc};
+    {ok, null, OutAcc};
 enum_docs(Db, NS, InFun, InAcc, Options0) ->
     FoldFun = pipe([
         fun skip_deleted/4,
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index ff43c61..45dd83d 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -403,8 +403,9 @@ cleanup(Db) ->
 
 
 all_docs_fold(Db, #mrargs{keys=undefined}=Args, Callback, UAcc) ->
+    ReduceFun = get_reduce_fun(Args),
     Total = get_total_rows(Db, Args),
-    UpdateSeq = couch_db:get_update_seq(Db),
+    UpdateSeq = get_update_seq(Db, Args),
     Acc = #mracc{
         db=Db,
         total_rows=Total,
@@ -412,7 +413,7 @@ all_docs_fold(Db, #mrargs{keys=undefined}=Args, Callback, UAcc) ->
         skip=Args#mrargs.skip,
         callback=Callback,
         user_acc=UAcc,
-        reduce_fun=fun couch_mrview_util:all_docs_reduce_to_count/1,
+        reduce_fun=ReduceFun,
         update_seq=UpdateSeq,
         args=Args
     },
@@ -420,8 +421,9 @@ all_docs_fold(Db, #mrargs{keys=undefined}=Args, Callback, UAcc) ->
     {ok, Offset, FinalAcc} = couch_db:enum_docs(Db, fun map_fold/3, Acc, Opts),
     finish_fold(FinalAcc, [{total, Total}, {offset, Offset}]);
 all_docs_fold(Db, #mrargs{direction=Dir, keys=Keys0}=Args, Callback, UAcc) ->
+    ReduceFun = get_reduce_fun(Args),
     Total = get_total_rows(Db, Args),
-    UpdateSeq = couch_db:get_update_seq(Db),
+    UpdateSeq = get_update_seq(Db, Args),
     Acc = #mracc{
         db=Db,
         total_rows=Total,
@@ -429,7 +431,7 @@ all_docs_fold(Db, #mrargs{direction=Dir, keys=Keys0}=Args, Callback, UAcc) ->
         skip=Args#mrargs.skip,
         callback=Callback,
         user_acc=UAcc,
-        reduce_fun=fun couch_mrview_util:all_docs_reduce_to_count/1,
+        reduce_fun=ReduceFun,
         update_seq=UpdateSeq,
         args=Args
     },
@@ -653,18 +655,34 @@ make_meta(Args, UpdateSeq, Base) ->
     end.
 
 
-get_total_rows(#db{local_tree = LocalTree} = Db, #mrargs{extra = Extra}) ->
+get_reduce_fun(#mrargs{extra = Extra}) ->
     case couch_util:get_value(namespace, Extra) of
         <<"_local">> ->
-            FoldFun = fun(_, _, Acc) -> {ok, Acc + 1} end,
-            {ok, _, Total} = couch_btree:foldl(LocalTree, FoldFun, 0),
-            Total;
+            fun(_) -> null end;
+        _ ->
+            fun couch_mrview_util:all_docs_reduce_to_count/1
+    end.
+
+
+get_total_rows(#db{} = Db, #mrargs{extra = Extra}) ->
+    case couch_util:get_value(namespace, Extra) of
+        <<"_local">> ->
+            null;
         _ ->
             {ok, Info} = couch_db:get_db_info(Db),
             couch_util:get_value(doc_count, Info)
     end.
 
 
+get_update_seq(#db{} = Db, #mrargs{extra = Extra}) ->
+    case couch_util:get_value(namespace, Extra) of
+        <<"_local">> ->
+            null;
+        _ ->
+            couch_db:get_update_seq(Db)
+    end.
+
+
 default_cb(complete, Acc) ->
     {ok, lists:reverse(Acc)};
 default_cb({final, Info}, []) ->
diff --git a/src/couch_mrview/src/couch_mrview_http.erl b/src/couch_mrview/src/couch_mrview_http.erl
index 7e3fd78..a94f48d 100644
--- a/src/couch_mrview/src/couch_mrview_http.erl
+++ b/src/couch_mrview/src/couch_mrview_http.erl
@@ -380,6 +380,8 @@ view_cb({meta, Meta}, #vacc{meta_sent=false, row_sent=false}=Acc) ->
         Offset -> [io_lib:format("\"offset\":~p", [Offset])]
     end ++ case couch_util:get_value(update_seq, Meta) of
         undefined -> [];
+        null ->
+            ["\"update_seq\":null"];
         UpdateSeq when is_integer(UpdateSeq) ->
             [io_lib:format("\"update_seq\":~B", [UpdateSeq])];
         UpdateSeq when is_binary(UpdateSeq) ->
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index 4bbb7cb..5c95f2e 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -345,8 +345,7 @@ get_row_count(#mrview{btree=Bt}) ->
     {ok, Count}.
 
 
-all_docs_reduce_to_count(Reductions0) ->
-    Reductions = maybe_convert_reductions(Reductions0),
+all_docs_reduce_to_count(Reductions) ->
     Reduce = fun couch_db_updater:btree_by_id_reduce/2,
     {Count, _, _} = couch_btree:final_reduce(Reduce, Reductions),
     Count.
@@ -866,16 +865,6 @@ maybe_load_doc(Db, Id, Val, #mrargs{doc_options=Opts}) ->
     doc_row(couch_index_util:load_doc(Db, docid_rev(Id, Val), []), Opts).
 
 
-maybe_convert_reductions({KVs0, UserReductions}) ->
-    KVs = lists:map(fun maybe_convert_kv/1, KVs0),
-    {KVs, UserReductions}.
-
-maybe_convert_kv({<<"_local/", _/binary>> = DocId, _}) ->
-    #full_doc_info{id = DocId};
-maybe_convert_kv(DocInfo) ->
-    DocInfo.
-
-
 doc_row(null, _Opts) ->
     [{doc, null}];
 doc_row(Doc, Opts) ->
diff --git a/src/couch_mrview/test/couch_mrview_local_docs_tests.erl b/src/couch_mrview/test/couch_mrview_local_docs_tests.erl
index c16f53c..f18f66e 100644
--- a/src/couch_mrview/test/couch_mrview_local_docs_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_local_docs_tests.erl
@@ -43,7 +43,8 @@ all_docs_test_() ->
                     fun should_query_with_range/1,
                     fun should_query_with_range_rev/1,
                     fun should_query_with_limit_and_skip/1,
-                    fun should_query_with_include_docs/1
+                    fun should_query_with_include_docs/1,
+                    fun should_query_with_update_seq/1
                 ]
             }
         }
@@ -53,7 +54,7 @@ all_docs_test_() ->
 should_query(Db) ->
     Result = run_query(Db, []),
     Expect = {ok, [
-        {meta, [{total, 10}, {offset, 0}]},
+        {meta, [{total, null}, {offset, null}]},
         mk_row(1),
         mk_row(10),
         mk_row(2),
@@ -73,7 +74,7 @@ should_query_with_range(Db) ->
         {end_key, <<"_local/5">>}
     ]),
     Expect = {ok, [
-        {meta, [{total, 10}, {offset, 3}]},
+        {meta, [{total, null}, {offset, null}]},
         mk_row(3),
         mk_row(4),
         mk_row(5)
@@ -87,7 +88,7 @@ should_query_with_range_rev(Db) ->
         {inclusive_end, true}
     ]),
     Expect = {ok, [
-        {meta, [{total, 10}, {offset, 4}]},
+        {meta, [{total, null}, {offset, null}]},
         mk_row(5),
         mk_row(4),
         mk_row(3)
@@ -101,7 +102,7 @@ should_query_with_limit_and_skip(Db) ->
         {skip, 3}
     ]),
     Expect = {ok, [
-        {meta, [{total, 10}, {offset, 5}]},
+        {meta, [{total, null}, {offset, null}]},
         mk_row(5),
         mk_row(6),
         mk_row(7)
@@ -117,11 +118,22 @@ should_query_with_include_docs(Db) ->
     {row, Doc0} = mk_row(8),
     Doc = Doc0 ++ [{doc, {[{<<"val">>, 8}]}}],
     Expect = {ok, [
-        {meta, [{total, 10}, {offset, 8}]},
+        {meta, [{total, null}, {offset, null}]},
         {row, Doc}
     ]},
     ?_assertEqual(Expect, Result).
 
+should_query_with_update_seq(Db) ->
+    Result = run_query(Db, [
+        {start_key, <<"_local/2">>},
+        {limit, 1},
+        {update_seq, true}
+    ]),
+    Expect = {ok, [
+        {meta, [{total, null}, {offset, null}, {update_seq, null}]},
+        mk_row(2)
+    ]},
+    ?_assertEqual(Expect, Result).
 
 mk_row(IntId) ->
     Id = list_to_binary(io_lib:format("_local/~b", [IntId])),
diff --git a/src/fabric/src/fabric_view_all_docs.erl b/src/fabric/src/fabric_view_all_docs.erl
index 2ba6f0d..de21dde 100644
--- a/src/fabric/src/fabric_view_all_docs.erl
+++ b/src/fabric/src/fabric_view_all_docs.erl
@@ -58,9 +58,9 @@ go(DbName, Options, QueryArgs, Callback, Acc0) ->
         limit = Limit,
         conflicts = Conflicts,
         skip = Skip,
-        keys = Keys0
+        keys = Keys0,
+        extra = Extra
     } = QueryArgs,
-    {_, Ref0} = spawn_monitor(fun() -> exit(fabric:get_doc_count(DbName)) end),
     DocOptions1 = case Conflicts of
         true -> [conflicts|DocOptions0];
         _ -> DocOptions0
@@ -81,20 +81,31 @@ go(DbName, Options, QueryArgs, Callback, Acc0) ->
         true -> lists:sublist(Keys2, Limit);
         false -> Keys2
     end,
-    Timeout = fabric_util:all_docs_timeout(),
-    receive {'DOWN', Ref0, _, _, Result} ->
-        case Result of
-            {ok, TotalRows} ->
-                {ok, Acc1} = Callback({meta, [{total, TotalRows}]}, Acc0),
-                {ok, Acc2} = doc_receive_loop(
-                    Keys3, queue:new(), SpawnFun, MaxJobs, Callback, Acc1
-                ),
-                Callback(complete, Acc2);
-            Error ->
-                Callback({error, Error}, Acc0)
-        end
-    after Timeout ->
-        Callback(timeout, Acc0)
+    Resp = case couch_util:get_value(namespace, Extra, <<"_all_docs">>) of
+        <<"_local">> ->
+            {ok, null};
+        _ ->
+            Timeout = fabric_util:all_docs_timeout(),
+            {_, Ref0} = spawn_monitor(fun() ->
+                exit(fabric:get_doc_count(DbName))
+            end),
+            receive {'DOWN', Ref0, _, _, Result} ->
+                Result
+            after Timeout ->
+                timeout
+            end
+    end,
+    case Resp of
+        {ok, TotalRows} ->
+            {ok, Acc1} = Callback({meta, [{total, TotalRows}]}, Acc0),
+            {ok, Acc2} = doc_receive_loop(
+                Keys3, queue:new(), SpawnFun, MaxJobs, Callback, Acc1
+            ),
+            Callback(complete, Acc2);
+        timeout ->
+            Callback(timeout, Acc0);
+        Error ->
+            Callback({error, Error}, Acc0)
     end.
 
 go(DbName, _Options, Workers, QueryArgs, Callback, Acc0) ->
@@ -142,10 +153,11 @@ handle_message({meta, Meta0}, {Worker, From}, State) ->
     0 = fabric_dict:lookup_element(Worker, Counters0),
     rexi:stream_ack(From),
     Counters1 = fabric_dict:update_counter(Worker, 1, Counters0),
-    Total = Total0 + Tot,
-    Offset = Offset0 + Off,
-    UpdateSeq = case UpdateSeq0 of
-        nil -> nil;
+    Total = if Tot == null -> null; true -> Total0 + Tot end,
+    Offset = if Off == null -> null; true -> Offset0 + Off end,
+    UpdateSeq = case {UpdateSeq0, Seq} of
+        {nil, _} -> nil;
+        {_, null} -> null;
         _   -> [{Worker, Seq} | UpdateSeq0]
     end,
     case fabric_dict:any(0, Counters1) of
@@ -157,11 +169,16 @@ handle_message({meta, Meta0}, {Worker, From}, State) ->
             offset = Offset
         }};
     false ->
-        FinalOffset = erlang:min(Total, Offset+State#collector.skip),
+        FinalOffset = case Offset of
+            null -> null;
+            _ -> erlang:min(Total, Offset+State#collector.skip)
+        end,
         Meta = [{total, Total}, {offset, FinalOffset}] ++
             case UpdateSeq of
                 nil ->
                     [];
+                null ->
+                    [{update_seq, null}];
                 _ ->
                     [{update_seq, fabric_view_changes:pack_seqs(UpdateSeq)}]
             end,

-- 
To stop receiving notification emails like this one, please contact
"commits@couchdb.apache.org" <co...@couchdb.apache.org>.