libmongo-client 0.1.4
src/mongo-sync.c
Go to the documentation of this file.
00001 /* mongo-sync.c - libmongo-client synchronous wrapper API
00002  * Copyright 2011 Gergely Nagy <algernon@balabit.hu>
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00021 #include "config.h"
00022 #include "mongo.h"
00023 #include "libmongo-private.h"
00024 
00025 #include <stdlib.h>
00026 #include <errno.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 
00030 mongo_sync_connection *
00031 mongo_sync_connect (const gchar *host, gint port,
00032                     gboolean slaveok)
00033 {
00034   mongo_sync_connection *s;
00035   mongo_connection *c;
00036 
00037   c = mongo_connect (host, port);
00038   if (!c)
00039     return NULL;
00040   s = g_realloc (c, sizeof (mongo_sync_connection));
00041 
00042   s->slaveok = slaveok;
00043   s->safe_mode = FALSE;
00044   s->auto_reconnect = FALSE;
00045   s->rs.seeds = g_list_append (NULL, g_strdup_printf ("%s:%d", host, port));
00046   s->rs.hosts = NULL;
00047   s->rs.primary = NULL;
00048   s->last_error = NULL;
00049   s->max_insert_size = MONGO_SYNC_DEFAULT_MAX_INSERT_SIZE;
00050 
00051   return s;
00052 }
00053 
00054 gboolean
00055 mongo_sync_conn_seed_add (mongo_sync_connection *conn,
00056                           const gchar *host, gint port)
00057 {
00058   if (!conn)
00059     {
00060       errno = ENOTCONN;
00061       return FALSE;
00062     }
00063   if (!host || port < 0)
00064     {
00065       errno = EINVAL;
00066       return FALSE;
00067     }
00068 
00069   conn->rs.seeds = g_list_append (conn->rs.seeds,
00070                                   g_strdup_printf ("%s:%d", host, port));
00071   return TRUE;
00072 }
00073 
00074 static void
00075 _mongo_sync_connect_replace (mongo_sync_connection *old,
00076                              mongo_sync_connection *new)
00077 {
00078   GList *l;
00079 
00080   if (!old || !new)
00081     return;
00082 
00083   g_free (old->rs.primary);
00084 
00085   /* Delete the host list. */
00086   l = old->rs.hosts;
00087   while (l)
00088     {
00089       g_free (l->data);
00090       l = g_list_delete_link (l, l);
00091     }
00092   old->rs.hosts = NULL;
00093 
00094   if (old->super.fd)
00095     close (old->super.fd);
00096 
00097   old->super.fd = new->super.fd;
00098   old->super.request_id = -1;
00099   old->slaveok = new->slaveok;
00100   old->rs.primary = NULL;
00101   g_free (old->last_error);
00102   old->last_error = NULL;
00103 
00104   /* Free the replicaset struct in the new connection. These aren't
00105      copied, in order to avoid infinite loops. */
00106   l = new->rs.hosts;
00107   while (l)
00108     {
00109       g_free (l->data);
00110       l = g_list_delete_link (l, l);
00111     }
00112   l = new->rs.seeds;
00113   while (l)
00114     {
00115       g_free (l->data);
00116       l = g_list_delete_link (l, l);
00117     }
00118   g_free (new->rs.primary);
00119   g_free (new->last_error);
00120   g_free (new);
00121 }
00122 
00123 mongo_sync_connection *
00124 mongo_sync_reconnect (mongo_sync_connection *conn,
00125                       gboolean force_master)
00126 {
00127   gboolean ping = FALSE;
00128   guint i;
00129   mongo_sync_connection *nc;
00130   gchar *host;
00131   gint port;
00132 
00133   if (!conn)
00134     {
00135       errno = ENOTCONN;
00136       return NULL;
00137     }
00138 
00139   ping = mongo_sync_cmd_ping (conn);
00140 
00141   if (ping)
00142     {
00143       if (!force_master)
00144         return conn;
00145       if (force_master && mongo_sync_cmd_is_master (conn))
00146         return conn;
00147 
00148       /* Force refresh the host list. */
00149       mongo_sync_cmd_is_master (conn);
00150     }
00151 
00152   /* We either didn't ping, or we're not master, and have to
00153    * reconnect.
00154    *
00155    * First, check if we have a primary, and if we can connect there.
00156    */
00157 
00158   if (conn->rs.primary)
00159     {
00160       if (mongo_util_parse_addr (conn->rs.primary, &host, &port))
00161         {
00162           nc = mongo_sync_connect (host, port, conn->slaveok);
00163           g_free (host);
00164           if (nc)
00165             {
00166               int e;
00167 
00168               /* We can call ourselves here, since connect does not set
00169                  conn->rs, thus, we won't end up in an infinite loop. */
00170               nc = mongo_sync_reconnect (nc, force_master);
00171               e = errno;
00172               _mongo_sync_connect_replace (conn, nc);
00173               errno = e;
00174               return conn;
00175             }
00176         }
00177     }
00178 
00179   /* No primary found, or we couldn't connect, try the rest of the
00180      hosts. */
00181 
00182   for (i = 0; i < g_list_length (conn->rs.hosts); i++)
00183     {
00184       gchar *addr = (gchar *)g_list_nth_data (conn->rs.hosts, i);
00185       int e;
00186 
00187       if (!mongo_util_parse_addr (addr, &host, &port))
00188         continue;
00189 
00190       nc = mongo_sync_connect (host, port, conn->slaveok);
00191       g_free (host);
00192       if (!nc)
00193         continue;
00194 
00195       nc = mongo_sync_reconnect (nc, force_master);
00196       e = errno;
00197       _mongo_sync_connect_replace (conn, nc);
00198       errno = e;
00199       return conn;
00200     }
00201 
00202   /* And if that failed too, try the seeds. */
00203 
00204   for (i = 0; i < g_list_length (conn->rs.seeds); i++)
00205     {
00206       gchar *addr = (gchar *)g_list_nth_data (conn->rs.seeds, i);
00207       int e;
00208 
00209       if (!mongo_util_parse_addr (addr, &host, &port))
00210         continue;
00211 
00212       nc = mongo_sync_connect (host, port, conn->slaveok);
00213       g_free (host);
00214       if (!nc)
00215         continue;
00216 
00217       nc = mongo_sync_reconnect (nc, force_master);
00218       e = errno;
00219       _mongo_sync_connect_replace (conn, nc);
00220       errno = e;
00221       return conn;
00222     }
00223 
00224   errno = EHOSTUNREACH;
00225   return NULL;
00226 }
00227 
00228 void
00229 mongo_sync_disconnect (mongo_sync_connection *conn)
00230 {
00231   GList *l;
00232 
00233   if (!conn)
00234     return;
00235 
00236   g_free (conn->rs.primary);
00237   g_free (conn->last_error);
00238 
00239   /* Delete the host list. */
00240   l = conn->rs.hosts;
00241   while (l)
00242     {
00243       g_free (l->data);
00244       l = g_list_delete_link (l, l);
00245     }
00246 
00247   /* Delete the seed list. */
00248   l = conn->rs.seeds;
00249   while (l)
00250     {
00251       g_free (l->data);
00252       l = g_list_delete_link (l, l);
00253     }
00254 
00255   mongo_disconnect ((mongo_connection *)conn);
00256 }
00257 
00258 gint32
00259 mongo_sync_conn_get_max_insert_size (mongo_sync_connection *conn)
00260 {
00261   if (!conn)
00262     {
00263       errno = ENOTCONN;
00264       return -1;
00265     }
00266   return conn->max_insert_size;
00267 }
00268 
00269 gboolean
00270 mongo_sync_conn_set_max_insert_size (mongo_sync_connection *conn,
00271                                      gint32 max_size)
00272 {
00273   if (!conn)
00274     {
00275       errno = ENOTCONN;
00276       return FALSE;
00277     }
00278   if (max_size <= 0)
00279     {
00280       errno = ERANGE;
00281       return FALSE;
00282     }
00283 
00284   errno = 0;
00285   conn->max_insert_size = max_size;
00286   return TRUE;
00287 }
00288 
00289 gboolean
00290 mongo_sync_conn_get_safe_mode (const mongo_sync_connection *conn)
00291 {
00292   if (!conn)
00293     {
00294       errno = ENOTCONN;
00295       return FALSE;
00296     }
00297 
00298   errno = 0;
00299   return conn->safe_mode;
00300 }
00301 
00302 gboolean
00303 mongo_sync_conn_set_safe_mode (mongo_sync_connection *conn,
00304                                gboolean safe_mode)
00305 {
00306   if (!conn)
00307     {
00308       errno = ENOTCONN;
00309       return FALSE;
00310     }
00311 
00312   errno = 0;
00313   conn->safe_mode = safe_mode;
00314   return TRUE;
00315 }
00316 
00317 gboolean
00318 mongo_sync_conn_get_auto_reconnect (const mongo_sync_connection *conn)
00319 {
00320   if (!conn)
00321     {
00322       errno = ENOTCONN;
00323       return FALSE;
00324     }
00325 
00326   errno = 0;
00327   return conn->auto_reconnect;
00328 }
00329 
00330 gboolean
00331 mongo_sync_conn_set_auto_reconnect (mongo_sync_connection *conn,
00332                                     gboolean auto_reconnect)
00333 {
00334   if (!conn)
00335     {
00336       errno = ENOTCONN;
00337       return FALSE;
00338     }
00339 
00340   conn->auto_reconnect = auto_reconnect;
00341   return TRUE;
00342 }
00343 
00344 gboolean
00345 mongo_sync_conn_get_slaveok (const mongo_sync_connection *conn)
00346 {
00347   if (!conn)
00348     {
00349       errno = ENOTCONN;
00350       return FALSE;
00351     }
00352 
00353   errno = 0;
00354   return conn->slaveok;
00355 }
00356 
00357 gboolean
00358 mongo_sync_conn_set_slaveok (mongo_sync_connection *conn,
00359                              gboolean slaveok)
00360 {
00361   if (!conn)
00362     {
00363       errno = ENOTCONN;
00364       return FALSE;
00365     }
00366 
00367   errno = 0;
00368   conn->slaveok = slaveok;
00369   return TRUE;
00370 }
00371 
00372 #define _SLAVE_FLAG(c) ((c->slaveok) ? MONGO_WIRE_FLAG_QUERY_SLAVE_OK : 0)
00373 
00374 static inline gboolean
00375 _mongo_cmd_ensure_conn (mongo_sync_connection *conn,
00376                         gboolean force_master)
00377 {
00378   if (!conn)
00379     {
00380       errno = ENOTCONN;
00381       return FALSE;
00382     }
00383 
00384   if (force_master || !conn->slaveok)
00385     {
00386       errno = 0;
00387       if (!mongo_sync_cmd_is_master (conn))
00388         {
00389           if (errno == EPROTO)
00390             return FALSE;
00391           if (!conn->auto_reconnect)
00392             {
00393               errno = ENOTCONN;
00394               return FALSE;
00395             }
00396           if (!mongo_sync_reconnect (conn, TRUE))
00397             return FALSE;
00398         }
00399       return TRUE;
00400     }
00401 
00402   errno = 0;
00403   if (!mongo_sync_cmd_ping (conn))
00404     {
00405       if (errno == EPROTO)
00406         return FALSE;
00407       if (!conn->auto_reconnect)
00408         {
00409           errno = ENOTCONN;
00410           return FALSE;
00411         }
00412       if (!mongo_sync_reconnect (conn, FALSE))
00413         {
00414           errno = ENOTCONN;
00415           return FALSE;
00416         }
00417     }
00418   errno = 0;
00419   return TRUE;
00420 }
00421 
00422 static inline gboolean
00423 _mongo_cmd_verify_slaveok (mongo_sync_connection *conn)
00424 {
00425   if (!conn)
00426     {
00427       errno = ENOTCONN;
00428       return FALSE;
00429     }
00430 
00431   if (conn->slaveok || !conn->safe_mode)
00432     return TRUE;
00433 
00434   errno = 0;
00435   if (!mongo_sync_cmd_is_master (conn))
00436     {
00437       if (errno == EPROTO)
00438         return FALSE;
00439       if (!conn->auto_reconnect)
00440         {
00441           errno = ENOTCONN;
00442           return FALSE;
00443         }
00444       if (!mongo_sync_reconnect (conn, TRUE))
00445         return FALSE;
00446     }
00447   return TRUE;
00448 }
00449 
00450 static inline gboolean
00451 _mongo_sync_packet_send (mongo_sync_connection *conn,
00452                          mongo_packet *p,
00453                          gboolean force_master,
00454                          gboolean auto_reconnect)
00455 {
00456   gboolean out = FALSE;
00457 
00458   if (force_master)
00459     if (!_mongo_cmd_ensure_conn (conn, force_master))
00460       return FALSE;
00461 
00462   for (;;)
00463     {
00464       if (!mongo_packet_send ((mongo_connection *)conn, p))
00465         {
00466           int e = errno;
00467 
00468           if (!auto_reconnect || (conn && !conn->auto_reconnect))
00469             {
00470               mongo_wire_packet_free (p);
00471               errno = e;
00472               return FALSE;
00473             }
00474 
00475           if (out || !mongo_sync_reconnect (conn, force_master))
00476             {
00477               mongo_wire_packet_free (p);
00478               errno = e;
00479               return FALSE;
00480             }
00481 
00482           out = TRUE;
00483           continue;
00484         }
00485       break;
00486     }
00487   mongo_wire_packet_free (p);
00488   return TRUE;
00489 }
00490 
00491 static inline mongo_packet *
00492 _mongo_sync_packet_recv (mongo_sync_connection *conn, gint32 rid, gint32 flags)
00493 {
00494   mongo_packet *p;
00495   mongo_packet_header h;
00496   mongo_reply_packet_header rh;
00497 
00498   p = mongo_packet_recv ((mongo_connection *)conn);
00499   if (!p)
00500     return NULL;
00501 
00502   if (!mongo_wire_packet_get_header_raw (p, &h))
00503     {
00504       int e = errno;
00505 
00506       mongo_wire_packet_free (p);
00507       errno = e;
00508       return NULL;
00509     }
00510 
00511   if (h.resp_to != rid)
00512     {
00513       mongo_wire_packet_free (p);
00514       errno = EPROTO;
00515       return NULL;
00516     }
00517 
00518   if (!mongo_wire_reply_packet_get_header (p, &rh))
00519     {
00520       int e = errno;
00521 
00522       mongo_wire_packet_free (p);
00523       errno = e;
00524       return NULL;
00525     }
00526 
00527   if (rh.flags & flags)
00528     {
00529       mongo_wire_packet_free (p);
00530       errno = EPROTO;
00531       return NULL;
00532     }
00533 
00534   if (rh.returned == 0)
00535     {
00536       mongo_wire_packet_free (p);
00537       errno = ENOENT;
00538       return NULL;
00539     }
00540 
00541   return p;
00542 }
00543 
00544 static gboolean
00545 _mongo_sync_check_ok (bson *b)
00546 {
00547   bson_cursor *c;
00548   gdouble d;
00549 
00550   c = bson_find (b, "ok");
00551   if (!c)
00552     {
00553       errno = ENOENT;
00554       return FALSE;
00555     }
00556 
00557   if (!bson_cursor_get_double (c, &d))
00558     {
00559       bson_cursor_free (c);
00560       errno = EINVAL;
00561       return FALSE;
00562     }
00563   bson_cursor_free (c);
00564   errno = (d == 1) ? 0 : EPROTO;
00565   return (d == 1);
00566 }
00567 
00568 static gboolean
00569 _mongo_sync_get_error (const bson *rep, gchar **error)
00570 {
00571   bson_cursor *c;
00572 
00573   if (!error)
00574     return FALSE;
00575 
00576   c = bson_find (rep, "err");
00577   if (!c)
00578     {
00579       c = bson_find (rep, "errmsg");
00580       if (!c)
00581         {
00582           errno = EPROTO;
00583           return FALSE;
00584         }
00585     }
00586   if (bson_cursor_type (c) == BSON_TYPE_NONE ||
00587       bson_cursor_type (c) == BSON_TYPE_NULL)
00588     {
00589       *error = NULL;
00590       bson_cursor_free (c);
00591       return TRUE;
00592     }
00593   else if (bson_cursor_type (c) == BSON_TYPE_STRING)
00594     {
00595       const gchar *err;
00596 
00597       bson_cursor_get_string (c, &err);
00598       *error = g_strdup (err);
00599       bson_cursor_free (c);
00600       return TRUE;
00601     }
00602   errno = EPROTO;
00603   return FALSE;
00604 }
00605 
00606 static mongo_packet *
00607 _mongo_sync_packet_check_error (mongo_sync_connection *conn, mongo_packet *p,
00608                                 gboolean check_ok)
00609 {
00610   bson *b;
00611   gboolean error;
00612 
00613   if (!p)
00614     return NULL;
00615 
00616   if (!mongo_wire_reply_packet_get_nth_document (p, 1, &b))
00617     {
00618       mongo_wire_packet_free (p);
00619       errno = EPROTO;
00620       return NULL;
00621     }
00622   bson_finish (b);
00623 
00624   if (check_ok)
00625     {
00626       if (!_mongo_sync_check_ok (b))
00627         {
00628           int e = errno;
00629 
00630           g_free (conn->last_error);
00631           conn->last_error = NULL;
00632           _mongo_sync_get_error (b, &conn->last_error);
00633           bson_free (b);
00634           mongo_wire_packet_free (p);
00635           errno = e;
00636           return NULL;
00637         }
00638       bson_free (b);
00639       return p;
00640     }
00641 
00642   g_free (conn->last_error);
00643   conn->last_error = NULL;
00644   error = _mongo_sync_get_error (b, &conn->last_error);
00645   bson_free (b);
00646 
00647   if (error)
00648     {
00649       mongo_wire_packet_free (p);
00650       return NULL;
00651     }
00652   return p;
00653 }
00654 
00655 static inline gboolean
00656 _mongo_sync_cmd_verify_result (mongo_sync_connection *conn,
00657                                const gchar *ns)
00658 {
00659   gchar *error, *db, *tmp;
00660   gboolean res;
00661 
00662   if (!conn || !ns)
00663     return FALSE;
00664   if (!conn->safe_mode)
00665     return TRUE;
00666 
00667   tmp = g_strstr_len (ns, -1, ".");
00668   if (tmp)
00669     db = g_strndup (ns, tmp - ns);
00670   else
00671     db = g_strdup (ns);
00672 
00673   mongo_sync_cmd_get_last_error (conn, db, &error);
00674   g_free (db);
00675   res = (error) ? FALSE : TRUE;
00676   g_free (error);
00677 
00678   return res;
00679 }
00680 
00681 gboolean
00682 mongo_sync_cmd_update (mongo_sync_connection *conn,
00683                        const gchar *ns,
00684                        gint32 flags, const bson *selector,
00685                        const bson *update)
00686 {
00687   mongo_packet *p;
00688   gint32 rid;
00689 
00690   rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
00691 
00692   p = mongo_wire_cmd_update (rid, ns, flags, selector, update);
00693   if (!p)
00694     return FALSE;
00695 
00696   if (!_mongo_sync_packet_send (conn, p, TRUE, TRUE))
00697     return FALSE;
00698 
00699   return _mongo_sync_cmd_verify_result (conn, ns);
00700 }
00701 
00702 gboolean
00703 mongo_sync_cmd_insert_n (mongo_sync_connection *conn,
00704                          const gchar *ns, gint32 n,
00705                          const bson **docs)
00706 {
00707   mongo_packet *p;
00708   gint32 rid;
00709   gint32 pos = 0, c, i = 0;
00710   gint32 size = 0;
00711 
00712   if (!conn)
00713     {
00714       errno = ENOTCONN;
00715       return FALSE;
00716     }
00717 
00718   if (!ns || !docs)
00719     {
00720       errno = EINVAL;
00721       return FALSE;
00722     }
00723   if (n <= 0)
00724     {
00725       errno = EINVAL;
00726       return FALSE;
00727     }
00728 
00729   for (i = 0; i < n; i++)
00730     {
00731       if (bson_size (docs[i]) >= conn->max_insert_size)
00732         {
00733           errno = EMSGSIZE;
00734           return FALSE;
00735         }
00736     }
00737 
00738   do
00739     {
00740       i = pos;
00741       c = 0;
00742 
00743       while (i < n && size < conn->max_insert_size)
00744         {
00745           size += bson_size (docs[i++]);
00746           c++;
00747         }
00748       size = 0;
00749       if (i < n)
00750         c--;
00751 
00752       rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
00753 
00754       p = mongo_wire_cmd_insert_n (rid, ns, c, &docs[pos]);
00755       if (!p)
00756         return FALSE;
00757 
00758       if (!_mongo_sync_packet_send (conn, p, TRUE, TRUE))
00759         return FALSE;
00760 
00761       if (!_mongo_sync_cmd_verify_result (conn, ns))
00762         return FALSE;
00763 
00764       pos += c;
00765     } while (pos < n);
00766 
00767   return TRUE;
00768 }
00769 
00770 gboolean
00771 mongo_sync_cmd_insert (mongo_sync_connection *conn,
00772                        const gchar *ns, ...)
00773 {
00774   gboolean b;
00775   bson **docs, *d;
00776   gint32 n = 0;
00777   va_list ap;
00778 
00779   if (!conn)
00780     {
00781       errno = ENOTCONN;
00782       return FALSE;
00783     }
00784 
00785   if (!ns)
00786     {
00787       errno = EINVAL;
00788       return FALSE;
00789     }
00790 
00791   docs = (bson **)g_new0 (bson *, 1);
00792 
00793   va_start (ap, ns);
00794   while ((d = (bson *)va_arg (ap, gpointer)))
00795     {
00796       if (bson_size (d) < 0)
00797         {
00798           g_free (docs);
00799           errno = EINVAL;
00800           return FALSE;
00801         }
00802 
00803       docs = (bson **)g_renew (bson *, docs, n + 1);
00804       docs[n++] = d;
00805     }
00806   va_end (ap);
00807 
00808   b = mongo_sync_cmd_insert_n (conn, ns, n, (const bson **)docs);
00809   g_free (docs);
00810   return b;
00811 }
00812 
00813 mongo_packet *
00814 mongo_sync_cmd_query (mongo_sync_connection *conn,
00815                       const gchar *ns, gint32 flags,
00816                       gint32 skip, gint32 ret,
00817                       const bson *query, const bson *sel)
00818 {
00819   mongo_packet *p;
00820   gint32 rid;
00821 
00822   if (!_mongo_cmd_verify_slaveok (conn))
00823     return FALSE;
00824 
00825   rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
00826 
00827   p = mongo_wire_cmd_query (rid, ns, flags | _SLAVE_FLAG (conn),
00828                             skip, ret, query, sel);
00829   if (!p)
00830     return NULL;
00831 
00832   if (!_mongo_sync_packet_send (conn, p,
00833                                 !((conn && conn->slaveok) ||
00834                                   (flags & MONGO_WIRE_FLAG_QUERY_SLAVE_OK)),
00835                                 TRUE))
00836     return NULL;
00837 
00838   p = _mongo_sync_packet_recv (conn, rid, MONGO_REPLY_FLAG_QUERY_FAIL);
00839   return _mongo_sync_packet_check_error (conn, p, FALSE);
00840 }
00841 
00842 mongo_packet *
00843 mongo_sync_cmd_get_more (mongo_sync_connection *conn,
00844                          const gchar *ns,
00845                          gint32 ret, gint64 cursor_id)
00846 {
00847   mongo_packet *p;
00848   gint32 rid;
00849 
00850   if (!_mongo_cmd_verify_slaveok (conn))
00851     return FALSE;
00852 
00853   rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
00854 
00855   p = mongo_wire_cmd_get_more (rid, ns, ret, cursor_id);
00856   if (!p)
00857     return NULL;
00858 
00859   if (!_mongo_sync_packet_send (conn, p, FALSE, TRUE))
00860     return FALSE;
00861 
00862   p = _mongo_sync_packet_recv (conn, rid, MONGO_REPLY_FLAG_NO_CURSOR);
00863   return _mongo_sync_packet_check_error (conn, p, FALSE);
00864 }
00865 
00866 gboolean
00867 mongo_sync_cmd_delete (mongo_sync_connection *conn, const gchar *ns,
00868                        gint32 flags, const bson *sel)
00869 {
00870   mongo_packet *p;
00871   gint32 rid;
00872 
00873   rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
00874 
00875   p = mongo_wire_cmd_delete (rid, ns, flags, sel);
00876   if (!p)
00877     return FALSE;
00878 
00879   return _mongo_sync_packet_send (conn, p, TRUE, TRUE);
00880 }
00881 
00882 gboolean
00883 mongo_sync_cmd_kill_cursors (mongo_sync_connection *conn,
00884                              gint32 n, ...)
00885 {
00886   mongo_packet *p;
00887   gint32 rid;
00888   va_list ap;
00889 
00890   if (n <= 0)
00891     {
00892       errno = EINVAL;
00893       return FALSE;
00894     }
00895 
00896   rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
00897 
00898   va_start (ap, n);
00899   p = mongo_wire_cmd_kill_cursors_va (rid, n, ap);
00900   if (!p)
00901     {
00902       int e = errno;
00903 
00904       va_end (ap);
00905       errno = e;
00906       return FALSE;
00907     }
00908   va_end (ap);
00909 
00910   return _mongo_sync_packet_send (conn, p, FALSE, TRUE);
00911 }
00912 
00913 static mongo_packet *
00914 _mongo_sync_cmd_custom (mongo_sync_connection *conn,
00915                         const gchar *db,
00916                         const bson *command,
00917                         gboolean check_conn,
00918                         gboolean force_master)
00919 {
00920   mongo_packet *p;
00921   gint32 rid;
00922 
00923   if (!conn)
00924     {
00925       errno = ENOTCONN;
00926       return NULL;
00927     }
00928 
00929   rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
00930 
00931   p = mongo_wire_cmd_custom (rid, db, _SLAVE_FLAG (conn), command);
00932   if (!p)
00933     return NULL;
00934 
00935   if (!_mongo_sync_packet_send (conn, p, force_master, check_conn))
00936     return NULL;
00937 
00938   p = _mongo_sync_packet_recv (conn, rid, MONGO_REPLY_FLAG_QUERY_FAIL);
00939   return _mongo_sync_packet_check_error (conn, p, TRUE);
00940 }
00941 
00942 mongo_packet *
00943 mongo_sync_cmd_custom (mongo_sync_connection *conn,
00944                        const gchar *db,
00945                        const bson *command)
00946 {
00947   return _mongo_sync_cmd_custom (conn, db, command, TRUE, FALSE);
00948 }
00949 
00950 gdouble
00951 mongo_sync_cmd_count (mongo_sync_connection *conn,
00952                       const gchar *db, const gchar *coll,
00953                       const bson *query)
00954 {
00955   mongo_packet *p;
00956   bson *cmd;
00957   bson_cursor *c;
00958   gdouble d;
00959 
00960   cmd = bson_new_sized (bson_size (query) + 32);
00961   bson_append_string (cmd, "count", coll, -1);
00962   if (query)
00963     bson_append_document (cmd, "query", query);
00964   bson_finish (cmd);
00965 
00966   p = _mongo_sync_cmd_custom (conn, db, cmd, TRUE, FALSE);
00967   if (!p)
00968     {
00969       int e = errno;
00970 
00971       bson_free (cmd);
00972       errno = e;
00973       return -1;
00974     }
00975   bson_free (cmd);
00976 
00977   if (!mongo_wire_reply_packet_get_nth_document (p, 1, &cmd))
00978     {
00979       int e = errno;
00980 
00981       mongo_wire_packet_free (p);
00982       errno = e;
00983       return -1;
00984     }
00985   mongo_wire_packet_free (p);
00986   bson_finish (cmd);
00987 
00988   c = bson_find (cmd, "n");
00989   if (!c)
00990     {
00991       bson_free (cmd);
00992       errno = ENOENT;
00993       return -1;
00994     }
00995   if (!bson_cursor_get_double (c, &d))
00996     {
00997       bson_free (cmd);
00998       bson_cursor_free (c);
00999       errno = EINVAL;
01000       return -1;
01001     }
01002   bson_cursor_free (c);
01003   bson_free (cmd);
01004 
01005   return d;
01006 }
01007 
01008 gboolean
01009 mongo_sync_cmd_create (mongo_sync_connection *conn,
01010                        const gchar *db, const gchar *coll,
01011                        gint flags, ...)
01012 {
01013   mongo_packet *p;
01014   bson *cmd;
01015 
01016   if (!conn)
01017     {
01018       errno = ENOTCONN;
01019       return FALSE;
01020     }
01021   if (!db || !coll)
01022     {
01023       errno = EINVAL;
01024       return FALSE;
01025     }
01026 
01027   cmd = bson_new_sized (128);
01028   bson_append_string (cmd, "create", coll, -1);
01029   if (flags & MONGO_COLLECTION_AUTO_INDEX_ID)
01030     bson_append_boolean (cmd, "autoIndexId", TRUE);
01031   if (flags & MONGO_COLLECTION_CAPPED ||
01032       flags & MONGO_COLLECTION_CAPPED_MAX ||
01033       flags & MONGO_COLLECTION_SIZED)
01034     {
01035       va_list ap;
01036       gint64 i;
01037 
01038       if (flags & MONGO_COLLECTION_CAPPED ||
01039           flags & MONGO_COLLECTION_CAPPED_MAX)
01040         bson_append_boolean (cmd, "capped", TRUE);
01041 
01042       va_start (ap, flags);
01043       i = (gint64)va_arg (ap, gint64);
01044       if (i <= 0)
01045         {
01046           bson_free (cmd);
01047           errno = ERANGE;
01048           return FALSE;
01049         }
01050       bson_append_int64 (cmd, "size", i);
01051 
01052       if (flags & MONGO_COLLECTION_CAPPED_MAX)
01053         {
01054           i = (gint64)va_arg (ap, gint64);
01055           if (i <= 0)
01056             {
01057               bson_free (cmd);
01058               errno = ERANGE;
01059               return FALSE;
01060             }
01061           bson_append_int64 (cmd, "max", i);
01062         }
01063       va_end (ap);
01064     }
01065   bson_finish (cmd);
01066 
01067   p = _mongo_sync_cmd_custom (conn, db, cmd, TRUE, TRUE);
01068   if (!p)
01069     {
01070       int e = errno;
01071 
01072       bson_free (cmd);
01073       errno = e;
01074       return FALSE;
01075     }
01076   bson_free (cmd);
01077   mongo_wire_packet_free (p);
01078 
01079   return TRUE;
01080 }
01081 
01082 bson *
01083 mongo_sync_cmd_exists (mongo_sync_connection *conn,
01084                        const gchar *db, const gchar *coll)
01085 {
01086   bson *cmd, *r;
01087   mongo_packet *p;
01088   gchar *ns, *sys;
01089   gint32 rid;
01090 
01091   if (!conn)
01092     {
01093       errno = ENOTCONN;
01094       return NULL;
01095     }
01096   if (!db || !coll)
01097     {
01098       errno = EINVAL;
01099       return NULL;
01100     }
01101 
01102   rid = mongo_connection_get_requestid ((mongo_connection *)conn) + 1;
01103 
01104   ns = g_strconcat (db, ".", coll, NULL);
01105   cmd = bson_new_sized (128);
01106   bson_append_string (cmd, "name", ns, -1);
01107   bson_finish (cmd);
01108   g_free (ns);
01109 
01110   sys = g_strconcat (db, ".system.namespaces", NULL);
01111 
01112   p = mongo_wire_cmd_query (rid, sys, _SLAVE_FLAG (conn), 0, 1, cmd, NULL);
01113   if (!p)
01114     {
01115       int e = errno;
01116 
01117       bson_free (cmd);
01118       g_free (sys);
01119 
01120       errno = e;
01121       return NULL;
01122     }
01123   g_free (sys);
01124   bson_free (cmd);
01125 
01126   if (!_mongo_sync_packet_send (conn, p, !conn->slaveok, TRUE))
01127     return NULL;
01128 
01129   p = _mongo_sync_packet_recv (conn, rid, MONGO_REPLY_FLAG_QUERY_FAIL);
01130   if (!p)
01131     return NULL;
01132 
01133   p = _mongo_sync_packet_check_error (conn, p, FALSE);
01134   if (!p)
01135     return NULL;
01136 
01137   if (!mongo_wire_reply_packet_get_nth_document (p, 1, &r))
01138     {
01139       int e = errno;
01140 
01141       mongo_wire_packet_free (p);
01142       errno = e;
01143       return NULL;
01144     }
01145   mongo_wire_packet_free (p);
01146   bson_finish (r);
01147 
01148   return r;
01149 }
01150 
01151 gboolean
01152 mongo_sync_cmd_drop (mongo_sync_connection *conn,
01153                      const gchar *db, const gchar *coll)
01154 {
01155   mongo_packet *p;
01156   bson *cmd;
01157 
01158   cmd = bson_new_sized (64);
01159   bson_append_string (cmd, "drop", coll, -1);
01160   bson_finish (cmd);
01161 
01162   p = _mongo_sync_cmd_custom (conn, db, cmd, TRUE, TRUE);
01163   if (!p)
01164     {
01165       int e = errno;
01166 
01167       bson_free (cmd);
01168       errno = e;
01169       return FALSE;
01170     }
01171   bson_free (cmd);
01172   mongo_wire_packet_free (p);
01173 
01174   return TRUE;
01175 }
01176 
01177 gboolean
01178 mongo_sync_cmd_get_last_error (mongo_sync_connection *conn,
01179                                const gchar *db, gchar **error)
01180 {
01181   mongo_packet *p;
01182   bson *cmd;
01183 
01184   if (!conn)
01185     {
01186       errno = ENOTCONN;
01187       return FALSE;
01188     }
01189   if (!error)
01190     {
01191       errno = EINVAL;
01192       return FALSE;
01193     }
01194 
01195   cmd = bson_new_sized (64);
01196   bson_append_int32 (cmd, "getlasterror", 1);
01197   bson_finish (cmd);
01198 
01199   p = _mongo_sync_cmd_custom (conn, db, cmd, FALSE, FALSE);
01200   if (!p)
01201     {
01202       int e = errno;
01203 
01204       bson_free (cmd);
01205       errno = e;
01206       return FALSE;
01207     }
01208   bson_free (cmd);
01209 
01210   if (!mongo_wire_reply_packet_get_nth_document (p, 1, &cmd))
01211     {
01212       int e = errno;
01213 
01214       mongo_wire_packet_free (p);
01215       errno = e;
01216       return FALSE;
01217     }
01218   mongo_wire_packet_free (p);
01219   bson_finish (cmd);
01220 
01221   if (!_mongo_sync_get_error (cmd, error))
01222     {
01223       int e = errno;
01224 
01225       bson_free (cmd);
01226       errno = e;
01227       return FALSE;
01228     }
01229   bson_free (cmd);
01230 
01231   if (*error == NULL)
01232     *error = g_strdup (conn->last_error);
01233   else
01234     {
01235       g_free (conn->last_error);
01236       conn->last_error = NULL;
01237     }
01238 
01239   return TRUE;
01240 }
01241 
01242 gboolean
01243 mongo_sync_cmd_reset_error (mongo_sync_connection *conn,
01244                             const gchar *db)
01245 {
01246   mongo_packet *p;
01247   bson *cmd;
01248 
01249   if (conn)
01250     {
01251       g_free (conn->last_error);
01252       conn->last_error = NULL;
01253     }
01254 
01255   cmd = bson_new_sized (32);
01256   bson_append_int32 (cmd, "reseterror", 1);
01257   bson_finish (cmd);
01258 
01259   p = _mongo_sync_cmd_custom (conn, db, cmd, FALSE, FALSE);
01260   if (!p)
01261     {
01262       int e = errno;
01263 
01264       bson_free (cmd);
01265       errno = e;
01266       return FALSE;
01267     }
01268   bson_free (cmd);
01269   mongo_wire_packet_free (p);
01270   return TRUE;
01271 }
01272 
01273 gboolean
01274 mongo_sync_cmd_is_master (mongo_sync_connection *conn)
01275 {
01276   bson *cmd, *res, *hosts;
01277   mongo_packet *p;
01278   bson_cursor *c;
01279   gboolean b;
01280   GList *l;
01281 
01282   cmd = bson_new_sized (32);
01283   bson_append_int32 (cmd, "ismaster", 1);
01284   bson_finish (cmd);
01285 
01286   p = _mongo_sync_cmd_custom (conn, "system", cmd, FALSE, FALSE);
01287   if (!p)
01288     {
01289       int e = errno;
01290 
01291       bson_free (cmd);
01292       errno = e;
01293       return FALSE;
01294     }
01295   bson_free (cmd);
01296 
01297   if (!mongo_wire_reply_packet_get_nth_document (p, 1, &res))
01298     {
01299       int e = errno;
01300 
01301       mongo_wire_packet_free (p);
01302       errno = e;
01303       return FALSE;
01304     }
01305   mongo_wire_packet_free (p);
01306   bson_finish (res);
01307 
01308   c = bson_find (res, "ismaster");
01309   if (!bson_cursor_get_boolean (c, &b))
01310     {
01311       bson_cursor_free (c);
01312       bson_free (res);
01313       errno = EPROTO;
01314       return FALSE;
01315     }
01316   bson_cursor_free (c);
01317 
01318   if (!b)
01319     {
01320       const gchar *s;
01321 
01322       /* We're not the master, so we should have a 'primary' key in
01323          the response. */
01324       c = bson_find (res, "primary");
01325       if (bson_cursor_get_string (c, &s))
01326         {
01327           g_free (conn->rs.primary);
01328           conn->rs.primary = g_strdup (s);
01329         }
01330       bson_cursor_free (c);
01331     }
01332 
01333   /* Find all the members of the set, and cache them. */
01334   c = bson_find (res, "hosts");
01335   if (!c)
01336     {
01337       bson_free (res);
01338       errno = 0;
01339       return b;
01340     }
01341 
01342   if (!bson_cursor_get_array (c, &hosts))
01343     {
01344       bson_cursor_free (c);
01345       bson_free (res);
01346       errno = 0;
01347       return b;
01348     }
01349   bson_cursor_free (c);
01350   bson_finish (hosts);
01351 
01352   /* Delete the old host list. */
01353   l = conn->rs.hosts;
01354   while (l)
01355     {
01356       g_free (l->data);
01357       l = g_list_delete_link (l, l);
01358     }
01359   conn->rs.hosts = NULL;
01360 
01361   c = bson_cursor_new (hosts);
01362   while (bson_cursor_next (c))
01363     {
01364       const gchar *s;
01365 
01366       if (bson_cursor_get_string (c, &s))
01367         conn->rs.hosts = g_list_append (conn->rs.hosts, g_strdup (s));
01368     }
01369   bson_cursor_free (c);
01370   bson_free (hosts);
01371 
01372   c = bson_find (res, "passives");
01373   if (bson_cursor_get_array (c, &hosts))
01374     {
01375       bson_cursor_free (c);
01376       bson_finish (hosts);
01377 
01378       c = bson_cursor_new (hosts);
01379       while (bson_cursor_next (c))
01380         {
01381           const gchar *s;
01382 
01383           if (bson_cursor_get_string (c, &s))
01384             conn->rs.hosts = g_list_append (conn->rs.hosts, g_strdup (s));
01385         }
01386       bson_free (hosts);
01387     }
01388   bson_cursor_free (c);
01389 
01390   bson_free (res);
01391   errno = 0;
01392   return b;
01393 }
01394 
01395 gboolean
01396 mongo_sync_cmd_ping (mongo_sync_connection *conn)
01397 {
01398   bson *cmd;
01399   mongo_packet *p;
01400 
01401   cmd = bson_new_sized (32);
01402   bson_append_int32 (cmd, "ping", 1);
01403   bson_finish (cmd);
01404 
01405   p = _mongo_sync_cmd_custom (conn, "system", cmd, FALSE, FALSE);
01406   if (!p)
01407     {
01408       int e = errno;
01409 
01410       bson_free (cmd);
01411       errno = e;
01412       return FALSE;
01413     }
01414   bson_free (cmd);
01415   mongo_wire_packet_free (p);
01416 
01417   errno = 0;
01418   return TRUE;
01419 }
01420 
01421 static gchar *
01422 _pass_digest (const gchar *user, const gchar *pw)
01423 {
01424   GChecksum *chk;
01425   gchar *digest;
01426 
01427   chk = g_checksum_new (G_CHECKSUM_MD5);
01428   g_checksum_update (chk, (const guchar *)user, -1);
01429   g_checksum_update (chk, (const guchar *)":mongo:", 7);
01430   g_checksum_update (chk, (const guchar *)pw, -1);
01431   digest = g_strdup (g_checksum_get_string (chk));
01432   g_checksum_free (chk);
01433 
01434   return digest;
01435 }
01436 
01437 gboolean
01438 mongo_sync_cmd_user_add (mongo_sync_connection *conn,
01439                          const gchar *db,
01440                          const gchar *user,
01441                          const gchar *pw)
01442 {
01443   bson *s, *u;
01444   gchar *userns;
01445   gchar *hex_digest;
01446 
01447   if (!db || !user || !pw)
01448     {
01449       errno = EINVAL;
01450       return FALSE;
01451     }
01452 
01453   userns = g_strconcat (db, ".system.users", NULL);
01454 
01455   hex_digest = _pass_digest (user, pw);
01456 
01457   s = bson_build (BSON_TYPE_STRING, "user", user, -1,
01458                   BSON_TYPE_NONE);
01459   bson_finish (s);
01460   u = bson_build_full (BSON_TYPE_DOCUMENT, "$set", TRUE,
01461                        bson_build (BSON_TYPE_STRING, "pwd", hex_digest, -1,
01462                                    BSON_TYPE_NONE),
01463                        BSON_TYPE_NONE);
01464   bson_finish (u);
01465   g_free (hex_digest);
01466 
01467   if (!mongo_sync_cmd_update (conn, userns, MONGO_WIRE_FLAG_UPDATE_UPSERT,
01468                               s, u))
01469     {
01470       int e = errno;
01471 
01472       bson_free (s);
01473       bson_free (u);
01474       g_free (userns);
01475       errno = e;
01476       return FALSE;
01477     }
01478   bson_free (s);
01479   bson_free (u);
01480   g_free (userns);
01481 
01482   return TRUE;
01483 }
01484 
01485 gboolean
01486 mongo_sync_cmd_user_remove (mongo_sync_connection *conn,
01487                             const gchar *db,
01488                             const gchar *user)
01489 {
01490   bson *s;
01491   gchar *userns;
01492 
01493   if (!db || !user)
01494     {
01495       errno = EINVAL;
01496       return FALSE;
01497     }
01498 
01499   userns = g_strconcat (db, ".system.users", NULL);
01500 
01501   s = bson_build (BSON_TYPE_STRING, "user", user, -1,
01502                   BSON_TYPE_NONE);
01503   bson_finish (s);
01504 
01505   if (!mongo_sync_cmd_delete (conn, userns, 0, s))
01506     {
01507       int e = errno;
01508 
01509       bson_free (s);
01510       g_free (userns);
01511       errno = e;
01512       return FALSE;
01513     }
01514   bson_free (s);
01515   g_free (userns);
01516 
01517   return TRUE;
01518 }
01519 
01520 gboolean
01521 mongo_sync_cmd_authenticate (mongo_sync_connection *conn,
01522                              const gchar *db,
01523                              const gchar *user,
01524                              const gchar *pw)
01525 {
01526   bson *b;
01527   mongo_packet *p;
01528   const gchar *s;
01529   gchar *nonce;
01530   bson_cursor *c;
01531 
01532   GChecksum *chk;
01533   gchar *hex_digest;
01534   const gchar *digest;
01535 
01536   if (!db || !user || !pw)
01537     {
01538       errno = EINVAL;
01539       return FALSE;
01540     }
01541 
01542   /* Obtain nonce */
01543   b = bson_new_sized (32);
01544   bson_append_int32 (b, "getnonce", 1);
01545   bson_finish (b);
01546 
01547   p = mongo_sync_cmd_custom (conn, db, b);
01548   if (!p)
01549     {
01550       int e = errno;
01551 
01552       bson_free (b);
01553       errno = e;
01554       return FALSE;
01555     }
01556   bson_free (b);
01557 
01558   if (!mongo_wire_reply_packet_get_nth_document (p, 1, &b))
01559     {
01560       int e = errno;
01561 
01562       mongo_wire_packet_free (p);
01563       errno = e;
01564       return FALSE;
01565     }
01566   mongo_wire_packet_free (p);
01567   bson_finish (b);
01568 
01569   c = bson_find (b, "nonce");
01570   if (!c)
01571     {
01572       bson_free (b);
01573       errno = EPROTO;
01574       return FALSE;
01575     }
01576   if (!bson_cursor_get_string (c, &s))
01577     {
01578       bson_free (b);
01579       errno = EPROTO;
01580       return FALSE;
01581     }
01582   nonce = g_strdup (s);
01583   bson_cursor_free (c);
01584   bson_free (b);
01585 
01586   /* Generate the password digest. */
01587   hex_digest = _pass_digest (user, pw);
01588 
01589   /* Generate the key */
01590   chk = g_checksum_new (G_CHECKSUM_MD5);
01591   g_checksum_update (chk, (const guchar *)nonce, -1);
01592   g_checksum_update (chk, (const guchar *)user, -1);
01593   g_checksum_update (chk, (const guchar *)hex_digest, -1);
01594   g_free (hex_digest);
01595 
01596   digest = g_checksum_get_string (chk);
01597 
01598   /* Run the authenticate command. */
01599   b = bson_build (BSON_TYPE_INT32, "authenticate", 1,
01600                   BSON_TYPE_STRING, "user", user, -1,
01601                   BSON_TYPE_STRING, "nonce", nonce, -1,
01602                   BSON_TYPE_STRING, "key", digest, -1,
01603                   BSON_TYPE_NONE);
01604   bson_finish (b);
01605   g_free (nonce);
01606   g_checksum_free (chk);
01607 
01608   p = mongo_sync_cmd_custom (conn, db, b);
01609   if (!p)
01610     {
01611       int e = errno;
01612 
01613       bson_free (b);
01614       errno = e;
01615       return FALSE;
01616     }
01617   bson_free (b);
01618   mongo_wire_packet_free (p);
01619 
01620   return TRUE;
01621 }
01622 
01623 static GString *
01624 _mongo_index_gen_name (const bson *key)
01625 {
01626   bson_cursor *c;
01627   GString *name;
01628 
01629   name = g_string_new ("_");
01630   c = bson_cursor_new (key);
01631   while (bson_cursor_next (c))
01632     {
01633       gint64 v = 0;
01634 
01635       g_string_append (name, bson_cursor_key (c));
01636       g_string_append_c (name, '_');
01637 
01638       switch (bson_cursor_type (c))
01639         {
01640         case BSON_TYPE_BOOLEAN:
01641           {
01642             gboolean vb;
01643 
01644             bson_cursor_get_boolean (c, &vb);
01645             v = vb;
01646             break;
01647           }
01648         case BSON_TYPE_INT32:
01649           {
01650             gint32 vi;
01651 
01652             bson_cursor_get_int32 (c, &vi);
01653             v = vi;
01654             break;
01655           }
01656         case BSON_TYPE_INT64:
01657           {
01658             gint64 vl;
01659 
01660             bson_cursor_get_int64 (c, &vl);
01661             v = vl;
01662             break;
01663           }
01664         case BSON_TYPE_DOUBLE:
01665           {
01666             gdouble vd;
01667 
01668             bson_cursor_get_double (c, &vd);
01669             v = (gint64)vd;
01670             break;
01671           }
01672         default:
01673           break;
01674         }
01675       if (v != 0)
01676         g_string_append_printf (name, "%" G_GINT64_FORMAT "_", v);
01677     }
01678   bson_cursor_free (c);
01679 
01680   return name;
01681 }
01682 
01683 gboolean
01684 mongo_sync_cmd_index_create (mongo_sync_connection *conn,
01685                              const gchar *ns,
01686                              const bson *key,
01687                              gint options)
01688 {
01689   GString *name;
01690   gchar *idxns, *t;
01691   bson *cmd;
01692 
01693   if (!conn)
01694     {
01695       errno = ENOTCONN;
01696       return FALSE;
01697     }
01698   if (!ns || !key)
01699     {
01700       errno = EINVAL;
01701       return FALSE;
01702     }
01703   if (strchr (ns, '.') == NULL)
01704     {
01705       errno = EINVAL;
01706       return FALSE;
01707     }
01708 
01709   name = _mongo_index_gen_name (key);
01710 
01711   cmd = bson_new_sized (bson_size (key) + name->len + 128);
01712   bson_append_document (cmd, "key", key);
01713   bson_append_string (cmd, "ns", ns, -1);
01714   bson_append_string (cmd, "name", name->str, name->len);
01715   if (options & MONGO_INDEX_UNIQUE)
01716     bson_append_boolean (cmd, "unique", TRUE);
01717   if (options & MONGO_INDEX_DROP_DUPS)
01718     bson_append_boolean (cmd, "dropDups", TRUE);
01719   if (options & MONGO_INDEX_BACKGROUND)
01720     bson_append_boolean (cmd, "background", TRUE);
01721   if (options & MONGO_INDEX_SPARSE)
01722     bson_append_boolean (cmd, "sparse", TRUE);
01723   bson_finish (cmd);
01724   g_string_free (name, TRUE);
01725 
01726   t = g_strdup (ns);
01727   *(strchr (t, '.')) = '\0';
01728   idxns = g_strconcat (t, ".system.indexes", NULL);
01729   g_free (t);
01730 
01731   if (!mongo_sync_cmd_insert_n (conn, idxns, 1, (const bson **)&cmd))
01732     {
01733       int e = errno;
01734 
01735       bson_free (cmd);
01736       g_free (idxns);
01737       errno = e;
01738       return FALSE;
01739     }
01740   bson_free (cmd);
01741   g_free (idxns);
01742 
01743   return TRUE;
01744 }
01745 
01746 static gboolean
01747 _mongo_sync_cmd_index_drop (mongo_sync_connection *conn,
01748                             const gchar *full_ns,
01749                             const gchar *index_name)
01750 {
01751   bson *cmd;
01752   gchar *db, *ns;
01753   mongo_packet *p;
01754 
01755   if (!conn)
01756     {
01757       errno = ENOTCONN;
01758       return FALSE;
01759     }
01760   if (!full_ns || !index_name)
01761     {
01762       errno = EINVAL;
01763       return FALSE;
01764     }
01765   ns = strchr (full_ns, '.');
01766   if (ns == NULL)
01767     {
01768       errno = EINVAL;
01769       return FALSE;
01770     }
01771   ns++;
01772 
01773   cmd = bson_new_sized (256 + strlen (index_name));
01774   bson_append_string (cmd, "deleteIndexes", ns, -1);
01775   bson_append_string (cmd, "index", index_name, -1);
01776   bson_finish (cmd);
01777 
01778   db = g_strndup (full_ns, ns - full_ns - 1);
01779   p = mongo_sync_cmd_custom (conn, db, cmd);
01780   if (!p)
01781     {
01782       int e = errno;
01783 
01784       bson_free (cmd);
01785       g_free (db);
01786       errno = e;
01787       return FALSE;
01788     }
01789   mongo_wire_packet_free (p);
01790   g_free (db);
01791   bson_free (cmd);
01792 
01793   return TRUE;
01794 }
01795 
01796 gboolean
01797 mongo_sync_cmd_index_drop (mongo_sync_connection *conn,
01798                            const gchar *ns,
01799                            const bson *key)
01800 {
01801   GString *name;
01802   gboolean b;
01803 
01804   if (!key)
01805     {
01806       errno = EINVAL;
01807       return FALSE;
01808     }
01809 
01810   name = _mongo_index_gen_name (key);
01811 
01812   b = _mongo_sync_cmd_index_drop (conn, ns, name->str);
01813   g_string_free (name, TRUE);
01814   return b;
01815 }
01816 
01817 gboolean
01818 mongo_sync_cmd_index_drop_all (mongo_sync_connection *conn,
01819                                const gchar *ns)
01820 {
01821   return _mongo_sync_cmd_index_drop (conn, ns, "*");
01822 }
 All Data Structures Files Functions Variables Enumerations Enumerator Defines