From fd841e416881cc0392e61ec312c1870f3a0004bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Tue, 2 Dec 2014 10:06:21 +0100 Subject: Initial import of libmongo-client version 0.1.8-2 --- examples/Makefile.am | 8 + examples/bson-inspect.c | 341 +++++++++++++++++++++++++++++++++++++++ examples/gridfs.c | 413 ++++++++++++++++++++++++++++++++++++++++++++++++ examples/mongo-dump.c | 224 ++++++++++++++++++++++++++ 4 files changed, 986 insertions(+) create mode 100644 examples/Makefile.am create mode 100644 examples/bson-inspect.c create mode 100644 examples/gridfs.c create mode 100644 examples/mongo-dump.c (limited to 'examples') diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..0cff31f --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,8 @@ +noinst_PROGRAMS = mongo-dump bson-inspect gridfs + +AM_CFLAGS = -I$(top_srcdir)/src/ @GLIB_CFLAGS@ +LDADD = $(top_builddir)/src/libmongo-client.la @GLIB_LIBS@ + +mongo_dump_SOURCES = mongo-dump.c +bson_inspect_SOURCES = bson-inspect.c +gridfs_SOURCES = gridfs.c diff --git a/examples/bson-inspect.c b/examples/bson-inspect.c new file mode 100644 index 0000000..841dc45 --- /dev/null +++ b/examples/bson-inspect.c @@ -0,0 +1,341 @@ +/* bson-inspect.c - BSON inspector, example application. + * Copyright 2011, 2012 Gergely Nagy + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +_indent (gint level, gboolean verbose) +{ + gint i; + + if (!verbose) + return; + + for (i = 1; i <= level; i++) + printf (" "); +} + +static void +bson_dump (bson *b, gint ilevel, gboolean verbose, gboolean as_array) +{ + bson_cursor *c; + gboolean first = TRUE; + + c = bson_cursor_new (b); + while (bson_cursor_next (c)) + { + if (!first) + { + printf (", "); + if (verbose) + printf ("\n"); + } + first = FALSE; + if (verbose) + { + _indent (ilevel, verbose); + printf ("/* type='%s'; */\n", + bson_cursor_type_as_string (c) + 10); + } + _indent (ilevel, verbose); + if (!as_array) + { + printf ("\"%s\" : ", bson_cursor_key (c)); + } + switch (bson_cursor_type (c)) + { + case BSON_TYPE_DOUBLE: + { + gdouble d; + bson_cursor_get_double (c, &d); + printf ("%f", d); + break; + } + case BSON_TYPE_STRING: + { + const gchar *s; + gchar *s2; + bson_cursor_get_string (c, &s); + s2 = g_strescape (s, NULL); + printf ("\"%s\"", s2); + g_free (s2); + break; + } + case BSON_TYPE_OID: + { + const guint8 *oid; + gint j; + bson_cursor_get_oid (c, &oid); + printf ("ObjectId( \""); + for (j = 0; j < 12; j++) + printf ("%02x", oid[j]); + printf ("\" )"); + break; + } + case BSON_TYPE_BOOLEAN: + { + gboolean b; + bson_cursor_get_boolean (c, &b); + printf ((b) ? "true" : "false"); + break; + } + case BSON_TYPE_REGEXP: + { + const gchar *r, *o; + gchar *r2, *o2; + bson_cursor_get_regex (c, &r, &o); + r2 = g_strescape (r, NULL); + o2 = g_strescape (o, NULL); + printf ("Regex(\"/%s/%s\")", r2, o2); + g_free (r2); + g_free (o2); + break; + } + case BSON_TYPE_NULL: + { + printf ("null"); + break; + } + case BSON_TYPE_JS_CODE: + { + const gchar *js; + gchar *js2; + bson_cursor_get_javascript (c, &js); + js2 = g_strescape (js, NULL); + printf ("%s", js2); + g_free (js2); + break; + } + case BSON_TYPE_SYMBOL: + { + const gchar *s; + gchar *s2; + bson_cursor_get_symbol (c, &s); + s2 = g_strescape (s, NULL); + printf ("%s", s2); + g_free (s2); + break; + } + case BSON_TYPE_INT32: + { + gint32 l32; + bson_cursor_get_int32 (c, &l32); + printf ("%d", l32); + break; + } + case BSON_TYPE_INT64: + { + gint64 l64; + bson_cursor_get_int64 (c, &l64); + printf ("%" G_GINT64_FORMAT, l64); + break; + } + case BSON_TYPE_DOCUMENT: + { + bson *sd; + bson_cursor_get_document (c, &sd); + printf ("{ "); + if (verbose) + printf ("/* size='%d' */\n", bson_size (sd)); + bson_dump (sd, ilevel + 1, verbose, FALSE); + if (verbose) + { + printf ("\n"); + _indent (ilevel, verbose); + printf ("}"); + } + else + printf (" }"); + bson_free (sd); + break; + } + case BSON_TYPE_ARRAY: + { + bson *sa; + + bson_cursor_get_array (c, &sa); + printf ("[ "); + if (verbose) + printf ("/* size='%d' */\n", bson_size (sa)); + bson_dump (sa, ilevel + 1, verbose, TRUE); + if (verbose) + { + printf ("\n"); + _indent (ilevel, verbose); + printf ("]"); + } + else + printf (" ]"); + bson_free (sa); + break; + } + case BSON_TYPE_BINARY: + { + const guint8 *data; + gint32 size; + bson_binary_subtype t; + gchar *b64; + + bson_cursor_get_binary (c, &t, &data, &size); + b64 = g_base64_encode (data, size); + printf ("{ "); + if (verbose) + { + printf ("/* size='%d' */\n", size); + _indent (ilevel + 1, verbose); + } + printf ("\"$binary\" : \"%s\",", b64); + if (verbose) + { + printf ("\n"); + _indent (ilevel + 1, verbose); + } + else + printf (" "); + printf ("\"$type\" : \"%02d\"", t); + if (verbose) + { + printf ("\n"); + _indent (ilevel, verbose); + } + else + printf (" "); + printf ("}"); + g_free (b64); + break; + } + case BSON_TYPE_JS_CODE_W_SCOPE: + case BSON_TYPE_UNDEFINED: + case BSON_TYPE_UTC_DATETIME: + case BSON_TYPE_DBPOINTER: + case BSON_TYPE_TIMESTAMP: + case BSON_TYPE_MIN: + case BSON_TYPE_MAX: + default: + printf ("\"\""); + break; + } + } + bson_cursor_free (c); +} + +int +main (int argc, char *argv[]) +{ + int fd; + off_t offs = 0; + bson *b; + guint8 *data; + struct stat st; + gint64 i = 1; + GOptionContext *context; + gboolean verbose = FALSE; + GError *error = NULL; + + GOptionEntry entries[] = + { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + "Be verbose", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + context = g_option_context_new ("- inspect a BSON dump"); + g_option_context_add_main_entries (context, entries, "bson-inspect"); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print ("option parsing failed: %s\n", error->message); + exit (1); + } + + if (argc < 2) + { + gchar **nargv; + argc = 2; + + nargv = g_new (gchar *, 3); + nargv[0] = argv[0]; + nargv[1] = "--help"; + nargv[2] = NULL; + + g_option_context_parse (context, &argc, (gchar ***)&nargv, &error); + + exit (1); + } + + fd = open (argv[1], O_RDONLY); + if (fd == -1) + { + fprintf (stderr, "Error opening file '%s': %s\n", + argv[1], strerror (errno)); + exit (1); + } + if (fstat (fd, &st) != 0) + { + fprintf (stderr, "Error fstat()ing file '%s': %s\n", + argv[1], strerror (errno)); + close (fd); + exit (1); + } + + data = mmap (NULL, (size_t)st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + fprintf (stderr, "Error mmap()ing file '%s': %s\n", + argv[1], strerror (errno)); + close (fd); + exit (1); + } + + while (offs < st.st_size) + { + b = bson_new_from_data ((const guint8 *)(data + offs), + bson_stream_doc_size (data, offs) - 1); + bson_finish (b); + offs += bson_size (b); + + if (verbose) + printf ("/* Document #%" G_GUINT64_FORMAT "; size='%d' */\n", i, + bson_size (b)); + printf ("{ "); + if (verbose) + printf ("\n"); + bson_dump (b, 1, verbose, FALSE); + if (verbose) + printf ("\n}\n"); + else + printf (" }\n"); + if (verbose) + printf ("\n"); + + bson_free (b); + i++; + } + munmap (data, st.st_size); + close (fd); + + return 0; +} diff --git a/examples/gridfs.c b/examples/gridfs.c new file mode 100644 index 0000000..2d19aee --- /dev/null +++ b/examples/gridfs.c @@ -0,0 +1,413 @@ +/* gridfs.c - A GridFS utility; example application + * Copyright 2011, 2012 Gergely Nagy + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + gchar *host; + gint port; + gchar *db; + gchar *coll; + gchar *ns; + gboolean verbose; + gboolean slaveok; + gboolean master_sync; +} config_t; + +#define VLOG(...) { if (config->verbose) fprintf (stderr, __VA_ARGS__); } + +void +mongo_gridfs_error (int e) +{ + fprintf (stderr, "Error encountered: %s\n", strerror (e)); + exit (1); +} + +mongo_sync_gridfs * +mongo_gridfs_connect (config_t *config) +{ + mongo_sync_connection *conn; + mongo_sync_gridfs *gfs; + + VLOG ("Connecting to %s:%d/%s.%s...\n", config->host, config->port, + config->db, config->coll); + + conn = mongo_sync_connect (config->host, config->port, config->slaveok); + if (!conn) + mongo_gridfs_error (errno); + + if (config->master_sync) + { + VLOG ("Syncing to master...\n"); + conn = mongo_sync_reconnect (conn, TRUE); + if (!conn) + mongo_gridfs_error (errno); + } + + gfs = mongo_sync_gridfs_new (conn, config->ns); + if (!gfs) + mongo_gridfs_error (errno); + + return gfs; +} + +void +mongo_gridfs_get (config_t *config, gint argc, gchar *argv[]) +{ + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_chunked_file *gfile; + mongo_sync_cursor *cursor; + gint64 n = 0; + bson *query; + int fd; + + gchar *gfn, *ofn; + + if (argc < 4) + { + fprintf (stderr, "Usage: %s get GRIDFS_FILENAME OUTPUT_FILENAME\n", + argv[0]); + exit (1); + } + gfn = argv[2]; + ofn = argv[3]; + + gfs = mongo_gridfs_connect (config); + + VLOG ("Trying to find '%s'...\n", gfn); + + query = bson_build (BSON_TYPE_STRING, "filename", gfn, -1, + BSON_TYPE_NONE); + bson_finish (query); + gfile = mongo_sync_gridfs_chunked_find (gfs, query); + if (!gfile) + mongo_gridfs_error (errno); + bson_free (query); + + VLOG ("Opening output file '%s'...\n", ofn); + fd = open (ofn, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd == -1) + { + fprintf (stderr, "Error opening output file '%s': %s\n", + ofn, strerror (errno)); + exit (1); + } + + VLOG ("Writing '%s' -> '%s' (%" G_GINT64_FORMAT " bytes in %" G_GINT64_FORMAT + " chunks)\n", gfn, ofn, + mongo_sync_gridfs_file_get_length (gfile), + mongo_sync_gridfs_file_get_chunks (gfile)); + + cursor = mongo_sync_gridfs_chunked_file_cursor_new (gfile, 0, 0); + if (!cursor) + mongo_gridfs_error (errno); + + while (mongo_sync_cursor_next (cursor)) + { + gint32 size; + guint8 *data; + + VLOG ("\rWriting chunk %" G_GINT64_FORMAT "...", n++); + + data = mongo_sync_gridfs_chunked_file_cursor_get_chunk (cursor, &size); + if (!data) + mongo_gridfs_error (errno); + + if (write (fd, data, size) != size) + { + perror ("write()"); + exit (1); + } + g_free (data); + } + mongo_sync_cursor_free (cursor); + mongo_sync_gridfs_chunked_file_free (gfile); + + close (fd); + + mongo_sync_gridfs_free (gfs, TRUE); + + VLOG("\n"); +} + +void +mongo_gridfs_put (config_t *config, gint argc, gchar *argv[]) +{ + mongo_sync_gridfs *gfs; + mongo_sync_gridfs_chunked_file *gfile; + bson *meta; + int fd; + guint8 *data; + struct stat st; + + gchar *gfn, *ifn, *oid_s; + + if (argc < 4) + { + fprintf (stderr, "Usage: %s put INPUT_FILENAME GRIDFS_FILENAME\n", + argv[0]); + exit (1); + } + ifn = argv[2]; + gfn = argv[3]; + + mongo_util_oid_init (0); + + gfs = mongo_gridfs_connect (config); + + VLOG ("Opening input file: '%s'...\n", ifn); + fd = open (ifn, O_RDONLY); + if (!fd) + { + fprintf (stderr, "Error opening input file: %s\n", + strerror (errno)); + exit (1); + } + if (fstat (fd, &st) != 0) + { + fprintf (stderr, "Error stat'ing the input file: %s\n", + strerror (errno)); + exit (1); + } + + data = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == MAP_FAILED) + { + fprintf (stderr, "Error mmapping the input file: %s\n", + strerror (errno)); + } + + meta = bson_build (BSON_TYPE_STRING, "filename", gfn, -1, + BSON_TYPE_NONE); + bson_finish (meta); + + VLOG ("Uploading '%s' -> '%s'...\n", ifn, gfn); + + gfile = mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, meta, + data, st.st_size); + if (!gfile) + mongo_gridfs_error (errno); + bson_free (meta); + munmap (data, st.st_size); + + oid_s = mongo_util_oid_as_string (mongo_sync_gridfs_file_get_id (gfile)); + printf ("Uploaded file: %s (_id: %s; md5 = %s)\n", gfn, + oid_s, + mongo_sync_gridfs_file_get_md5 (gfile)); + + g_free (oid_s); + mongo_sync_gridfs_chunked_file_free (gfile); + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +mongo_gridfs_list (config_t *config) +{ + mongo_sync_cursor *cursor; + mongo_sync_gridfs *gfs; + + gfs = mongo_gridfs_connect (config); + + cursor = mongo_sync_gridfs_list (gfs, NULL); + + while (mongo_sync_cursor_next (cursor)) + { + bson *meta = mongo_sync_cursor_get_data (cursor); + bson_cursor *c; + const guint8 oid[12]; + gint32 i32, chunk_size; + gint64 length, date; + const gchar *md5, *filename = NULL; + gchar *oid_s; + + c = bson_find (meta, "_id"); + if (!bson_cursor_get_oid (c, (const guint8 **)&oid)) + mongo_gridfs_error (errno); + + bson_cursor_find (c, "length"); + if (!bson_cursor_get_int32 (c, &i32)) + { + if (!bson_cursor_get_int64 (c, &length)) + mongo_gridfs_error (errno); + } + else + length = i32; + + bson_cursor_find (c, "chunkSize"); + if (!bson_cursor_get_int32 (c, &chunk_size)) + mongo_gridfs_error (errno); + + bson_cursor_find (c, "uploadDate"); + if (!bson_cursor_get_utc_datetime (c, &date)) + mongo_gridfs_error (errno); + + bson_cursor_find (c, "md5"); + if (!bson_cursor_get_string (c, &md5)) + mongo_gridfs_error (errno); + + bson_cursor_find (c, "filename"); + bson_cursor_get_string (c, &filename); + + bson_cursor_free (c); + + oid_s = mongo_util_oid_as_string (oid); + printf ("{ _id: ObjectID(\"%s\"), length: %" G_GINT64_FORMAT + ", chunkSize: %i, uploadDate: %" + G_GINT64_FORMAT ", md5: \"%s\"", + + oid_s, length, chunk_size, date, md5); + g_free (oid_s); + + if (filename) + printf (", filename: \"%s\"", filename); + printf (" }\n"); + + if (config->verbose) + { + c = bson_cursor_new (meta); + printf ("\tExtra metadata: [ "); + while (bson_cursor_next (c)) + { + if (strcmp (bson_cursor_key (c), "_id") && + strcmp (bson_cursor_key (c), "length") && + strcmp (bson_cursor_key (c), "chunkSize") && + strcmp (bson_cursor_key (c), "uploadDate") && + strcmp (bson_cursor_key (c), "md5") && + strcmp (bson_cursor_key (c), "filename")) + { + printf ("%s (%s), ", bson_cursor_key (c), + bson_cursor_type_as_string (c)); + } + } + bson_cursor_free (c); + printf ("]\n"); + } + } + + mongo_sync_gridfs_free (gfs, TRUE); +} + +void +mongo_gridfs_remove (config_t *config, gint argc, gchar *argv[]) +{ + mongo_sync_gridfs *gfs; + bson *query; + gchar *fn; + + if (argc < 3) + { + fprintf (stderr, "Usage: %s remove GRIDFS_FILENAME\n", argv[0]); + exit (1); + } + fn = argv[2]; + + gfs = mongo_gridfs_connect (config); + + VLOG ("Deleting file: '%s'...\n", fn); + + query = bson_build (BSON_TYPE_STRING, "filename", fn, -1, + BSON_TYPE_NONE); + bson_finish (query); + + if (mongo_sync_gridfs_remove (gfs, query)) + { + VLOG ("\tDeleted\n"); + } + else + { + VLOG ("\tFailed: %s\n", strerror (errno)); + } + bson_free (query); + + mongo_sync_gridfs_free (gfs, TRUE); +} + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + GOptionContext *context; + config_t config = { + NULL, 27017, NULL, NULL, NULL, FALSE, FALSE, FALSE + }; + + GOptionEntry entries[] = + { + { "host", 'h', 0, G_OPTION_ARG_STRING, &config.host, + "Host to connect to", "HOST" }, + { "port", 'p', 0, G_OPTION_ARG_INT, &config.port, "Port", "PORT" }, + { "db", 'd', 0, G_OPTION_ARG_STRING, &config.db, "Database", "DB" }, + { "collection", 'c', 0, G_OPTION_ARG_STRING, &config.coll, "Collection", + "COLL" }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &config.verbose, + "Be verbose", NULL }, + { "slave-ok", 's', 0, G_OPTION_ARG_NONE, &config.slaveok, + "Connecting to slaves is ok", NULL }, + { "master-sync", 'm', 0, G_OPTION_ARG_NONE, &config.master_sync, + "Reconnect to the replica master", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + context = g_option_context_new ("- GridFS utility"); + g_option_context_add_main_entries (context, entries, "mongo-dump"); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print ("option parsing failed: %s\n", error->message); + exit (1); + } + + if (!config.host || !config.port || !config.db || + !config.coll || argc < 2) + { + gchar **nargv; + argc = 2; + + nargv = g_new (gchar *, 3); + nargv[0] = argv[0]; + nargv[1] = "--help"; + nargv[2] = NULL; + + g_option_context_parse (context, &argc, (gchar ***)&nargv, &error); + + exit (1); + } + config.ns = g_strdup_printf ("%s.%s", config.db, config.coll); + + if (g_ascii_strcasecmp (argv[1], "get") == 0) + mongo_gridfs_get (&config, argc, argv); + else if (g_ascii_strcasecmp (argv[1], "put") == 0) + mongo_gridfs_put (&config, argc, argv); + else if (g_ascii_strcasecmp (argv[1], "list") == 0) + mongo_gridfs_list (&config); + else if (g_ascii_strcasecmp (argv[1], "remove") == 0) + mongo_gridfs_remove (&config, argc, argv); + + g_free (config.ns); + g_option_context_free (context); + + return 0; +} diff --git a/examples/mongo-dump.c b/examples/mongo-dump.c new file mode 100644 index 0000000..7e6419f --- /dev/null +++ b/examples/mongo-dump.c @@ -0,0 +1,224 @@ +/* mongo-dump.c - MongoDB database dumper; example application. + * Copyright 2011, 2012 Gergely Nagy + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + gchar *addr; + gint port; + gchar *db; + gchar *coll; + gchar *output; + gchar *ns; + gboolean verbose; + gboolean slaveok; + gboolean master_sync; +} config_t; + +#define VLOG(...) { if (config->verbose) fprintf (stderr, __VA_ARGS__); } + +void +mongo_dump (config_t *config) +{ + mongo_sync_connection *conn; + mongo_sync_cursor *cursor; + bson *b; + int fd; + + glong cnt, pos = 0; + + gchar *error = NULL; + int e; + + if (config->port == MONGO_CONN_LOCAL) + { + VLOG ("Connecting to %s/%s.%s...\n", config->addr, config->db, + config->coll); + } + else + { + VLOG ("Connecting to %s:%d/%s.%s...\n", config->addr, config->port, + config->db, config->coll); + } + conn = mongo_sync_connect (config->addr, config->port, config->slaveok); + + if (!conn) + { + e = errno; + + mongo_sync_cmd_get_last_error (conn, config->db, &error); + fprintf (stderr, "Error connecting to %s:%d: %s\n", config->addr, + config->port, (error) ? error : strerror (e)); + g_free (error); + exit (1); + } + + if (config->master_sync) + { + VLOG ("Syncing to master...\n"); + conn = mongo_sync_reconnect (conn, TRUE); + if (!conn) + { + e = errno; + + mongo_sync_cmd_get_last_error (conn, config->db, &error); + fprintf (stderr, "Error reconnecting to the master of %s:%d: %s\n", + config->addr, config->port, (error) ? error : strerror (e)); + exit (1); + } + } + + VLOG ("Counting documents...\n"); + cnt = mongo_sync_cmd_count (conn, config->db, config->coll, NULL); + if (cnt < 0) + { + e = errno; + + mongo_sync_cmd_get_last_error (conn, config->db, &error); + fprintf (stderr, "Error counting documents in %s.%s: %s\n", + config->db, config->coll, (error) ? error : strerror (e)); + mongo_sync_disconnect (conn); + exit (1); + } + + VLOG ("Opening output file '%s'...\n", config->output); + if (strcmp (config->output, "-") == 0) + fd = 1; + else + { + fd = open (config->output, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd == -1) + { + fprintf (stderr, "Error opening output file '%s': %s\n", + config->output, strerror (errno)); + mongo_sync_disconnect (conn); + exit (1); + } + } + + VLOG ("Launching initial query...\n"); + b = bson_new (); + bson_finish (b); + cursor = mongo_sync_cursor_new (conn, config->ns, + mongo_sync_cmd_query (conn, config->ns, + MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT, + 0, 10, b, NULL)); + bson_free (b); + + while ((pos < cnt) && mongo_sync_cursor_next (cursor)) + { + bson *b = mongo_sync_cursor_get_data (cursor); + pos++; + + if (!b) + { + e = errno; + + mongo_sync_cmd_get_last_error (conn, config->db, &error); + fprintf (stderr, "Error advancing the cursor: %s\n", + (error) ? error : strerror (e)); + mongo_sync_disconnect (conn); + exit (1); + } + + if (pos % 10 == 0) + VLOG ("\rDumping... %03.2f%%", (pos * 1.0) / (cnt * 1.0) * 100); + + if (write (fd, bson_data (b), bson_size (b)) != bson_size (b)) + { + perror ("write()"); + exit (1); + } + bson_free (b); + } + VLOG ("\rDumping... %03.2f%%\n", (double)((pos / cnt) * 100)); + + mongo_sync_cursor_free (cursor); + + close (fd); + mongo_sync_disconnect (conn); +} + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + GOptionContext *context; + config_t config = { + NULL, 27017, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE + }; + + GOptionEntry entries[] = + { + { "addr", 'a', 0, G_OPTION_ARG_STRING, &config.addr, + "Address to connect to", "ADDRESS" }, + { "port", 'p', 0, G_OPTION_ARG_INT, &config.port, "Port", "PORT" }, + { "db", 'd', 0, G_OPTION_ARG_STRING, &config.db, "Database", "DB" }, + { "collection", 'c', 0, G_OPTION_ARG_STRING, &config.coll, "Collection", + "COLL" }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &config.verbose, + "Be verbose", NULL }, + { "output", 'o', 0, G_OPTION_ARG_STRING, &config.output, + "Output", "FILENAME" }, + { "slave-ok", 's', 0, G_OPTION_ARG_NONE, &config.slaveok, + "Connecting to slaves is ok", NULL }, + { "master-sync", 'm', 0, G_OPTION_ARG_NONE, &config.master_sync, + "Reconnect to the replica master", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + context = g_option_context_new ("- dump a complete mongo collection"); + g_option_context_add_main_entries (context, entries, "mongo-dump"); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print ("option parsing failed: %s\n", error->message); + exit (1); + } + + if (!((config.addr && config.port)) || !config.db || + !config.coll || !config.output) + { + gchar **nargv; + argc = 2; + + nargv = g_new (gchar *, 3); + nargv[0] = argv[0]; + nargv[1] = "--help"; + nargv[2] = NULL; + + g_option_context_parse (context, &argc, (gchar ***)&nargv, &error); + + exit (1); + } + + config.ns = g_strdup_printf ("%s.%s", config.db, config.coll); + mongo_dump (&config); + + g_free (config.ns); + g_option_context_free (context); + + return 0; +} -- cgit v1.2.3