Building and running Couchbase on FreeBSD


October 2015.
The FreeBSD logo The Couchbase logo

Lets's try to build and run Couchbase on FreeBSD!

The system I'm using here is completely new.


# uname -a
FreeBSD couchbasebsd 10.2-RELEASE FreeBSD 10.2-RELEASE #0 r286666: Wed Aug 12 15:26:37 UTC 2015 root@releng1.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC amd64

Fetching the source


Let's download repo, Google's tool to fetch multiple git repositories at once.


# fetch https://storage.googleapis.com/git-repo-downloads/repo -o /root/bin/repo --no-verify-peer
/root/bin/repo 100% of 25 kB 1481 kBps 00m00s

I don't have any certificate bundle installed, so I need --no-verify-peer to prevent openssl from complaining. In that case I must verify that the file is correct before executing it.


# sha1 /root/bin/repo
SHA1 (/root/bin/repo) = da0514e484f74648a890c0467d61ca415379f791

The list of SHA1s can be found in Android Open Source Project - Downloading the Source .

Make it executable.


# chmod +x /root/bin/repo

Create a directory to work in.


# mkdir couchbase && cd couchbase

I'll be fetching branch 3.1.1, which is the latest release at the time I'm writing this.


# /root/bin/repo init -u git://github.com/couchbase/manifest -m released/3.1.1.xml
env: python: No such file or directory

Told you the system was brand new.


# make -C /usr/ports/lang/python install clean

Let's try again.


# /root/bin/repo init -u git://github.com/couchbase/manifest -m released/3.1.1.xml

fatal: 'git' is not available
fatal: [Errno 2] No such file or directory

Please make sure git is installed and in your path.

Install git:


# make -C /usr/ports/devel/git install clean

Try again:


# /root/bin/repo init -u git://github.com/couchbase/manifest -m released/3.1.1.xml

Traceback (most recent call last):
File "/root/couchbase/.repo/repo/main.py", line 526, in <module>
_Main(sys.argv[1:])
File "/root/couchbase/.repo/repo/main.py", line 502, in _Main
result = repo._Run(argv) or 0
File "/root/couchbase/.repo/repo/main.py", line 175, in _Run
result = cmd.Execute(copts, cargs)
File "/root/couchbase/.repo/repo/subcmds/init.py", line 395, in Execute
self._ConfigureUser()
File "/root/couchbase/.repo/repo/subcmds/init.py", line 289, in _ConfigureUser
name = self._Prompt('Your Name', mp.UserName)
File "/root/couchbase/.repo/repo/project.py", line 703, in UserName
self._LoadUserIdentity()
File "/root/couchbase/.repo/repo/project.py", line 716, in _LoadUserIdentity
u = self.bare_git.var('GIT_COMMITTER_IDENT')
File "/root/couchbase/.repo/repo/project.py", line 2644, in runner
p.stderr))
error.GitError: manifests var:
*** Please tell me who you are.

Run

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@couchbasebsd.(none)')

Configure your git information:


# git config --global user.email "you@example.com"
# git config --global user.name "Your Name"

Try again:


# /root/bin/repo init -u git://github.com/couchbase/manifest -m released/3.1.1.xml

Your identity is: Your Name <you@example.com>
If you want to change this, please re-run 'repo init' with --config-name

[...]

repo has been initialized in /root/couchbase

Repo was initialized successfully. Let's sync!


# repo sync
[...]
Fetching projects: 100% (25/25), done.
Checking out files: 100% (2988/2988), done.ut files: 21% (641/2988)
Checking out files: 100% (11107/11107), done. files: 2% (236/11107)
Checking out files: 100% (3339/3339), done.ut files: 11% (379/3339)
Checking out files: 100% (1256/1256), done.ut files: 48% (608/1256)
Checking out files: 100% (4298/4298), done.ut files: 0% (27/4298)
Syncing work tree: 100% (25/25), done.

We now have our source environment setup.

Building



Let's invoke the makefile.


# gmake
(cd build && cmake -G "Unix Makefiles" -D CMAKE_INSTALL_PREFIX="/root/couchbase/install" -D CMAKE_PREFIX_PATH=";/root/couchbase/install" -D PRODUCT_VERSION= -D BUILD_ENTERPRISE= -D CMAKE_BUILD_TYPE=Debug ..)
cmake: not found
Makefile:42: recipe for target 'build/Makefile' failed
gmake[1]: *** [build/Makefile] Error 127
GNUmakefile:5: recipe for target 'all' failed
gmake: *** [all] Error 2

CMake is missing? Let's install it.


# make -C /usr/ports/devel/cmake install clean

Let's try again...


# gmake

CMake Error at tlm/cmake/Modules/FindCouchbaseTcMalloc.cmake:38 (MESSAGE):
Can not find tcmalloc. Exiting.
Call Stack (most recent call first):
tlm/cmake/Modules/CouchbaseMemoryAllocator.cmake:3 (INCLUDE)
tlm/cmake/Modules/CouchbaseSingleModuleBuild.cmake:11 (INCLUDE)
CMakeLists.txt:12 (INCLUDE)

-- Configuring incomplete, errors occurred!
See also "/root/couchbase/build/CMakeFiles/CMakeOutput.log".
Makefile:42: recipe for target 'build/Makefile' failed
gmake[1]: *** [build/Makefile] Error 1
GNUmakefile:5: recipe for target 'all' failed
gmake: *** [all] Error 2

What the hell is the system looking for?


# cat tlm/cmake/Modules/FindCouchbaseTcMalloc.cmake
[...]
FIND_PATH(TCMALLOC_INCLUDE_DIR gperftools/malloc_hook_c.h
PATHS
${_gperftools_exploded}/include)
[...]

Where is that malloc_hook_c.h?


# grep -R gperftools/malloc_hook_c.h *
gperftools/Makefile.am: src/gperftools/malloc_hook_c.h \
gperftools/Makefile.am: src/gperftools/malloc_hook_c.h \
gperftools/Makefile.am:## src/gperftools/malloc_hook_c.h \
gperftools/src/google/malloc_hook_c.h:#warning "google/malloc_hook_c.h is deprecated. Use gperftools/malloc_hook_c.h instead"
gperftools/src/google/malloc_hook_c.h:#include <gperftools/malloc_hook_c.h>
gperftools/src/gperftools/malloc_hook.h:#include <gperftools/malloc_hook_c.h> // a C version of the malloc_hook interface
gperftools/src/tests/malloc_extension_c_test.c:#include <gperftools/malloc_hook_c.h>
[...]

It's in directory gperftools. Let's build that module first.


# cd gperftools/

# ./autogen.sh

# ./configure
[...]
config.status: creating Makefile
config.status: creating src/gperftools/tcmalloc.h
config.status: creating src/windows/gperftools/tcmalloc.h
config.status: creating src/config.h
config.status: executing depfiles commands
config.status: executing libtool commands

# make && make install

Let's try to build again.


# cd ..

# make
CMake Error at tlm/cmake/Modules/FindCouchbaseIcu.cmake:108 (MESSAGE):
Can't build Couchbase without ICU
Call Stack (most recent call first):
tlm/cmake/Modules/CouchbaseSingleModuleBuild.cmake:16 (INCLUDE)
CMakeLists.txt:12 (INCLUDE)

ICU is missing? Let's install it.


# make -C /usr/ports/devel/icu install clean

Let's try again.


# make
CMake Error at tlm/cmake/Modules/FindCouchbaseSnappy.cmake:34 (MESSAGE):
Can't build Couchbase without Snappy
Call Stack (most recent call first):
tlm/cmake/Modules/CouchbaseSingleModuleBuild.cmake:17 (INCLUDE)
CMakeLists.txt:12 (INCLUDE)

snappy is missing? Let's install it.


# make -C /usr/ports/archivers/snappy install

Do not make the mistake of installing multimedia/snappy instead. This is a totally unrelated module, and it will install 175 crappy Linux/X11 dependencies on your system.

Let's try again:


# gmake
CMake Error at tlm/cmake/Modules/FindCouchbaseV8.cmake:52 (MESSAGE):
Can't build Couchbase without V8
Call Stack (most recent call first):
tlm/cmake/Modules/CouchbaseSingleModuleBuild.cmake:18 (INCLUDE)
CMakeLists.txt:12 (INCLUDE)

V8 is missing? Let's install it.


# make -C /usr/ports/lang/v8 install clean

Let's try again.


# gmake
CMake Error at tlm/cmake/Modules/FindCouchbaseErlang.cmake:80 (MESSAGE):
Erlang not found - cannot continue building
Call Stack (most recent call first):
tlm/cmake/Modules/CouchbaseSingleModuleBuild.cmake:21 (INCLUDE)
CMakeLists.txt:12 (INCLUDE)

Erlang FTW!


# make -C /usr/ports/lang/erlang install clean

Let's build again.


