1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
3/**
4 * @copyright 2013 Couchbase, Inc.
5 *
6 * @author Sarath Lakshman  <sarath@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#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include "../view_group.h"
26#include "../util.h"
27#include "../file_sorter.h"
28#include "util.h"
29
30#define BUF_SIZE 8192
31
32int main(int argc, char *argv[])
33{
34    view_group_info_t *group_info = NULL;
35    char buf[BUF_SIZE];
36    char **source_files = NULL;
37    char *tmp_dir = NULL;
38    int i;
39    int batch_size;
40    int ret = 2;
41    int is_sorted = 0;
42    view_group_update_stats_t stats;
43    sized_buf header_buf = {NULL, 0};
44    sized_buf header_outbuf = {NULL, 0};
45    view_error_t error_info = {NULL, NULL};
46    cb_thread_t exit_thread;
47
48    (void) argc;
49    (void) argv;
50
51    /*
52     * Disable buffering for stdout since index updater messages
53     * needs to be immediately available at erlang side
54     */
55    setvbuf(stdout, (char *) NULL, _IONBF, 0);
56
57    if (set_binary_mode() < 0) {
58        fprintf(stderr, "Error setting binary mode\n");
59        goto out;
60    }
61
62    /* Set all stats counters to zero */
63    memset((char *) &stats, 0, sizeof(view_group_update_stats_t));
64
65    if (couchstore_read_line(stdin, buf, BUF_SIZE) != buf) {
66        fprintf(stderr, "Error reading temporary directory path\n");
67        ret = COUCHSTORE_ERROR_INVALID_ARGUMENTS;
68        goto out;
69    }
70
71    tmp_dir = strdup(buf);
72    if (tmp_dir == NULL) {
73        fprintf(stderr, "Memory allocation failure\n");
74        ret = COUCHSTORE_ERROR_ALLOC_FAIL;
75        goto out;
76    }
77
78    group_info = couchstore_read_view_group_info(stdin, stderr);
79    if (group_info == NULL) {
80        ret = COUCHSTORE_ERROR_ALLOC_FAIL;
81        goto out;
82    }
83
84    if (couchstore_read_line(stdin, buf, BUF_SIZE) != buf) {
85        fprintf(stderr, "Error reading is_sorted flag\n");
86        ret = COUCHSTORE_ERROR_INVALID_ARGUMENTS;
87        goto out;
88    }
89
90    if (!strncmp(buf, "s", 1)) {
91        is_sorted = 1;
92    }
93
94    source_files = (char **) calloc(group_info->num_btrees + 1, sizeof(char *));
95    if (source_files == NULL) {
96        fprintf(stderr, "Memory allocation failure\n");
97        ret = COUCHSTORE_ERROR_ALLOC_FAIL;
98        goto out;
99    }
100
101    for (i = 0; i <= group_info->num_btrees; ++i) {
102        if (couchstore_read_line(stdin, buf, BUF_SIZE) != buf) {
103            if (i == 0) {
104                fprintf(stderr, "Error reading source file for id btree\n");
105            } else {
106                fprintf(stderr,
107                        "Error reading source file for btree %d\n", i - 1);
108            }
109            ret = COUCHSTORE_ERROR_INVALID_ARGUMENTS;
110            goto out;
111        }
112
113        source_files[i] = strdup(buf);
114        if (source_files[i] == NULL) {
115            fprintf(stderr, "Memory allocation failure\n");
116            ret = COUCHSTORE_ERROR_ALLOC_FAIL;
117            goto out;
118        }
119    }
120
121    batch_size = couchstore_read_int(stdin, buf, sizeof(buf), &ret);
122    if (ret != COUCHSTORE_SUCCESS) {
123        fprintf(stderr, "Error reading batch size\n");
124        ret = COUCHSTORE_ERROR_INVALID_ARGUMENTS;
125        goto out;
126    }
127
128    header_buf.size = couchstore_read_int(stdin, buf, sizeof(buf), &ret);
129    if (ret != COUCHSTORE_SUCCESS) {
130        fprintf(stderr, "Error reading viewgroup header size\n");
131        goto out;
132    }
133
134    header_buf.buf = malloc(header_buf.size);
135    if (header_buf.buf == NULL) {
136            fprintf(stderr, "Memory allocation failure\n");
137            ret = COUCHSTORE_ERROR_ALLOC_FAIL;
138            goto out;
139    }
140
141    if (fread(header_buf.buf, header_buf.size, 1, stdin) != 1) {
142        fprintf(stderr,
143                "Error reading viewgroup header from stdin\n");
144        goto out;
145    }
146
147    ret = start_exit_listener(&exit_thread);
148    if (ret) {
149        fprintf(stderr, "Error starting stdin exit listener thread\n");
150        goto out;
151    }
152
153    ret = couchstore_update_view_group(group_info,
154                                      source_files[0],
155                                      (const char **) &source_files[1],
156                                      batch_size,
157                                      &header_buf,
158                                      is_sorted,
159                                      tmp_dir,
160                                      &stats,
161                                      &header_outbuf,
162                                      &error_info);
163
164
165    if (ret != COUCHSTORE_SUCCESS) {
166        if (error_info.error_msg != NULL && error_info.view_name != NULL) {
167            fprintf(stderr,
168                    "Error updating index for view `%s`, reason: %s\n",
169                    error_info.view_name,
170                    error_info.error_msg);
171        }
172        goto out;
173    }
174
175    fprintf(stdout, "Header Len : %lu\n", header_outbuf.size);
176    fwrite(header_outbuf.buf, header_outbuf.size, 1, stdout);
177    fprintf(stdout, "\n");
178
179    fprintf(stdout,"Results ="
180                   " id_inserts : %"PRIu64
181                   ", id_deletes : %"PRIu64
182                   ", kv_inserts : %"PRIu64
183                   ", kv_deletes : %"PRIu64
184                   ", cleanups : %"PRIu64"\n",
185                   stats.ids_inserted,
186                   stats.ids_removed,
187                   stats.kvs_inserted,
188                   stats.kvs_removed,
189                   stats.purged);
190
191out:
192    if (source_files != NULL) {
193        for (i = 0; i <= group_info->num_btrees; ++i) {
194            free(source_files[i]);
195        }
196        free(source_files);
197    }
198
199    couchstore_free_view_group_info(group_info);
200    free((void *) error_info.error_msg);
201    free((void *) error_info.view_name);
202    free((void *) header_buf.buf);
203    free((void *) header_outbuf.buf);
204    free(tmp_dir);
205
206    return (ret < 0) ? (100 + ret) : ret;
207}
208