summaryrefslogtreecommitdiff
path: root/examples/mongo-dump.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/mongo-dump.c')
-rw-r--r--examples/mongo-dump.c224
1 files changed, 224 insertions, 0 deletions
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 <algernon@balabit.hu>
+ *
+ * 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 <mongo.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+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;
+}