/root/couchbase/platform/src/cb_time.c:60:2: error: "Don't know how to build cb_get_monotonic_seconds"
#error "Don't know how to build cb_get_monotonic_seconds"
^
1 error generated.
platform/CMakeFiles/platform.dir/build.make:169: recipe for target 'platform/CMakeFiles/platform.dir/src/cb_time.c.o' failed
gmake[4]: *** [platform/CMakeFiles/platform.dir/src/cb_time.c.o] Error 1
CMakeFiles/Makefile2:285: recipe for target 'platform/CMakeFiles/platform.dir/all' failed
gmake[3]: *** [platform/CMakeFiles/platform.dir/all] Error 2
Makefile:126: recipe for target 'all' failed
gmake[2]: *** [all] Error 2
Makefile:36: recipe for target 'compile' failed
gmake[1]: *** [compile] Error 2
GNUmakefile:5: recipe for target 'all' failed
gmake: *** [all] Error 2

At last! A real error. Let's see the code.

# cat platform/src/cb_time.c

/*
return a monotonically increasing value with a seconds frequency.
*/
uint64_t cb_get_monotonic_seconds() {
uint64_t seconds = 0;
#if defined(WIN32)
/* GetTickCound64 gives us near 60years of ticks...*/
seconds = (GetTickCount64() / 1000);
#elif defined(__APPLE__)
uint64_t time = mach_absolute_time();

static mach_timebase_info_data_t timebase;
if (timebase.denom == 0) {
mach_timebase_info(&timebase);
}

seconds = (double)time * timebase.numer / timebase.denom * 1e-9;
#elif defined(__linux__) || defined(__sun)
/* Linux and Solaris can use clock_gettime */
struct timespec tm;
if (clock_gettime(CLOCK_MONOTONIC, &tm) == -1) {
abort();
}
seconds = tm.tv_sec;
#else
#error "Don't know how to build cb_get_monotonic_seconds"
#endif

return seconds;
}

FreeBSD also has clock_gettime, so let's patch the file:


diff -u platform/src/cb_time.c.orig platform/src/cb_time.c
--- platform/src/cb_time.c.orig 2015-10-07 19:26:14.258513000 +0200
+++ platform/src/cb_time.c 2015-10-07 19:26:29.768324000 +0200
@@ -49,7 +49,7 @@
}

