When exporting a message, write to the client 10 KB at a time.
[citadel.git] / citadel / modules / migrate / serv_migrate.c
index aad6615f553dce0659d0f3954edbbd6810411f6d..7cc8fc041fde63275598c34fd4c85e202cd5bd09 100644 (file)
 /*
  * Explanation of <progress> tags:
  *
- * 0%              nothing
- * 2%              finished exporting configuration
- * 7%              finished exporting users
- * 12%             finished exporting openids
- * 17%             finished exporting rooms
- * 18%             finished exporting floors
- * 25%             finished exporting visits
- * 100%            finished exporting messages
+ * 0%          started
+ * 2%          finished exporting configuration
+ * 7%          finished exporting users
+ * 12%         finished exporting openids
+ * 17%         finished exporting rooms
+ * 18%         finished exporting floors
+ * 25%         finished exporting visits
+ * 26-99%      exporting messages
+ * 100%                finished exporting messages
+ *
+ * These tags are inserted into the XML stream to give the reader an approximation of its progress.
  */
 
 #include "sysdep.h"
@@ -134,15 +137,24 @@ void migr_export_users(void) {
 
 
 void migr_export_room_msg(long msgnum, void *userdata) {
-       cprintf("%ld\n", msgnum);
+       static int count = 0;
+
+       cprintf("%ld,", msgnum);
+       if (++count%10==0) {
+               cprintf("\n");
+       }
        fprintf(migr_global_message_list, "%ld\n", msgnum);
 }
 
 
 void migr_export_rooms_backend(struct ctdlroom *buf, void *data) {
        client_write(HKEY("<room>\n"));
-       client_write(HKEY("<QRname>")); xml_strout(buf->QRname);        client_write(HKEY("</QRname>\n"));
-       client_write(HKEY("<QRpasswd>"));       xml_strout(buf->QRpasswd);      client_write(HKEY("</QRpasswd>\n"));
+       client_write(HKEY("<QRname>"));
+       xml_strout(buf->QRname);
+       client_write(HKEY("</QRname>\n"));
+       client_write(HKEY("<QRpasswd>"));
+       xml_strout(buf->QRpasswd);
+       client_write(HKEY("</QRpasswd>\n"));
        cprintf("<QRroomaide>%ld</QRroomaide>\n", buf->QRroomaide);
        cprintf("<QRhighest>%ld</QRhighest>\n", buf->QRhighest);
        cprintf("<QRgen>%ld</QRgen>\n", (long)buf->QRgen);
@@ -165,16 +177,15 @@ void migr_export_rooms_backend(struct ctdlroom *buf, void *data) {
        client_write(HKEY("</room>\n"));
 
        /* message list goes inside this tag */
-
        CtdlGetRoom(&CC->room, buf->QRname);
        client_write(HKEY("<room_messages>"));
-       client_write(HKEY("<FRname>")); xml_strout(CC->room.QRname);    client_write(HKEY("</FRname>\n"));
-       client_write(HKEY("<FRmsglist>"));
+       client_write(HKEY("<FRname>"));
+       xml_strout(buf->QRname);                        // buf->QRname rather than CC->room.QRname to guarantee consistency
+       client_write(HKEY("</FRname>\n"));
+       client_write(HKEY("<FRmsglist>\n"));
        CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_export_room_msg, NULL);
        client_write(HKEY("</FRmsglist>\n"));
        client_write(HKEY("</room_messages>\n"));
-
-
 }
 
 
@@ -193,10 +204,13 @@ void migr_export_rooms(void) {
         * exporting the message multiple times.)
         */
        snprintf(cmd, sizeof cmd, "sort -n <%s >%s", migr_tempfilename1, migr_tempfilename2);
-       if (system(cmd) != 0) syslog(LOG_ALERT, "Error %d", errno);
+       if (system(cmd) != 0) {
+               syslog(LOG_ERR, "migrate: error %d", errno);
+       }
        snprintf(cmd, sizeof cmd, "uniq <%s >%s", migr_tempfilename2, migr_tempfilename1);
-       if (system(cmd) != 0) syslog(LOG_ALERT, "Error %d", errno);
-
+       if (system(cmd) != 0) {
+               syslog(LOG_ERR, "migrate: error %d", errno);
+       }
 
        snprintf(cmd, sizeof cmd, "wc -l %s", migr_tempfilename1);
        FILE *fp = popen(cmd, "r");
@@ -208,7 +222,7 @@ void migr_export_rooms(void) {
        else {
                total_msgs = 1; // any nonzero just to keep it from barfing
        }
-       syslog(LOG_DEBUG, "Total messages to be exported: %d", total_msgs);
+       syslog(LOG_DEBUG, "migrate: total messages to be exported: %d", total_msgs);
 }
 
 
@@ -295,12 +309,14 @@ void migr_export_message(long msgnum) {
        struct MetaData smi;
        struct CtdlMessage *msg;
        struct ser_ret smr;
+       long bytes_written = 0;
+       long this_block = 0;
+
+       // We can use a static buffer here because there will never be more than
+       // one of this operation happening at any given time, and it's really best
+       // to just keep it allocated once instead of torturing malloc/free.
+       // Call this function with msgnum "-1" to free the buffer when finished.
 
-       /* We can use a static buffer here because there will never be more than
-        * one of this operation happening at any given time, and it's really best
-        * to just keep it allocated once instead of torturing malloc/free.
-        * Call this function with msgnum "-1" to free the buffer when finished.
-        */
        static int encoded_alloc = 0;
        static char *encoded_msg = NULL;
 
@@ -313,10 +329,10 @@ void migr_export_message(long msgnum) {
                return;
        }
 
-       /* Ok, here we go ... */
+       // Ok, here we go ...
 
        msg = CtdlFetchMessage(msgnum, 1);
-       if (msg == NULL) return;        /* fail silently */
+       if (msg == NULL) return;                                // fail silently
 
        client_write(HKEY("<message>\n"));
        GetMetaData(&smi, msgnum);
@@ -329,7 +345,7 @@ void migr_export_message(long msgnum) {
        CtdlSerializeMessage(&smr, msg);
        CM_Free(msg);
 
-       /* Predict the buffer size we need.  Expand the buffer if necessary. */
+       // Predict the buffer size we need.  Expand the buffer if necessary.
        int encoded_len = smr.len * 15 / 10 ;
        if (encoded_len > encoded_alloc) {
                encoded_alloc = encoded_len;
@@ -337,13 +353,24 @@ void migr_export_message(long msgnum) {
        }
 
        if (encoded_msg == NULL) {
-               /* Questionable hack that hopes it'll work next time and we only lose one message */
+               // Questionable hack that hopes it'll work next time and we only lose one message
                encoded_alloc = 0;
        }
        else {
-               /* Once we do the encoding we know the exact size */
+               // Once we do the encoding we know the exact size
                encoded_len = CtdlEncodeBase64(encoded_msg, (char *)smr.ser, smr.len, 1);
-               client_write(encoded_msg, encoded_len);
+
+               // Careful now.  If the message is gargantuan, trying to write multiple gigamegs in one
+               // big write operation can make our transport unhappy.  So we'll chunk it up 10 KB at a time.
+               bytes_written = 0;
+               while ( (bytes_written < encoded_len) && (!server_shutting_down) ) {
+                       this_block = encoded_len - bytes_written;
+                       if (this_block > 10240) {
+                               this_block = 10240;
+                       }
+                       client_write(&encoded_msg[bytes_written], this_block);
+                       bytes_written += this_block;
+               }
        }
 
        free(smr.ser);
@@ -409,7 +436,7 @@ void migr_export_messages(void) {
        Ctx = CC;
        migr_global_message_list = fopen(migr_tempfilename1, "r");
        if (migr_global_message_list != NULL) {
-               syslog(LOG_INFO, "Opened %s", migr_tempfilename1);
+               syslog(LOG_INFO, "migrate: opened %s", migr_tempfilename1);
                while ((Ctx->kill_me == 0) && 
                       (fgets(buf, sizeof(buf), migr_global_message_list) != NULL)) {
                        msgnum = atol(buf);
@@ -426,10 +453,10 @@ void migr_export_messages(void) {
                fclose(migr_global_message_list);
        }
        if (Ctx->kill_me == 0) {
-               syslog(LOG_INFO, "Exported %d messages.", count);
+               syslog(LOG_INFO, "migrate: exported %d messages.", count);
        }
        else {
-               syslog(LOG_ERR, "Export aborted due to client disconnect!");
+               syslog(LOG_ERR, "migrate: export aborted due to client disconnect!");
        }
 
        migr_export_message(-1L);       /* This frees the encoding buffer */
@@ -496,8 +523,7 @@ long import_msgnum = 0;
 /*
  * This callback stores up the data which appears in between tags.
  */
-void migr_xml_chardata(void *data, const XML_Char *s, int len)
-{
+void migr_xml_chardata(void *data, const XML_Char *s, int len) {
        StrBufAppendBufPlain(migr_chardata, s, len, 0);
 }
 
@@ -526,7 +552,7 @@ void migr_xml_start(void *data, const char *el, const char **attr) {
        }
 
        if (citadel_migrate_data != 1) {
-               syslog(LOG_ALERT, "Out-of-sequence tag <%s> detected.  Warning: ODD-DATA!", el);
+               syslog(LOG_ERR, "migrate: out-of-sequence tag <%s> detected.  Warning: ODD-DATA!", el);
                return;
        }
 
@@ -560,8 +586,7 @@ void migr_xml_start(void *data, const char *el, const char **attr) {
 }
 
 
-int migr_userrecord(void *data, const char *el)
-{
+int migr_userrecord(void *data, const char *el) {
        if (!strcasecmp(el, "u_version"))                       usbuf.version = atoi(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "u_uid"))                      usbuf.uid = atol(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "u_password"))                 safestrncpy(usbuf.password, ChrPtr(migr_chardata), sizeof usbuf.password);
@@ -583,8 +608,7 @@ int migr_userrecord(void *data, const char *el)
 }
 
 
-int migr_roomrecord(void *data, const char *el)
-{
+int migr_roomrecord(void *data, const char *el) {
        if (!strcasecmp(el, "QRname"))                          safestrncpy(qrbuf.QRname, ChrPtr(migr_chardata), sizeof qrbuf.QRname);
        else if (!strcasecmp(el, "QRpasswd"))                   safestrncpy(qrbuf.QRpasswd, ChrPtr(migr_chardata), sizeof qrbuf.QRpasswd);
        else if (!strcasecmp(el, "QRroomaide"))                 qrbuf.QRroomaide = atol(ChrPtr(migr_chardata));
@@ -607,8 +631,7 @@ int migr_roomrecord(void *data, const char *el)
 }
 
 
-int migr_floorrecord(void *data, const char *el)
-{
+int migr_floorrecord(void *data, const char *el) {
        if (!strcasecmp(el, "f_num"))                           floornum = atoi(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "f_flags"))                    flbuf.f_flags = atoi(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "f_name"))                     safestrncpy(flbuf.f_name, ChrPtr(migr_chardata), sizeof flbuf.f_name);
@@ -620,8 +643,7 @@ int migr_floorrecord(void *data, const char *el)
 }
 
 
-int migr_visitrecord(void *data, const char *el)
-{
+int migr_visitrecord(void *data, const char *el) {
        if (!strcasecmp(el, "v_roomnum"))                       vbuf.v_roomnum = atol(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "v_roomgen"))                  vbuf.v_roomgen = atol(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "v_usernum"))                  vbuf.v_usernum = atol(ChrPtr(migr_chardata));
@@ -648,8 +670,7 @@ int migr_visitrecord(void *data, const char *el)
 }
 
 
-void migr_xml_end(void *data, const char *el)
-{
+void migr_xml_end(void *data, const char *el) {
        const char *ptr;
        int msgcount = 0;
        long msgnum = 0L;
@@ -663,7 +684,7 @@ void migr_xml_end(void *data, const char *el)
        }
 
        if (citadel_migrate_data != 1) {
-               syslog(LOG_ALERT, "Out-of-sequence tag <%s> detected.  Warning: ODD-DATA!", el);
+               syslog(LOG_ERR, "migrate: out-of-sequence tag <%s> detected.  Warning: ODD-DATA!", el);
                return;
        }
 
@@ -671,9 +692,8 @@ void migr_xml_end(void *data, const char *el)
 
        /*** CONFIG ***/
 
-       if (!strcasecmp(el, "config"))
-       {
-               syslog(LOG_DEBUG, "Imported config key=%s", ikey);
+       if (!strcasecmp(el, "config")) {
+               syslog(LOG_DEBUG, "migrate: imported config key=%s", ikey);
 
                if (ikey != NULL) {
                        CtdlSetConfigStr(ikey, (char *)ChrPtr(migr_chardata));
@@ -681,7 +701,7 @@ void migr_xml_end(void *data, const char *el)
                        ikey = NULL;
                }
                else {
-                       syslog(LOG_INFO, "Closed a <config> tag but no key name was supplied.");
+                       syslog(LOG_INFO, "migrate: closed a <config> tag but no key name was supplied.");
                }
        }
 
@@ -691,7 +711,7 @@ void migr_xml_end(void *data, const char *el)
                ; /* Nothing to do anymore */
        else if (!strcasecmp(el, "user")) {
                CtdlPutUser(&usbuf);
-               syslog(LOG_INFO, "Imported user: %s", usbuf.fullname);
+               syslog(LOG_INFO, "migrate: imported user: %s", usbuf.fullname);
        }
 
        /*** OPENID ***/
@@ -708,7 +728,7 @@ void migr_xml_end(void *data, const char *el)
                memcpy(&oid_data[sizeof(long)], openid_url, strlen(openid_url) + 1);
                cdb_store(CDB_EXTAUTH, openid_url, strlen(openid_url), oid_data, oid_data_len);
                free(oid_data);
-               syslog(LOG_INFO, "Imported OpenID: %s (%ld)", openid_url, openid_usernum);
+               syslog(LOG_INFO, "migrate: imported OpenID: %s (%ld)", openid_url, openid_usernum);
        }
 
        /*** ROOM ***/
@@ -717,12 +737,14 @@ void migr_xml_end(void *data, const char *el)
                ; /* Nothing to do anymore */
        else if (!strcasecmp(el, "room")) {
                CtdlPutRoom(&qrbuf);
-               syslog(LOG_INFO, "Imported room: %s", qrbuf.QRname);
+               syslog(LOG_INFO, "migrate: imported room: %s", qrbuf.QRname);
        }
 
        /*** ROOM MESSAGE POINTERS ***/
 
-       else if (!strcasecmp(el, "FRname"))                     safestrncpy(FRname, ChrPtr(migr_chardata), sizeof FRname);
+       else if (!strcasecmp(el, "FRname")) {
+               safestrncpy(FRname, ChrPtr(migr_chardata), sizeof FRname);
+       }
 
        else if (!strcasecmp(el, "FRmsglist")) {
                if (!IsEmptyStr(FRname)) {
@@ -730,7 +752,7 @@ void migr_xml_end(void *data, const char *el)
                        msglist_alloc = 1000;
                        msglist = malloc(sizeof(long) * msglist_alloc);
 
-                       syslog(LOG_DEBUG, "Message list for: %s", FRname);
+                       syslog(LOG_DEBUG, "migrate: message list for: %s", FRname);
 
                        ptr = ChrPtr(migr_chardata);
                        while (*ptr != 0) {
@@ -758,7 +780,7 @@ void migr_xml_end(void *data, const char *el)
                        free(msglist);
                        msglist = NULL;
                        msglist_alloc = 0;
-                       syslog(LOG_DEBUG, "Imported %d messages.", msgcount);
+                       syslog(LOG_DEBUG, "migrate: imported %d messages.", msgcount);
                        if (server_shutting_down) {
                                return;
                }
@@ -771,7 +793,7 @@ void migr_xml_end(void *data, const char *el)
 
        else if (!strcasecmp(el, "floor")) {
                CtdlPutFloor(&flbuf, floornum);
-               syslog(LOG_INFO, "Imported floor #%d (%s)", floornum, flbuf.f_name);
+               syslog(LOG_INFO, "migrate: imported floor #%d (%s)", floornum, flbuf.f_name);
        }
 
        /*** VISITS ***/
@@ -780,7 +802,7 @@ void migr_xml_end(void *data, const char *el)
        }
        else if (!strcasecmp(el, "visit")) {
                put_visit(&vbuf);
-               syslog(LOG_INFO, "Imported visit: %ld/%ld/%ld", vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
+               syslog(LOG_INFO, "migrate: imported visit: %ld/%ld/%ld", vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
        }
 
        /*** MESSAGES ***/
@@ -790,8 +812,7 @@ void migr_xml_end(void *data, const char *el)
        else if (!strcasecmp(el, "msg_meta_rfc822_length"))     smi.meta_rfc822_length = atoi(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "msg_meta_content_type"))      safestrncpy(smi.meta_content_type, ChrPtr(migr_chardata), sizeof smi.meta_content_type);
 
-       else if (!strcasecmp(el, "msg_text"))
-       {
+       else if (!strcasecmp(el, "msg_text")) {
                long rc;
                struct CtdlMessage *msg;
 
@@ -813,7 +834,7 @@ void migr_xml_end(void *data, const char *el)
                }
 
                syslog(LOG_INFO,
-                      "%s message #%ld, size=%d, refcount=%d, bodylength=%ld, content-type: %s",
+                      "migrate: %s message #%ld, size=%d, refcount=%d, bodylength=%ld, content-type: %s",
                       (rc!= 0)?"failed to import ":"Imported ",
                       import_msgnum,
                       StrLength(migr_MsgData),
@@ -894,8 +915,7 @@ void migr_do_listdirs(void) {
 StrBuf *PlainMessageBuf = NULL;
 HashList *UsedMessageIDS = NULL;
 
-int migr_restore_message_metadata(long msgnum, int refcount)
-{
+int migr_restore_message_metadata(long msgnum, int refcount) {
        struct MetaData smi;
        struct CtdlMessage *msg;
        char *mptr = NULL;
@@ -957,7 +977,7 @@ int migr_restore_message_metadata(long msgnum, int refcount)
        CC->redirect_buffer = NULL;
 
        syslog(LOG_INFO,
-              "Setting message #%ld meta data to: refcount=%d, bodylength=%ld, content-type: %s",
+              "migrate: setting message #%ld meta data to: refcount=%d, bodylength=%ld, content-type: %s",
               smi.meta_msgnum,
               smi.meta_refcount,
               smi.meta_rfc822_length,
@@ -965,9 +985,7 @@ int migr_restore_message_metadata(long msgnum, int refcount)
        );
 
        PutMetaData(&smi);
-
        CM_Free(msg);
-
        return 0;
 }
 
@@ -978,9 +996,7 @@ void migr_check_room_msg(long msgnum, void *userdata) {
 
 
 void migr_check_rooms_backend(struct ctdlroom *buf, void *data) {
-
        /* message list goes inside this tag */
-
        CtdlGetRoom(&CC->room, buf->QRname);
        CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_check_room_msg, NULL);
 }
@@ -991,7 +1007,7 @@ void RemoveMessagesFromRooms(StrBuf *RoomNameVec, long msgnum) {
        const char *Pos = NULL;
        StrBuf *oneRoom = NewStrBuf();
 
-       syslog(LOG_INFO, "removing message pointer %ld from these rooms: %s", msgnum, ChrPtr(RoomNameVec));
+       syslog(LOG_INFO, "migrate: removing message pointer %ld from these rooms: %s", msgnum, ChrPtr(RoomNameVec));
 
        while (Pos != StrBufNOTNULL){
                StrBufExtract_NextToken(oneRoom, RoomNameVec, &Pos, '|');
@@ -1026,13 +1042,15 @@ void migr_do_restore_meta(void) {
         * exporting the message multiple times.)
         */
        snprintf(cmd, sizeof cmd, "sort -n <%s >%s", migr_tempfilename1, migr_tempfilename2);
-       if (system(cmd) != 0) syslog(LOG_ALERT, "Error %d", errno);
+       if (system(cmd) != 0) {
+               syslog(LOG_ERR, "migrate: error %d", errno);
+       }
 
        RoomNames = NewStrBuf();
        Ctx = CC;
        migr_global_message_list = fopen(migr_tempfilename2, "r");
        if (migr_global_message_list != NULL) {
-               syslog(LOG_INFO, "Opened %s", migr_tempfilename1);
+               syslog(LOG_INFO, "migrate: opened %s", migr_tempfilename1);
                while ((Ctx->kill_me == 0) && 
                       (fgets(buf, sizeof(buf), migr_global_message_list) != NULL)) {
                        msgnum = atol(buf);