1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
3/**
4 * @copyright 2013 Couchbase, Inc.
5 *
6 * @author Filipe Manana  <filipe@couchbase.com>
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 * use this file except in compliance with the License. You may obtain a copy of
10 * the License at
11 *
12 *  http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 * License for the specific language governing permissions and limitations under
18 * the License.
19 **/
20
21#include "config.h"
22
23#include <platform/cb_malloc.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include "../view_group.h"
28#include "../util.h"
29#include "util.h"
30#include "../file_sorter.h"
31#include "../mapreduce/mapreduce.h"
32
33#define BUF_SIZE 8192
34
35int main(int argc, char *argv[])
36{
37    view_group_info_t *group_info = NULL;
38    char buf[BUF_SIZE];
39    char **source_files = NULL;
40    char *dest_file = NULL;
41    char *tmp_dir = NULL;
42    int i;
43    int ret = 2;
44    uint64_t header_pos;
45    view_error_t error_info = {NULL, NULL, "GENERIC"};
46    cb_thread_t exit_thread;
47
48    (void) argc;
49    (void) argv;
50
51    /*
52     * Disable buffering for stdout/stderr since index builder messages
53     * needs to be immediately available at erlang side
54     */
55    setvbuf(stdout, (char *) NULL, _IONBF, 0);
56    setvbuf(stderr, (char *) NULL, _IONBF, 0);
57
58    if (set_binary_mode() < 0) {
59        fprintf(stderr, "Error setting binary mode\n");
60        goto out;
61    }
62
63    group_info = couchstore_read_view_group_info(stdin, stderr);
64    if (group_info == NULL) {
65        ret = COUCHSTORE_ERROR_ALLOC_FAIL;
66        goto out;
67    }
68
69    if (couchstore_read_line(stdin, buf, BUF_SIZE) != buf) {
70        fprintf(stderr, "Error reading temporary directory path\n");
71        ret = COUCHSTORE_ERROR_INVALID_ARGUMENTS;
72        goto out;
73    }
74
75    tmp_dir = cb_strdup(buf);
76    if (tmp_dir == NULL) {
77        fprintf(stderr, "Memory allocation failure\n");
78        ret = COUCHSTORE_ERROR_ALLOC_FAIL;
79        goto out;
80    }
81
82    source_files = (char **) cb_calloc(group_info->num_btrees + 1, sizeof(char *));
83    if (source_files == NULL) {
84        fprintf(stderr, "Memory allocation failure\n");
85        ret = COUCHSTORE_ERROR_ALLOC_FAIL;
86        goto out;
87    }
88
89    if (couchstore_read_line(stdin, buf, BUF_SIZE) != buf) {
90        fprintf(stderr, "Error reading destination file\n");
91        ret = COUCHSTORE_ERROR_INVALID_ARGUMENTS;
92        goto out;
93    }
94
95    dest_file = cb_strdup(buf);
96    if (dest_file == NULL) {
97        fprintf(stderr, "Memory allocation failure\n");
98        ret = COUCHSTORE_ERROR_ALLOC_FAIL;
99        goto out;
100    }
101
102    for (i = 0; i <= group_info->num_btrees; ++i) {
103        if (couchstore_read_line(stdin, buf, BUF_SIZE) != buf) {
104            if (i == 0) {
105                fprintf(stderr, "Error reading source file for id btree\n");
106            } else {
107                fprintf(stderr,
108                        "Error reading source file for btree %d\n", i - 1);
109            }
110            ret = COUCHSTORE_ERROR_INVALID_ARGUMENTS;
111            goto out;
112        }
113
114        source_files[i] = cb_strdup(buf);
115        if (source_files[i] == NULL) {
116            fprintf(stderr, "Memory allocation failure\n");
117            ret = COUCHSTORE_ERROR_ALLOC_FAIL;
118            goto out;
119        }
120    }
121
122    ret = start_exit_listener(&exit_thread, 1 /*uses_v8*/);
123    if (ret) {
124        fprintf(stderr, "Error starting stdin exit listener thread\n");
125        goto out;
126    }
127
128    mapreduce_init();
129    ret = couchstore_build_view_group(group_info,
130                                      source_files[0],
131                                      (const char **) &source_files[1],
132                                      dest_file,
133                                      tmp_dir,
134                                      &header_pos,
135                                      &error_info);
136
137    mapreduce_deinit();
138    if (ret != COUCHSTORE_SUCCESS) {
139        if (error_info.error_msg != NULL && error_info.view_name != NULL) {
140            fprintf(stderr,
141                    "%s Error building index for view `%s`, reason: %s\n",
142                    error_info.idx_type,
143                    error_info.view_name,
144                    error_info.error_msg);
145        }
146        goto out;
147    }
148
149out:
150    if (source_files != NULL) {
151        for (i = 0; i <= group_info->num_btrees; ++i) {
152            cb_free(source_files[i]);
153        }
154        cb_free(source_files);
155    }
156    cb_free(tmp_dir);
157    cb_free(dest_file);
158    couchstore_free_view_group_info(group_info);
159    cb_free((void *) error_info.error_msg);
160    cb_free((void *) error_info.view_name);
161
162    ret = (ret < 0) ? (100 + ret) : ret;
163    _exit(ret);
164}
165