seconds = (double)time * timebase.numer / timebase.denom * 1e-9;
-#elif defined(__linux__) || defined(__sun)
+#elif defined(__linux__) || defined(__sun) || defined(__FreeBSD__)
/* Linux and Solaris can use clock_gettime */
struct timespec tm;
if (clock_gettime(CLOCK_MONOTONIC, &tm) == -1) {

Next error, please.


# gmake
Linking CXX shared library libplatform.so
/usr/bin/ld: cannot find -ldl
CC: error: linker command failed with exit code 1 (use -v to see invocation)
platform/CMakeFiles/platform.dir/build.make:210: recipe for target 'platform/libplatform.so.0.1.0' failed
gmake[4]: *** [platform/libplatform.so.0.1.0] Error 1

Aaah, good old Linux dl library. Let's get rid of that in the Makefile:


diff -u CMakeLists.txt.orig CMakeLists.txt
--- CMakeLists.txt.orig 2015-10-07 19:30:45.546580000 +0200
+++ CMakeLists.txt 2015-10-07 19:36:27.052693000 +0200
@@ -34,7 +34,9 @@
ELSE (WIN32)
SET(PLATFORM_FILES src/cb_pthreads.c src/urandom.c)
SET(THREAD_LIBS "pthread")
- SET(DLOPENLIB "dl")
+ IF(NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ SET(DLOPENLIB "dl")
+ ENDIF(NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")

IF (NOT APPLE)
SET(RTLIB "rt")

Next!

FreeBSD has Dtrace, but not the same as Solaris, so we must disable it.

Someone already did that: see commit Disable DTrace for FreeBSD for the patch:


--- a/cmake/Modules/FindCouchbaseDtrace.cmake
+++ b/cmake/Modules/FindCouchbaseDtrace.cmake
@@ -1,18 +1,19 @@
-# stupid systemtap use a binary named dtrace as well..
+# stupid systemtap use a binary named dtrace as well, but it's not dtrace
+IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ IF (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ MESSAGE(STATUS "We don't have support for DTrace on FreeBSD")
+ ELSE (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ FIND_PROGRAM(DTRACE dtrace)
+ IF (DTRACE)
+ SET(ENABLE_DTRACE True CACHE BOOL "Whether DTrace has been found")
+ MESSAGE(STATUS "Found dtrace in ${DTRACE}")

-IF (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ IF (CMAKE_SYSTEM_NAME MATCHES "SunOS")
+ SET(DTRACE_NEED_INSTUMENT True CACHE BOOL
+ "Whether DTrace should instrument object files")
+ ENDIF (CMAKE_SYSTEM_NAME MATCHES "SunOS")
+ ENDIF (DTRACE)

-FIND_PROGRAM(DTRACE dtrace)
-IF (DTRACE)
- SET(ENABLE_DTRACE True CACHE BOOL "Whether DTrace has been found")
- MESSAGE(STATUS "Found dtrace in ${DTRACE}")
-
- IF (CMAKE_SYSTEM_NAME MATCHES "SunOS")
- SET(DTRACE_NEED_INSTUMENT True CACHE BOOL
- "Whether DTrace should instrument object files")
- ENDIF (CMAKE_SYSTEM_NAME MATCHES "SunOS")
-ENDIF (DTRACE)
-
-MARK_AS_ADVANCED(DTRACE_NEED_INSTUMENT ENABLE_DTRACE DTRACE)
-
-ENDIF (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ MARK_AS_ADVANCED(DTRACE_NEED_INSTUMENT ENABLE_DTRACE DTRACE)
+ ENDIF (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ENDIF (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")

Next!


# gmake
Linking C executable couch_compact
libcouchstore.so: undefined reference to `fdatasync'
cc: error: linker command failed with exit code 1 (use -v to see invocation)
couchstore/CMakeFiles/couch_compact.dir/build.make:89: recipe for target 'couchstore/couch_compact' failed
gmake[4]: *** [couchstore/couch_compact] Error 1
CMakeFiles/Makefile2:1969: recipe for target 'couchstore/CMakeFiles/couch_compact.dir/all' failed

FreeBSD does not have fdatasync. Instead, we should use fsync:


diff -u couchstore/config.cmake.h.in.orig couchstore/config.cmake.h.in
--- couchstore/config.cmake.h.in.orig 2015-10-07 19:56:05.461932000 +0200
+++ couchstore/config.cmake.h.in 2015-10-07 19:56:42.973040000 +0200
@@ -38,10 +38,10 @@
#include <unistd.h>
#endif

-#ifdef __APPLE__
-/* autoconf things OS X has fdatasync but it doesn't */
+#if defined(__APPLE__) || defined(__FreeBSD__)
+/* autoconf things OS X and FreeBSD have fdatasync but they don't */
#define fdatasync(FD) fsync(FD)
-#endif /* __APPLE__ */
+#endif /* __APPLE__ || __FreeBSD__ */

#include <platform/platform.h>

Next!


[ 56%] Building C object sigar/build-src/CMakeFiles/sigar.dir/sigar.c.o
/root/couchbase/sigar/src/sigar.c:1071:12: fatal error: 'utmp.h' file not found
# include <utmp.h>
^
1 error generated.
sigar/build-src/CMakeFiles/sigar.dir/build.make:77: recipe for target 'sigar/build-src/CMakeFiles/sigar.dir/sigar.c.o' failed
gmake[4]: *** [sigar/build-src/CMakeFiles/sigar.dir/sigar.c.o] Error 1
CMakeFiles/Makefile2:4148: recipe for target 'sigar/build-src/CMakeFiles/sigar.dir/all' failed

I was planning to port that file to utmpx, and then I wondered how the freebsd port of the library (java/sigar) was working. Then I found the patch has already been done:

Commit "Make utmp-handling more standards-compliant. " on Github -> amishHammer -> sigar (https://github.com/amishHammer/sigar/commit/67b476efe0f2a7c644f3966b79f5e358f67752e9)


diff --git a/src/sigar.c b/src/sigar.c
index 8bd7e91..7f76dfd 100644
--- a/src/sigar.c
+++ b/src/sigar.c
@@ -30,6 +30,11 @@
#ifndef WIN32
#include <arpa/inet.h>
#endif
+#if defined(HAVE_UTMPX_H)
+# include <utmpx.h>
+#elif defined(HAVE_UTMP_H)
+# include <utmp.h>
+#endif

#include "sigar.h"
#include "sigar_private.h"
@@ -1024,40 +1029,7 @@ SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar,
return SIGAR_OK;
}

-#ifdef DARWIN
-#include <AvailabilityMacros.h>
-#endif
-#ifdef MAC_OS_X_VERSION_10_5
-# if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
-# define SIGAR_NO_UTMP
-# endif
-/* else 10.4 and earlier or compiled with -mmacosx-version-min=10.3 */
-#endif
-
-#if defined(__sun)
-# include <utmpx.h>
-# define SIGAR_UTMP_FILE _UTMPX_FILE
-# define ut_time ut_tv.tv_sec
-#elif defined(WIN32)
-/* XXX may not be the default */
-#define SIGAR_UTMP_FILE "C:\\cygwin\\var\\run\\utmp"
-#define UT_LINESIZE 16
-#define UT_NAMESIZE 16
-#define UT_HOSTSIZE 256
-#define UT_IDLEN 2
-#define ut_name ut_user
-
-struct utmp {
- short ut_type;
- int ut_pid;
- char ut_line[UT_LINESIZE];
- char ut_id[UT_IDLEN];
- time_t ut_time;
- char ut_user[UT_NAMESIZE];
- char ut_host[UT_HOSTSIZE];
- long ut_addr;
-};
-#elif defined(NETWARE)
+#if defined(NETWARE)
static char *getpass(const char *prompt)
{
static char password[BUFSIZ];
@@ -1067,109 +1039,48 @@ static char *getpass(const char *prompt)

return (char *)&password;
}
-#elif !defined(SIGAR_NO_UTMP)
-# include <utmp.h>
-# ifdef UTMP_FILE
-# define SIGAR_UTMP_FILE UTMP_FILE
-# else
-# define SIGAR_UTMP_FILE _PATH_UTMP
-# endif
-#endif
-
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(DARWIN)
-# define ut_user ut_name
#endif

-#ifdef DARWIN
-/* XXX from utmpx.h; sizeof changed in 10.5 */
-/* additionally, utmpx does not work on 10.4 */
-#define SIGAR_HAS_UTMPX
-#define _PATH_UTMPX "/var/run/utmpx"
-#define _UTX_USERSIZE 256 /* matches MAXLOGNAME */
-#define _UTX_LINESIZE 32
-#define _UTX_IDSIZE 4
-#define _UTX_HOSTSIZE 256
-struct utmpx {
- char ut_user[_UTX_USERSIZE]; /* login name */
- char ut_id[_UTX_IDSIZE]; /* id */
- char ut_line[_UTX_LINESIZE]; /* tty name */
- pid_t ut_pid; /* process id creating the entry */
- short ut_type; /* type of this entry */
- struct timeval ut_tv; /* time entry was created */
- char ut_host[_UTX_HOSTSIZE]; /* host name */
- __uint32_t ut_pad[16]; /* reserved for future use */
-};
-#define ut_xtime ut_tv.tv_sec
-#define UTMPX_USER_PROCESS 7
-/* end utmpx.h */
-#define SIGAR_UTMPX_FILE _PATH_UTMPX
-#endif
-
-#if !defined(NETWARE) && !defined(_AIX)
-
#define WHOCPY(dest, src) \
SIGAR_SSTRCPY(dest, src); \
if (sizeof(src) < sizeof(dest)) \
dest[sizeof(src)] = '\0'

-#ifdef SIGAR_HAS_UTMPX
-static int sigar_who_utmpx(sigar_t *sigar,
- sigar_who_list_t *wholist)
+static int sigar_who_utmp(sigar_t *sigar,
+ sigar_who_list_t *wholist)
{
- FILE *fp;
- struct utmpx ut;
+#if defined(HAVE_UTMPX_H)
+ struct utmpx *ut;

- if (!(fp = fopen(SIGAR_UTMPX_FILE, "r"))) {
- return errno;
- }
+ setutxent();

- while (fread(&ut, sizeof(ut), 1, fp) == 1) {
+ while ((ut = getutxent()) != NULL) {
sigar_who_t *who;

- if (*ut.ut_user == '\0') {
+ if (*ut->ut_user == '\0') {
continue;
}

-#ifdef UTMPX_USER_PROCESS
- if (ut.ut_type != UTMPX_USER_PROCESS) {
+ if (ut->ut_type != USER_PROCESS) {
continue;
}
-#endif

SIGAR_WHO_LIST_GROW(wholist);
who = &wholist->data[wholist->number++];

- WHOCPY(who->user, ut.ut_user);
- WHOCPY(who->device, ut.ut_line);
- WHOCPY(who->host, ut.ut_host);
+ WHOCPY(who->user, ut->ut_user);
+ WHOCPY(who->device, ut->ut_line);
+ WHOCPY(who->host, ut->ut_host);

- who->time = ut.ut_xtime;
+ who->time = ut->ut_tv.tv_sec;
}

- fclose(fp);
-
- return SIGAR_OK;
-}
-#endif
-
-#if defined(SIGAR_NO_UTMP) && defined(SIGAR_HAS_UTMPX)
-#define sigar_who_utmp sigar_who_utmpx
-#else
-static int sigar_who_utmp(sigar_t *sigar,
- sigar_who_list_t *wholist)
-{
+ endutxent();
+#elif defined(HAVE_UTMP_H)
FILE *fp;
-#ifdef __sun
- /* use futmpx w/ pid32_t for sparc64 */
- struct futmpx ut;
-#else
struct utmp ut;
-#endif
- if (!(fp = fopen(SIGAR_UTMP_FILE, "r"))) {
-#ifdef SIGAR_HAS_UTMPX
- /* Darwin 10.5 */
- return sigar_who_utmpx(sigar, wholist);
-#endif
+
+ if (!(fp = fopen(_PATH_UTMP, "r"))) {
return errno;
}

@@ -1189,7 +1100,7 @@ static int sigar_who_utmp(sigar_t *sigar,
SIGAR_WHO_LIST_GROW(wholist);
who = &wholist->data[wholist->number++];

- WHOCPY(who->user, ut.ut_user);
+ WHOCPY(who->user, ut.ut_name);
WHOCPY(who->device, ut.ut_line);
WHOCPY(who->host, ut.ut_host);

@@ -1197,11 +1108,10 @@ static int sigar_who_utmp(sigar_t *sigar,
}

fclose(fp);
+#endif

return SIGAR_OK;
}
-#endif /* SIGAR_NO_UTMP */
-#endif /* NETWARE */

#if defined(WIN32)

Next!


# gmake
[ 75%] Generating couch_btree.beam
compile: warnings being treated as errors
/root/couchbase/couchdb/src/couchdb/couch_btree.erl:415: variable 'NodeList' exported from 'case' (line 391)
/root/couchbase/couchdb/src/couchdb/couch_btree.erl:1010: variable 'NodeList' exported from 'case' (line 992)
couchdb/src/couchdb/CMakeFiles/couchdb.dir/build.make:151: recipe for target 'couchdb/src/couchdb/couch_btree.beam' failed
gmake[4]: *** [couchdb/src/couchdb/couch_btree.beam] Error 1
CMakeFiles/Makefile2:5531: recipe for target 'couchdb/src/couchdb/CMakeFiles/couchdb.dir/all' failed

Fortunately, I'm fluent in Erlang.

I'm not sure why compiler option +warn_export_vars was set if the code does contains such errors. Let's fix them.


diff -u /root/couchbase/couchdb/src/couchdb/couch_btree.erl /root/couchbase/couchdb/src/couchdb/couch_btree.erl.orig
--- /root/couchbase/couchdb/src/couchdb/couch_btree.erl 2015-10-07 22:01:05.191344000 +0200
+++ /root/couchbase/couchdb/src/couchdb/couch_btree.erl.orig 2015-10-07 21:59:43.359322000 +0200
@@ -388,12 +388,13 @@
end.

modify_node(Bt, RootPointerInfo, Actions, QueryOutput, Acc, PurgeFun, PurgeFunAcc, KeepPurging) ->
- {NodeType, NodeList} = case RootPointerInfo of
+ case RootPointerInfo of
nil ->
- {kv_node, []};
+ NodeType = kv_node,
+ NodeList = [];
_Tuple ->
Pointer = element(1, RootPointerInfo),
- get_node(Bt, Pointer)
+ {NodeType, NodeList} = get_node(Bt, Pointer)
end,

case NodeType of
@@ -988,12 +989,13 @@

guided_purge(Bt, NodeState, GuideFun, GuideAcc) ->
% inspired by modify_node/5
- {NodeType, NodeList} = case NodeState of
+ case NodeState of
nil ->
- {kv_node, []};
+ NodeType = kv_node,
+ NodeList = [];
_Tuple ->
Pointer = element(1, NodeState),
- get_node(Bt, Pointer)
+ {NodeType, NodeList} = get_node(Bt, Pointer)
end,
{ok, NewNodeList, GuideAcc2, Bt2, Go} =
case NodeType of

diff -u /root/couchbase/couchdb/src/couchdb/couch_compaction_daemon.erl.orig /root/couchbase/couchdb/src/couchdb/couch_compaction_daemon.erl
--- /root/couchbase/couchdb/src/couchdb/couch_compaction_daemon.erl.orig 2015-10-07 22:01:48.495966000 +0200
+++ /root/couchbase/couchdb/src/couchdb/couch_compaction_daemon.erl 2015-10-07 22:02:15.620989000 +0200
@@ -142,14 +142,14 @@
true ->
{ok, DbCompactPid} = couch_db:start_compact(Db),
TimeLeft = compact_time_left(Config),
- case Config#config.parallel_view_compact of
+ ViewsMonRef = case Config#config.parallel_view_compact of
true ->
ViewsCompactPid = spawn_link(fun() ->
maybe_compact_views(DbName, DDocNames, Config)
end),
- ViewsMonRef = erlang:monitor(process, ViewsCompactPid);
+ erlang:monitor(process, ViewsCompactPid);
false ->
- ViewsMonRef = nil
+ nil
end,
DbMonRef = erlang:monitor(process, DbCompactPid),
receive

Next!


[ 84%] Generating ebin/couch_set_view_group.beam
/root/couchbase/couchdb/src/couch_set_view/src/couch_set_view_group.erl:3178: type dict() undefined
couchdb/src/couch_set_view/CMakeFiles/couch_set_view.dir/build.make:87: recipe for target 'couchdb/src/couch_set_view/ebin/couch_set_view_group.beam' failed
gmake[4]: *** [couchdb/src/couch_set_view/ebin/couch_set_view_group.beam] Error 1
CMakeFiles/Makefile2:5720: recipe for target 'couchdb/src/couch_set_view/CMakeFiles/couch_set_view.dir/all' failed
gmake[3]: *** [couchdb/src/couch_set_view/CMakeFiles/couch_set_view.dir/all] Error 2

Those happen since I'm building the project with Erlang 18. I guess I wouldn't have had them with version 17.

Anyway, let's fix them.


--- couchdb.orig/src/couch_dcp/src/couch_dcp_client.erl 2015-10-08 11:26:37.034138000 +0200
+++ couchdb/src/couch_dcp/src/couch_dcp_client.erl 2015-10-07 22:07:35.556126000 +0200
@@ -47,13 +47,13 @@
bufsocket = nil :: #bufsocket{} | nil,
timeout = 5000 :: timeout(),
request_id = 0 :: request_id(),
- pending_requests = dict:new() :: dict(),
- stream_queues = dict:new() :: dict(),
+ pending_requests = dict:new() :: dict:dict(),
+ stream_queues = dict:new() :: dict:dict(),
active_streams = [] :: list(),
worker_pid :: pid(),
max_buffer_size = ?MAX_BUF_SIZE :: integer(),
total_buffer_size = 0 :: non_neg_integer(),
- stream_info = dict:new() :: dict(),
+ stream_info = dict:new() :: dict:dict(),
args = [] :: list()
}).

@@ -1378,7 +1378,7 @@
{error, Error}
end.

--spec get_queue_size(queue(), non_neg_integer()) -> non_neg_integer().
+-spec get_queue_size(queue:queue(), non_neg_integer()) -> non_neg_integer().
get_queue_size(EvQueue, Size) ->
case queue:out(EvQueue) of
{empty, _} ->
diff -r -u couchdb.orig/src/couch_set_view/src/couch_set_view_group.erl couchdb/src/couch_set_view/src/couch_set_view_group.erl
--- couchdb.orig/src/couch_set_view/src/couch_set_view_group.erl 2015-10-08 11:26:37.038856000 +0200
+++ couchdb/src/couch_set_view/src/couch_set_view_group.erl 2015-10-07 22:04:53.198951000 +0200
@@ -118,7 +118,7 @@
auto_transfer_replicas = true :: boolean(),
replica_partitions = [] :: ordsets:ordset(partition_id()),
pending_transition_waiters = [] :: [{From::{pid(), reference()}, #set_view_group_req{}}],
- update_listeners = dict:new() :: dict(),
+ update_listeners = dict:new() :: dict:dict(),
compact_log_files = nil :: 'nil' | {[[string()]], partition_seqs(), partition_versions()},
timeout = ?DEFAULT_TIMEOUT :: non_neg_integer() | 'infinity'
}).
@@ -3136,7 +3136,7 @@
}.


--spec notify_update_listeners(#state{}, dict(), #set_view_group{}) -> dict().
+-spec notify_update_listeners(#state{}, dict:dict(), #set_view_group{}) -> dict:dict().
notify_update_listeners(State, Listeners, NewGroup) ->
case dict:size(Listeners) == 0 of
true ->
@@ -3175,7 +3175,7 @@
end.


--spec error_notify_update_listeners(#state{}, dict(), monitor_error()) -> dict().
+-spec error_notify_update_listeners(#state{}, dict:dict(), monitor_error()) -> dict:dict().
error_notify_update_listeners(State, Listeners, Error) ->
_ = dict:fold(
fun(Ref, #up_listener{pid = ListPid, partition = PartId}, _Acc) ->
diff -r -u couchdb.orig/src/couch_set_view/src/mapreduce_view.erl couchdb/src/couch_set_view/src/mapreduce_view.erl
--- couchdb.orig/src/couch_set_view/src/mapreduce_view.erl 2015-10-08 11:26:37.040295000 +0200
+++ couchdb/src/couch_set_view/src/mapreduce_view.erl 2015-10-07 22:05:56.157242000 +0200
@@ -109,7 +109,7 @@
convert_primary_index_kvs_to_binary(Rest, Group, [{KeyBin, V} | Acc]).


--spec finish_build(#set_view_group{}, dict(), string()) ->
+-spec finish_build(#set_view_group{}, dict:dict(), string()) ->
{#set_view_group{}, pid()}.
finish_build(Group, TmpFiles, TmpDir) ->
#set_view_group{
diff -r -u couchdb.orig/src/couchdb/couch_btree.erl couchdb/src/couchdb/couch_btree.erl
--- couchdb.orig/src/couchdb/couch_btree.erl 2015-10-08 11:26:37.049320000 +0200
+++ couchdb/src/couchdb/couch_btree.erl 2015-10-07 22:01:05.191344000 +0200
@@ -388,13 +388,12 @@
end.

modify_node(Bt, RootPointerInfo, Actions, QueryOutput, Acc, PurgeFun, PurgeFunAcc, KeepPurging) ->
- case RootPointerInfo of
+ {NodeType, NodeList} = case RootPointerInfo of
nil ->
- NodeType = kv_node,
- NodeList = [];
+ {kv_node, []};
_Tuple ->
Pointer = element(1, RootPointerInfo),
- {NodeType, NodeList} = get_node(Bt, Pointer)
+ get_node(Bt, Pointer)
end,

case NodeType of
@@ -989,13 +988,12 @@

guided_purge(Bt, NodeState, GuideFun, GuideAcc) ->
% inspired by modify_node/5
- case NodeState of
+ {NodeType, NodeList} = case NodeState of
nil ->
- NodeType = kv_node,
- NodeList = [];
+ {kv_node, []};
_Tuple ->
Pointer = element(1, NodeState),
- {NodeType, NodeList} = get_node(Bt, Pointer)
+ get_node(Bt, Pointer)
end,
{ok, NewNodeList, GuideAcc2, Bt2, Go} =
case NodeType of
diff -r -u couchdb.orig/src/couchdb/couch_compaction_daemon.erl couchdb/src/couchdb/couch_compaction_daemon.erl
--- couchdb.orig/src/couchdb/couch_compaction_daemon.erl 2015-10-08 11:26:37.049734000 +0200
+++ couchdb/src/couchdb/couch_compaction_daemon.erl 2015-10-07 22:02:15.620989000 +0200
@@ -142,14 +142,14 @@
true ->
{ok, DbCompactPid} = couch_db:start_compact(Db),
TimeLeft = compact_time_left(Config),
- case Config#config.parallel_view_compact of
+ ViewsMonRef = case Config#config.parallel_view_compact of
true ->
ViewsCompactPid = spawn_link(fun() ->
maybe_compact_views(DbName, DDocNames, Config)
end),
- ViewsMonRef = erlang:monitor(process, ViewsCompactPid);
+ erlang:monitor(process, ViewsCompactPid);
false ->
- ViewsMonRef = nil
+ nil
end,
DbMonRef = erlang:monitor(process, DbCompactPid),
receive



[ 98%] Generating ebin/vtree_cleanup.beam
compile: warnings being treated as errors
/root/couchbase/geocouch/vtree/src/vtree_cleanup.erl:32: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
/root/couchbase/geocouch/vtree/src/vtree_cleanup.erl:42: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
../geocouch/build/vtree/CMakeFiles/vtree.dir/build.make:64: recipe for target '../geocouch/build/vtree/ebin/vtree_cleanup.beam' failed
gmake[4]: *** [../geocouch/build/vtree/ebin/vtree_cleanup.beam] Error 1
CMakeFiles/Makefile2:6702: recipe for target '../geocouch/build/vtree/CMakeFiles/vtree.dir/all' failed
gmake[3]: *** [../geocouch/build/vtree/CMakeFiles/vtree.dir/all] Error 2


diff -r -u geocouch.orig/gc-couchbase/src/spatial_view.erl geocouch/gc-couchbase/src/spatial_view.erl
--- geocouch.orig/gc-couchbase/src/spatial_view.erl 2015-10-08 11:29:05.323361000 +0200
+++ geocouch/gc-couchbase/src/spatial_view.erl 2015-10-07 22:17:09.741790000 +0200
@@ -166,7 +166,7 @@


% Build the tree out of the sorted files
--spec finish_build(#set_view_group{}, dict(), string()) ->
+-spec finish_build(#set_view_group{}, dict:dict(), string()) ->
{#set_view_group{}, pid()}.
finish_build(Group, TmpFiles, TmpDir) ->
#set_view_group{
diff -r -u geocouch.orig/vtree/src/vtree_cleanup.erl geocouch/vtree/src/vtree_cleanup.erl
--- geocouch.orig/vtree/src/vtree_cleanup.erl 2015-10-08 11:29:05.327423000 +0200
+++ geocouch/vtree/src/vtree_cleanup.erl 2015-10-07 22:12:26.915600000 +0200
@@ -29,7 +29,7 @@
cleanup(#vtree{root=nil}=Vt, _Nodes) ->
Vt;
cleanup(Vt, Nodes) ->
- T1 = now(),
+ T1 = erlang:monotonic_time(seconds),
Root = Vt#vtree.root,
PartitionedNodes = [Nodes],
KpNodes = cleanup_multiple(Vt, PartitionedNodes, [Root]),
@@ -39,7 +39,7 @@
vtree_modify:write_new_root(Vt, KpNodes)
end,
?LOG_DEBUG("Cleanup took: ~ps~n",
- [timer:now_diff(now(), T1)/1000000]),
+ [erlang:monotonic_time(seconds) - T1]),
Vt#vtree{root=NewRoot}.

-spec cleanup_multiple(Vt :: #vtree{}, ToCleanup :: [#kv_node{}],
diff -r -u geocouch.orig/vtree/src/vtree_delete.erl geocouch/vtree/src/vtree_delete.erl
--- geocouch.orig/vtree/src/vtree_delete.erl 2015-10-08 11:29:05.327537000 +0200
+++ geocouch/vtree/src/vtree_delete.erl 2015-10-07 22:13:51.733064000 +0200
@@ -30,7 +30,7 @@
delete(#vtree{root=nil}=Vt, _Nodes) ->
Vt;
delete(Vt, Nodes) ->
- T1 = now(),
+ T1 = erlang:monotonic_time(seconds),
Root = Vt#vtree.root,
PartitionedNodes = [Nodes],
KpNodes = delete_multiple(Vt, PartitionedNodes, [Root]),
@@ -40,7 +40,7 @@
vtree_modify:write_new_root(Vt, KpNodes)
end,
?LOG_DEBUG("Deletion took: ~ps~n",
- [timer:now_diff(now(), T1)/1000000]),
+ [erlang:monotonic_time(seconds) - T1]),
Vt#vtree{root=NewRoot}.


diff -r -u geocouch.orig/vtree/src/vtree_insert.erl geocouch/vtree/src/vtree_insert.erl
--- geocouch.orig/vtree/src/vtree_insert.erl 2015-10-08 11:29:05.327648000 +0200
+++ geocouch/vtree/src/vtree_insert.erl 2015-10-07 22:15:50.812447000 +0200
@@ -26,7 +26,7 @@
insert(Vt, []) ->
Vt;
insert(#vtree{root=nil}=Vt, Nodes) ->
- T1 = now(),
+ T1 = erlang:monotonic_time(seconds),
% If we would do single inserts, the first node that was inserted would
% have set the original Mbb `MbbO`
MbbO = (hd(Nodes))#kv_node.key,
@@ -48,7 +48,7 @@
ArbitraryBulkSize = round(math:log(Threshold)+50),
Vt3 = insert_in_bulks(Vt2, Rest, ArbitraryBulkSize),
?LOG_DEBUG("Insertion into empty tree took: ~ps~n",
- [timer:now_diff(now(), T1)/1000000]),
+ [erlang:monotonic_time(seconds) - T1]),
?LOG_DEBUG("Root pos: ~p~n", [(Vt3#vtree.root)#kp_node.childpointer]),
Vt3;
false ->
@@ -56,13 +56,13 @@
Vt#vtree{root=Root}
end;
insert(Vt, Nodes) ->
- T1 = now(),
+ T1 = erlang:monotonic_time(seconds),
Root = Vt#vtree.root,
PartitionedNodes = [Nodes],
KpNodes = insert_multiple(Vt, PartitionedNodes, [Root]),
NewRoot = vtree_modify:write_new_root(Vt, KpNodes),
?LOG_DEBUG("Insertion into existing tree took: ~ps~n",
- [timer:now_diff(now(), T1)/1000000]),
+ [erlang:monotonic_time(seconds) - T1]),
Vt#vtree{root=NewRoot}.


diff -u ns_server/deps/ale/src/ale.erl.orig ns_server/deps/ale/src/ale.erl
--- ns_server/deps/ale/src/ale.erl.orig 2015-10-07 22:19:28.730212000 +0200
+++ ns_server/deps/ale/src/ale.erl 2015-10-07 22:20:09.788761000 +0200
@@ -45,12 +45,12 @@

-include("ale.hrl").

--record(state, {sinks :: dict(),
- loggers :: dict()}).
+-record(state, {sinks :: dict:dict(),
+ loggers :: dict:dict()}).

-record(logger, {name :: atom(),
loglevel :: loglevel(),
- sinks :: dict(),
+ sinks :: dict:dict(),
formatter :: module()}).

-record(sink, {name :: atom(),


==> ns_babysitter (compile)
src/ns_crash_log.erl:18: type queue() undefined
../ns_server/build/deps/ns_babysitter/CMakeFiles/ns_babysitter.dir/build.make:49: recipe for target '../ns_server/build/deps/ns_babysitter/CMakeFiles/ns_babysitter' failed
gmake[4]: *** [../ns_server/build/deps/ns_babysitter/CMakeFiles/ns_babysitter] Error 1
CMakeFiles/Makefile2:7484: recipe for target '../ns_server/build/deps/ns_babysitter/CMakeFiles/ns_babysitter.dir/all' failed
gmake[3]: *** [../ns_server/build/deps/ns_babysitter/CMakeFiles/ns_babysitter.dir/all] Error 2


diff -r -u ns_server.orig/deps/ale/src/ale.erl ns_server/deps/ale/src/ale.erl
--- ns_server.orig/deps/ale/src/ale.erl 2015-10-08 11:31:20.520281000 +0200
+++ ns_server/deps/ale/src/ale.erl 2015-10-07 22:20:09.788761000 +0200
@@ -45,12 +45,12 @@

-include("ale.hrl").

--record(state, {sinks :: dict(),
- loggers :: dict()}).
+-record(state, {sinks :: dict:dict(),
+ loggers :: dict:dict()}).

-record(logger, {name :: atom(),
loglevel :: loglevel(),
- sinks :: dict(),
+ sinks :: dict:dict(),
formatter :: module()}).

-record(sink, {name :: atom(),
diff -r -u ns_server.orig/deps/ns_babysitter/src/ns_crash_log.erl ns_server/deps/ns_babysitter/src/ns_crash_log.erl
--- ns_server.orig/deps/ns_babysitter/src/ns_crash_log.erl 2015-10-08 11:31:20.540433000 +0200
+++ ns_server/deps/ns_babysitter/src/ns_crash_log.erl 2015-10-07 22:21:45.292975000 +0200
@@ -13,9 +13,9 @@
-define(MAX_CRASHES_LEN, 100).

-record(state, {file_path :: file:filename(),
- crashes :: queue(),
+ crashes :: queue:queue(),
crashes_len :: non_neg_integer(),
- crashes_saved :: queue(),
+ crashes_saved :: queue:queue(),
consumer_from = undefined :: undefined | {pid(), reference()},
consumer_mref = undefined :: undefined | reference()
}).
diff -r -u ns_server.orig/include/remote_clusters_info.hrl ns_server/include/remote_clusters_info.hrl
--- ns_server.orig/include/remote_clusters_info.hrl 2015-10-08 11:31:20.544760000 +0200
+++ ns_server/include/remote_clusters_info.hrl 2015-10-07 22:22:48.541494000 +0200
@@ -20,6 +20,6 @@
cluster_cert :: binary() | undefined,
server_list_nodes :: [#remote_node{}],
bucket_caps :: [binary()],
- raw_vbucket_map :: dict(),
- capi_vbucket_map :: dict(),
+ raw_vbucket_map :: dict:dict(),
+ capi_vbucket_map :: dict:dict(),
cluster_version :: {integer(), integer()}}).
diff -r -u ns_server.orig/src/auto_failover.erl ns_server/src/auto_failover.erl
--- ns_server.orig/src/auto_failover.erl 2015-10-08 11:31:21.396519000 +0200
+++ ns_server/src/auto_failover.erl 2015-10-08 11:19:43.710301000 +0200
@@ -336,7 +336,7 @@
%%

%% @doc Returns a list of nodes that should be active, but are not running.
--spec actual_down_nodes(dict(), [atom()], [{atom(), term()}]) -> [atom()].
+-spec actual_down_nodes(dict:dict(), [atom()], [{atom(), term()}]) -> [atom()].
actual_down_nodes(NodesDict, NonPendingNodes, Config) ->
% Get all buckets
BucketConfigs = ns_bucket:get_buckets(Config),
diff -r -u ns_server.orig/src/dcp_upgrade.erl ns_server/src/dcp_upgrade.erl
--- ns_server.orig/src/dcp_upgrade.erl 2015-10-08 11:31:21.400562000 +0200
+++ ns_server/src/dcp_upgrade.erl 2015-10-08 11:19:47.370353000 +0200
@@ -37,7 +37,7 @@
num_buckets :: non_neg_integer(),
bucket :: bucket_name(),
bucket_config :: term(),
- progress :: dict(),
+ progress :: dict:dict(),
workers :: [pid()]}).

start_link(Buckets) ->
diff -r -u ns_server.orig/src/janitor_agent.erl ns_server/src/janitor_agent.erl
--- ns_server.orig/src/janitor_agent.erl 2015-10-08 11:31:21.401859000 +0200
+++ ns_server/src/janitor_agent.erl 2015-10-08 11:18:09.979728000 +0200
@@ -43,7 +43,7 @@
rebalance_status = finished :: in_process | finished,
replicators_primed :: boolean(),

- apply_vbucket_states_queue :: queue(),
+ apply_vbucket_states_queue :: queue:queue(),
apply_vbucket_states_worker :: undefined | pid(),
rebalance_subprocesses_registry :: pid()}).

diff -r -u ns_server.orig/src/menelaus_web_alerts_srv.erl ns_server/src/menelaus_web_alerts_srv.erl
--- ns_server.orig/src/menelaus_web_alerts_srv.erl 2015-10-08 11:31:21.405690000 +0200
+++ ns_server/src/menelaus_web_alerts_srv.erl 2015-10-08 10:58:15.641331000 +0200
@@ -219,7 +219,7 @@

%% @doc if listening on a non localhost ip, detect differences between
%% external listening host and current node host
--spec check(atom(), dict(), list(), [{atom(),number()}]) -> dict().
+-spec check(atom(), dict:dict(), list(), [{atom(),number()}]) -> dict:dict().
check(ip, Opaque, _History, _Stats) ->
{_Name, Host} = misc:node_name_host(node()),
case can_listen(Host) of
@@ -290,7 +290,7 @@

%% @doc only check for disk usage if there has been no previous
%% errors or last error was over the timeout ago
--spec hit_rate_limit(atom(), dict()) -> true | false.
+-spec hit_rate_limit(atom(), dict:dict()) -> true | false.
hit_rate_limit(Key, Dict) ->
case dict:find(Key, Dict) of
error ->
@@ -355,7 +355,7 @@


%% @doc list of buckets thats measured stats have increased
--spec stat_increased(dict(), dict()) -> list().
+-spec stat_increased(dict:dict(), dict:dict()) -> list().
stat_increased(New, Old) ->
[Bucket || {Bucket, Val} <- dict:to_list(New), increased(Bucket, Val, Old)].

@@ -392,7 +392,7 @@


%% @doc Lookup old value and test for increase
--spec increased(string(), integer(), dict()) -> true | false.
+-spec increased(string(), integer(), dict:dict()) -> true | false.
increased(Key, Val, Dict) ->
case dict:find(Key, Dict) of
error ->
diff -r -u ns_server.orig/src/misc.erl ns_server/src/misc.erl
--- ns_server.orig/src/misc.erl 2015-10-08 11:31:21.407175000 +0200
+++ ns_server/src/misc.erl 2015-10-08 10:55:15.167246000 +0200
@@ -54,7 +54,7 @@
randomize() ->
case get(random_seed) of
undefined ->
- random:seed(erlang:now());
+ random:seed(erlang:timestamp());
_ ->
ok
end.
@@ -303,8 +303,8 @@

position(E, [_|List], N) -> position(E, List, N+1).

-now_int() -> time_to_epoch_int(now()).
-now_float() -> time_to_epoch_float(now()).
+now_int() -> time_to_epoch_int(erlang:timestamp()).
+now_float() -> time_to_epoch_float(erlang:timestamp()).

time_to_epoch_int(Time) when is_integer(Time) or is_float(Time) ->
Time;
@@ -1239,7 +1239,7 @@


%% Get an item from from a dict, if it doesnt exist return default
--spec dict_get(term(), dict(), term()) -> term().
+-spec dict_get(term(), dict:dict(), term()) -> term().
dict_get(Key, Dict, Default) ->
case dict:is_key(Key, Dict) of
true -> dict:fetch(Key, Dict);
diff -r -u ns_server.orig/src/ns_doctor.erl ns_server/src/ns_doctor.erl
--- ns_server.orig/src/ns_doctor.erl 2015-10-08 11:31:21.410269000 +0200
+++ ns_server/src/ns_doctor.erl 2015-10-08 10:53:49.208657000 +0200
@@ -30,8 +30,8 @@
get_tasks_version/0, build_tasks_list/2]).

-record(state, {
- nodes :: dict(),
- tasks_hash_nodes :: undefined | dict(),
+ nodes :: dict:dict(),
+ tasks_hash_nodes :: undefined | dict:dict(),
tasks_hash :: undefined | integer(),
tasks_version :: undefined | string()
}).
@@ -112,14 +112,14 @@
RV = case dict:find(Node, Nodes) of
{ok, Status} ->
LiveNodes = [node() | nodes()],
- annotate_status(Node, Status, now(), LiveNodes);
+ annotate_status(Node, Status, erlang:timestamp(), LiveNodes);
_ ->
[]
end,
{reply, RV, State};

handle_call(get_nodes, _From, #state{nodes=Nodes} = State) ->
- Now = erlang:now(),
+ Now = erlang:timestamp(),
LiveNodes = [node()|nodes()],
Nodes1 = dict:map(
fun (Node, Status) ->
@@ -210,7 +210,7 @@
orelse OldReadyBuckets =/= NewReadyBuckets.

update_status(Name, Status0, Dict) ->
- Status = [{last_heard, erlang:now()} | Status0],
+ Status = [{last_heard, erlang:timestamp()} | Status0],
PrevStatus = case dict:find(Name, Dict) of
{ok, V} -> V;
error -> []
diff -r -u ns_server.orig/src/ns_janitor_map_recoverer.erl ns_server/src/ns_janitor_map_recoverer.erl
--- ns_server.orig/src/ns_janitor_map_recoverer.erl 2015-10-08 11:31:21.410945000 +0200
+++ ns_server/src/ns_janitor_map_recoverer.erl 2015-10-08 10:52:23.927033000 +0200
@@ -79,7 +79,7 @@
end.

-spec recover_map([{non_neg_integer(), node()}],
- dict(),
+ dict:dict(),
boolean(),
non_neg_integer(),
pos_integer(),
diff -r -u ns_server.orig/src/ns_memcached.erl ns_server/src/ns_memcached.erl
--- ns_server.orig/src/ns_memcached.erl 2015-10-08 11:31:21.411920000 +0200
+++ ns_server/src/ns_memcached.erl 2015-10-08 10:51:08.281320000 +0200
@@ -65,9 +65,9 @@
running_very_heavy = 0,
%% NOTE: otherwise dialyzer seemingly thinks it's possible
%% for queue fields to be undefined
- fast_calls_queue = impossible :: queue(),
- heavy_calls_queue = impossible :: queue(),
- very_heavy_calls_queue = impossible :: queue(),
+ fast_calls_queue = impossible :: queue:queue(),
+ heavy_calls_queue = impossible :: queue:queue(),
+ very_heavy_calls_queue = impossible :: queue:queue(),
status :: connecting | init | connected | warmed,
start_time::tuple(),
bucket::nonempty_string(),
diff -r -u ns_server.orig/src/ns_orchestrator.erl ns_server/src/ns_orchestrator.erl
--- ns_server.orig/src/ns_orchestrator.erl 2015-10-08 11:31:21.412957000 +0200
+++ ns_server/src/ns_orchestrator.erl 2015-10-08 10:45:51.967739000 +0200
@@ -251,7 +251,7 @@
not_needed |
{error, {failed_nodes, [node()]}}
when UUID :: binary(),
- RecoveryMap :: dict().
+ RecoveryMap :: dict:dict().
start_recovery(Bucket) ->
wait_for_orchestrator(),
gen_fsm:sync_send_event(?SERVER, {start_recovery, Bucket}).
@@ -260,7 +260,7 @@
when Status :: [{bucket, bucket_name()} |
{uuid, binary()} |
{recovery_map, RecoveryMap}],
- RecoveryMap :: dict().
+ RecoveryMap :: dict:dict().
recovery_status() ->
case is_recovery_running() of
false ->
@@ -271,7 +271,7 @@
end.

-spec recovery_map(bucket_name(), UUID) -> bad_recovery | {ok, RecoveryMap}
- when RecoveryMap :: dict(),
+ when RecoveryMap :: dict:dict(),
UUID :: binary().
recovery_map(Bucket, UUID) ->
wait_for_orchestrator(),
@@ -1062,7 +1062,7 @@
{next_state, FsmState, State#janitor_state{remaining_buckets = NewBucketRequests}}
end.

--spec update_progress(dict()) -> ok.
+-spec update_progress(dict:dict()) -> ok.
update_progress(Progress) ->
gen_fsm:send_event(?SERVER, {update_progress, Progress}).

diff -r -u ns_server.orig/src/ns_replicas_builder.erl ns_server/src/ns_replicas_builder.erl
--- ns_server.orig/src/ns_replicas_builder.erl 2015-10-08 11:31:21.413763000 +0200
+++ ns_server/src/ns_replicas_builder.erl 2015-10-08 10:43:03.655761000 +0200
@@ -153,7 +153,7 @@
observe_wait_all_done_old_style_loop(Bucket, SrcNode, Sleeper, NewTapNames, SleepsSoFar+1)
end.

--spec filter_true_producers(list(), set(), binary()) -> [binary()].
+-spec filter_true_producers(list(), set:set(), binary()) -> [binary()].
filter_true_producers(PList, TapNamesSet, StatName) ->
[TapName
|| {<<"eq_tapq:replication_", Key/binary>>, <<"true">>} <- PList,
diff -r -u ns_server.orig/src/ns_vbucket_mover.erl ns_server/src/ns_vbucket_mover.erl
--- ns_server.orig/src/ns_vbucket_mover.erl 2015-10-08 11:31:21.415305000 +0200
+++ ns_server/src/ns_vbucket_mover.erl 2015-10-08 10:42:02.815008000 +0200
@@ -36,14 +36,14 @@

-export([inhibit_view_compaction/3]).

--type progress_callback() :: fun((dict()) -> any()).
+-type progress_callback() :: fun((dict:dict()) -> any()).

-record(state, {bucket::nonempty_string(),
disco_events_subscription::pid(),
- map::array(),
+ map::array:array(),
moves_scheduler_state,
progress_callback::progress_callback(),
- all_nodes_set::set(),
+ all_nodes_set::set:set(),
replication_type::bucket_replication_type()}).

%%
@@ -218,14 +218,14 @@

%% @private
%% @doc Convert a map array back to a map list.
--spec array_to_map(array()) -> vbucket_map().
+-spec array_to_map(array:array()) -> vbucket_map().
array_to_map(Array) ->
array:to_list(Array).

%% @private
%% @doc Convert a map, which is normally a list, into an array so that
%% we can randomly access the replication chains.
--spec map_to_array(vbucket_map()) -> array().
+-spec map_to_array(vbucket_map()) -> array:array().
map_to_array(Map) ->
array:fix(array:from_list(Map)).

diff -r -u ns_server.orig/src/path_config.erl ns_server/src/path_config.erl
--- ns_server.orig/src/path_config.erl 2015-10-08 11:31:21.415376000 +0200
+++ ns_server/src/path_config.erl 2015-10-08 10:38:48.687500000 +0200
@@ -53,7 +53,7 @@
filename:join(component_path(NameAtom), SubPath).

tempfile(Dir, Prefix, Suffix) ->
- {_, _, MicroSecs} = erlang:now(),
+ {_, _, MicroSecs} = erlang:timestamp(),
Pid = os:getpid(),
Filename = Prefix ++ integer_to_list(MicroSecs) ++ "_" ++
Pid ++ Suffix,
diff -r -u ns_server.orig/src/recoverer.erl ns_server/src/recoverer.erl
--- ns_server.orig/src/recoverer.erl 2015-10-08 11:31:21.415655000 +0200
+++ ns_server/src/recoverer.erl 2015-10-08 10:36:46.182185000 +0200
@@ -23,16 +23,16 @@
is_recovery_complete/1]).

-record(state, {bucket_config :: list(),
- recovery_map :: dict(),
- post_recovery_chains :: dict(),
- apply_map :: array(),
- effective_map :: array()}).
+ recovery_map :: dict:dict(),
+ post_recovery_chains :: dict:dict(),
+ apply_map :: array:array(),
+ effective_map :: array:array()}).

-spec start_recovery(BucketConfig) ->
{ok, RecoveryMap, {Servers, BucketConfig}, #state{}}
| not_needed
when BucketConfig :: list(),
- RecoveryMap :: dict(),
+ RecoveryMap :: dict:dict(),
Servers :: [node()].
start_recovery(BucketConfig) ->
NumVBuckets = proplists:get_value(num_vbuckets, BucketConfig),
@@ -92,7 +92,7 @@
effective_map=array:from_list(OldMap)}}
end.

--spec get_recovery_map(#state{}) -> dict().
+-spec get_recovery_map(#state{}) -> dict:dict().
get_recovery_map(#state{recovery_map=RecoveryMap}) ->
RecoveryMap.

@@ -205,7 +205,7 @@
-define(MAX_NUM_SERVERS, 50).

compute_recovery_map_test_() ->
- random:seed(now()),
+ random:seed(erlang:timestamp()),

{timeout, 100,
{inparallel,
diff -r -u ns_server.orig/src/remote_clusters_info.erl ns_server/src/remote_clusters_info.erl
--- ns_server.orig/src/remote_clusters_info.erl 2015-10-08 11:31:21.416143000 +0200
+++ ns_server/src/remote_clusters_info.erl 2015-10-08 10:37:57.095653000 +0200
@@ -121,10 +121,10 @@
{node, node(), remote_clusters_info_config_update_interval}, 10000)).

-record(state, {cache_path :: string(),
- scheduled_config_updates :: set(),
- remote_bucket_requests :: dict(),
- remote_bucket_waiters :: dict(),
- remote_bucket_waiters_trefs :: dict()}).
+ scheduled_config_updates :: set:set(),
+ remote_bucket_requests :: dict:dict(),
+ remote_bucket_waiters :: dict:dict(),
+ remote_bucket_waiters_trefs :: dict:dict()}).

start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
diff -r -u ns_server.orig/src/ringbuffer.erl ns_server/src/ringbuffer.erl
--- ns_server.orig/src/ringbuffer.erl 2015-10-08 11:31:21.416440000 +0200
+++ ns_server/src/ringbuffer.erl 2015-10-08 10:33:36.063532000 +0200
@@ -18,7 +18,7 @@
-export([new/1, to_list/1, to_list/2, to_list/3, add/2]).

% Create a ringbuffer that can hold at most Size items.
--spec new(integer()) -> queue().
+-spec new(integer()) -> queue:queue().
new(Size) ->
queue:from_list([empty || _ <- lists:seq(1, Size)]).

@@ -26,15 +26,15 @@
% Convert the ringbuffer to a list (oldest items first).
-spec to_list(integer()) -> list().
to_list(R) -> to_list(R, false).
--spec to_list(queue(), W) -> list() when is_subtype(W, boolean());
- (integer(), queue()) -> list().
+-spec to_list(queue:queue(), W) -> list() when is_subtype(W, boolean());
+ (integer(), queue:queue()) -> list().
to_list(R, WithEmpties) when is_boolean(WithEmpties) ->
queue:to_list(to_queue(R));

% Get at most the N newest items from the given ringbuffer (oldest first).
to_list(N, R) -> to_list(N, R, false).

--spec to_list(integer(), queue(), boolean()) -> list().
+-spec to_list(integer(), queue:queue(), boolean()) -> list().
to_list(N, R, WithEmpties) ->
L = lists:reverse(queue:to_list(to_queue(R, WithEmpties))),
lists:reverse(case (catch lists:split(N, L)) of
@@ -43,14 +43,14 @@
end).

% Add an element to a ring buffer.
--spec add(term(), queue()) -> queue().
+-spec add(term(), queue:queue()) -> queue:queue().
add(E, R) ->
queue:in(E, queue:drop(R)).

% private
--spec to_queue(queue()) -> queue().
+-spec to_queue(queue:queue()) -> queue:queue().
to_queue(R) -> to_queue(R, false).

--spec to_queue(queue(), boolean()) -> queue().
+-spec to_queue(queue:queue(), boolean()) -> queue:queue().
to_queue(R, false) -> queue:filter(fun(X) -> X =/= empty end, R);
to_queue(R, true) -> R.
diff -r -u ns_server.orig/src/vbucket_map_mirror.erl ns_server/src/vbucket_map_mirror.erl
--- ns_server.orig/src/vbucket_map_mirror.erl 2015-10-08 11:31:21.417885000 +0200
+++ ns_server/src/vbucket_map_mirror.erl 2015-10-07 22:27:21.036638000 +0200
@@ -119,7 +119,7 @@
end).

-spec node_vbuckets_dict_or_not_present(bucket_name()) ->
- dict() | no_map | not_present.
+ dict:dict() | no_map | not_present.
node_vbuckets_dict_or_not_present(BucketName) ->
case ets:lookup(vbucket_map_mirror, BucketName) of
[] ->
diff -r -u ns_server.orig/src/vbucket_move_scheduler.erl ns_server/src/vbucket_move_scheduler.erl
--- ns_server.orig/src/vbucket_move_scheduler.erl 2015-10-08 11:31:21.418054000 +0200
+++ ns_server/src/vbucket_move_scheduler.erl 2015-10-07 22:26:10.523913000 +0200
@@ -128,7 +128,7 @@
backfills_limit :: non_neg_integer(),
moves_before_compaction :: non_neg_integer(),
total_in_flight = 0 :: non_neg_integer(),
- moves_left_count_per_node :: dict(), % node() -> non_neg_integer()
+ moves_left_count_per_node :: dict:dict(), % node() -> non_neg_integer()
moves_left :: [move()],

%% pending moves when current master is undefined For them
@@ -136,13 +136,13 @@
%% And that's first moves that we ever consider doing
moves_from_undefineds :: [move()],

- compaction_countdown_per_node :: dict(), % node() -> non_neg_integer()
- in_flight_backfills_per_node :: dict(), % node() -> non_neg_integer() (I.e. counts current moves)
- in_flight_per_node :: dict(), % node() -> non_neg_integer() (I.e. counts current moves)
- in_flight_compactions :: set(), % set of nodes
+ compaction_countdown_per_node :: dict:dict(), % node() -> non_neg_integer()
+ in_flight_backfills_per_node :: dict:dict(), % node() -> non_neg_integer() (I.e. counts current moves)
+ in_flight_per_node :: dict:dict(), % node() -> non_neg_integer() (I.e. counts current moves)
+ in_flight_compactions :: set:set(), % set of nodes

- initial_move_counts :: dict(),
- left_move_counts :: dict(),
+ initial_move_counts :: dict:dict(),
+ left_move_counts :: dict:dict(),
inflight_moves_limit :: non_neg_integer()
}).

diff -r -u ns_server.orig/src/xdc_vbucket_rep_xmem.erl ns_server/src/xdc_vbucket_rep_xmem.erl
--- ns_server.orig/src/xdc_vbucket_rep_xmem.erl 2015-10-08 11:31:21.419959000 +0200
+++ ns_server/src/xdc_vbucket_rep_xmem.erl 2015-10-07 22:24:35.829228000 +0200
@@ -134,7 +134,7 @@
end.

%% internal
--spec categorise_statuses_to_dict(list(), list()) -> {dict(), dict()}.
+-spec categorise_statuses_to_dict(list(), list()) -> {dict:dict(), dict:dict()}.
categorise_statuses_to_dict(Statuses, MutationsList) ->
{ErrorDict, ErrorKeys, _}
= lists:foldl(fun(Status, {DictAcc, ErrorKeyAcc, CountAcc}) ->
@@ -164,7 +164,7 @@
lists:reverse(Statuses)),
{ErrorDict, ErrorKeys}.

--spec lookup_error_dict(term(), dict()) -> integer().
+-spec lookup_error_dict(term(), dict:dict()) -> integer().
lookup_error_dict(Key, ErrorDict)->
case dict:find(Key, ErrorDict) of
error ->
@@ -173,7 +173,7 @@
V
end.

--spec convert_error_dict_to_string(dict()) -> list().
+-spec convert_error_dict_to_string(dict:dict()) -> list().
convert_error_dict_to_string(ErrorKeyDict) ->
StrHead = case dict:size(ErrorKeyDict) > 0 of
true ->

Next!


# gmake
[no errors]

There are no next error. Let's see the destination folder:


# ll install/
total 32
drwxr-xr-x 3 root wheel 1536 Oct 8 11:21 bin/
drwxr-xr-x 2 root wheel 512 Oct 8 11:21 doc/
drwxr-xr-x 5 root wheel 512 Oct 8 11:21 etc/
drwxr-xr-x 6 root wheel 1024 Oct 8 11:21 lib/
drwxr-xr-x 3 root wheel 512 Oct 8 11:21 man/
drwxr-xr-x 2 root wheel 512 Oct 8 11:21 samples/
drwxr-xr-x 3 root wheel 512 Oct 8 11:21 share/
drwxr-xr-x 3 root wheel 512 Oct 8 11:21 var/

Sucess. Couchbase is built.

Running the server



# bin/couchbase-server
bin/couchbase-server: Command not found.

What the hell is that file?


root@couchbasebsd:~/couchbase # head bin/couchbase-server
#! /bin/bash
#
# Copyright (c) 2010-2011, Couchbase, Inc.
# All rights reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0

Yum. Sweet bash. Let's dirty our system a bit:


# ln -s /usr/local/bin/bash /bin/bash

Let's try running the server again:

# bin/couchbase-server
Erlang/OTP 18 [erts-7.0.1] [source] [64-bit] [smp:2:2] [async-threads:16] [hipe] [kernel-poll:false]

Eshell V7.0.1 (abort with ^G)

Nothing complained. Let's see if the web UI is present.


# sockstat -4l | grep 8091
#

It's not.

What's in the log?


[user:critical,2015-10-08T11:42:24.599,ns_1@127.0.0.1:ns_server_sup<0.271.0>:menelaus_sup:start_link:51]Couchbase Server has failed to start on web port 8091 on node 'ns_1@127.0.0.1'. Perhaps another process has taken port 8091 already? If so, please stop that process first before trying again.
[ns_server:info,2015-10-08T11:42:24.600,ns_1@127.0.0.1:mb_master<0.319.0>:mb_master:terminate:299]Synchronously shutting down child mb_master_sup

Server could not start. Let's see more logs:


# /root/couchbase/install/bin/cbbrowse_logs
[...]
[error_logger:error,2015-10-08T11:57:36.860,ns_1@127.0.0.1:error_logger<0.6.0>:ale_error_logger_handler:do_log:203]
=========================SUPERVISOR REPORT=========================
Supervisor: {local,ns_ssl_services_sup}
Context: start_error
Reason: {bad_generate_cert_exit,1,<<>>}
Offender: [{pid,undefined},
{id,ns_ssl_services_setup},
{mfargs,{ns_ssl_services_setup,start_link,[]}},
{restart_type,permanent},
{shutdown,1000},
{child_type,worker}]

bad_generate_cert_exit? Let's execute that program ourselves:


# bin/generate_cert
ELF binary type "0" not known.
bin/generate_cert: Exec format error. Binary file not executable.

# file bin/generate_cert
bin/generate_cert: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, BuildID[md5/uuid]=48f74c5e6c624dfe8ecba6d8687f151b, not stripped

Nothing beats building some software on FreeBSD and ending up with Linux binaries.

Where is the source of that program?


# find . -name '*generate_cert*'
./ns_server/deps/generate_cert
./ns_server/deps/generate_cert/generate_cert.go
./ns_server/priv/i386-darwin-generate_cert
./ns_server/priv/i386-linux-generate_cert
./ns_server/priv/i386-win32-generate_cert.exe
./install/bin/generate_cert

Let's build it and replace the Linux one.


# cd ns_server/deps/generate_cert/
# go build
# file generate_cert
generate_cert: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, not stripped
# cp generate_cert ../../../install/bin/

# cd ../gozip/
# go build
# cp gozip ../../../install/bin

Let's run the server again.


# # bin/couchbase-server
Erlang/OTP 18 [erts-7.0.1] [source] [64-bit] [smp:2:2] [async-threads:16] [hipe] [kernel-poll:false]

Eshell V7.0.1 (abort with ^G)

# sockstat -4l | grep 8091
root beam.smp 93667 39 tcp4 *:8091 *:*

This time the web UI is present.

The first page you see when you installed a couchbase server

Let's follow the setup and create a bucket.

Couchbase cluster overview

So far, everything seems to be working.

Interracting with the server via the CLI is also working.


# bin/couchbase-cli bucket-list -u Administrator -p abcd1234 -c 127.0.0.1
default
bucketType: membase
authType: sasl
saslPassword:
numReplicas: 1
ramQuota: 507510784
ramUsed: 31991104
test_bucket
bucketType: membase
authType: sasl
saslPassword:
numReplicas: 1
ramQuota: 104857600
ramUsed: 31991008

Conclusion


I obviously haven't tested every feature of the server, but as far as I demonstrated, it's perfectly capable of running on FreeBSD.