Work on bug #550: Avoid exit. In particular the mfile/cfile/bfile has
[idzebra-moved-to-github.git] / index / recindex.c
index 3991171..3280dfc 100644 (file)
@@ -1,5 +1,5 @@
-/* $Id: recindex.c,v 1.46 2005-08-22 08:18:43 adam Exp $
-   Copyright (C) 1995-2005
+/* $Id: recindex.c,v 1.53 2006-11-14 08:12:08 adam Exp $
+   Copyright (C) 1995-2006
    Index Data ApS
 
 This file is part of the Zebra server.
@@ -15,9 +15,9 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with Zebra; see the file LICENSE.zebra.  If not, write to the
-Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
 */
 
 #define RIDX_CHUNK 128
@@ -73,7 +73,7 @@ SYSNO rec_sysno_to_int(SYSNO sysno)
     return sysno - FAKE_OFFSET;
 }
 
-static void rec_write_head(Records p)
+static ZEBRA_RES rec_write_head(Records p)
 {
     int r;
 
@@ -84,8 +84,9 @@ static void rec_write_head(Records p)
     if (r)
     {
         yaz_log(YLOG_FATAL|YLOG_ERRNO, "write head of %s", p->index_fname);
-        exit(1);
+       return ZEBRA_FAIL;
     }
+    return ZEBRA_OK;
 }
 
 static void rec_tmp_expand(Records p, int size)
@@ -105,7 +106,7 @@ static int read_indx(Records p, SYSNO sysno, void *buf, int itemsize,
 {
     int r;
     zint pos = (sysno-1)*itemsize;
-    int off = (int) (pos%RIDX_CHUNK);
+    int off = CAST_ZINT_TO_INT(pos%RIDX_CHUNK);
     int sz1 = RIDX_CHUNK - off;    /* sz1 is size of buffer to read.. */
 
     if (sz1 > itemsize)
@@ -118,8 +119,7 @@ static int read_indx(Records p, SYSNO sysno, void *buf, int itemsize,
     if (r != 1 && !ignoreError)
     {
         yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in %s at pos %ld",
-              p->index_fname, (long) pos);
-        exit(1);
+               p->index_fname, (long) pos);
     }
     return r;
 }
@@ -127,7 +127,7 @@ static int read_indx(Records p, SYSNO sysno, void *buf, int itemsize,
 static void write_indx(Records p, SYSNO sysno, void *buf, int itemsize)
 {
     zint pos = (sysno-1)*itemsize;
-    int off = (int) (pos%RIDX_CHUNK);
+    int off = CAST_ZINT_TO_INT(pos%RIDX_CHUNK);
     int sz1 = RIDX_CHUNK - off;    /* sz1 is size of buffer to read.. */
 
     if (sz1 > itemsize)
@@ -139,7 +139,7 @@ static void write_indx(Records p, SYSNO sysno, void *buf, int itemsize)
                (char*) buf + sz1);
 }
 
-static void rec_release_blocks(Records p, SYSNO sysno)
+static ZEBRA_RES rec_release_blocks(Records p, SYSNO sysno)
 {
     struct record_index_entry entry;
     zint freeblock;
@@ -148,11 +148,11 @@ static void rec_release_blocks(Records p, SYSNO sysno)
     int first = 1;
 
     if (read_indx(p, sysno, &entry, sizeof(entry), 1) != 1)
-        return ;
+        return ZEBRA_FAIL;
 
     freeblock = entry.next;
     assert(freeblock > 0);
-    dst_type = (int) (freeblock & 7);
+    dst_type = CAST_ZINT_TO_INT(freeblock & 7);
     assert(dst_type < REC_BLOCK_TYPES);
     freeblock = freeblock / 8;
     while (freeblock)
@@ -162,7 +162,7 @@ static void rec_release_blocks(Records p, SYSNO sysno)
                     block_and_ref) != 1)
         {
             yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in rec_del_single");
-            exit(1);
+           return ZEBRA_FAIL;
         }
        if (first)
        {
@@ -176,9 +176,9 @@ static void rec_release_blocks(Records p, SYSNO sysno)
                              sizeof(block_and_ref), block_and_ref))
                {
                    yaz_log(YLOG_FATAL|YLOG_ERRNO, "write in rec_del_single");
-                   exit(1);
+                   return ZEBRA_FAIL;
                }
-               return;
+               return ZEBRA_OK;
            }
            first = 0;
        }
@@ -187,7 +187,7 @@ static void rec_release_blocks(Records p, SYSNO sysno)
                       &p->head.block_free[dst_type]))
         {
             yaz_log(YLOG_FATAL|YLOG_ERRNO, "write in rec_del_single");
-            exit(1);
+           return ZEBRA_FAIL;
         }
         p->head.block_free[dst_type] = freeblock;
         memcpy(&freeblock, block_and_ref, sizeof(freeblock));
@@ -195,21 +195,24 @@ static void rec_release_blocks(Records p, SYSNO sysno)
         p->head.block_used[dst_type]--;
     }
     p->head.total_bytes -= entry.size;
+    return ZEBRA_OK;
 }
 
-static void rec_delete_single(Records p, Record rec)
+static ZEBRA_RES rec_delete_single(Records p, Record rec)
 {
     struct record_index_entry entry;
 
-    rec_release_blocks(p, rec_sysno_to_int(rec->sysno));
+    if (rec_release_blocks(p, rec_sysno_to_int(rec->sysno)) != ZEBRA_OK)
+       return ZEBRA_FAIL;
 
     entry.next = p->head.index_free;
     entry.size = 0;
     p->head.index_free = rec_sysno_to_int(rec->sysno);
     write_indx(p, rec_sysno_to_int(rec->sysno), &entry, sizeof(entry));
+    return ZEBRA_OK;
 }
 
-static void rec_write_tmp_buf(Records p, int size, SYSNO *sysnos)
+static ZEBRA_RES rec_write_tmp_buf(Records p, int size, SYSNO *sysnos)
 {
     struct record_index_entry entry;
     int no_written = 0;
@@ -233,7 +236,7 @@ static void rec_write_tmp_buf(Records p, int size, SYSNO *sysnos)
                 yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in %s at free block "
                         ZINT_FORMAT,
                         p->data_fname[dst_type], block_free);
-               exit(1);
+               return ZEBRA_FAIL;
             }
         }
         else
@@ -256,7 +259,8 @@ static void rec_write_tmp_buf(Records p, int size, SYSNO *sysnos)
             cptr = p->tmp_buf + no_written;
         }
         block_prev = block_free;
-        no_written += (int)(p->head.block_size[dst_type]) - sizeof(zint);
+        no_written += CAST_ZINT_TO_INT(p->head.block_size[dst_type]) 
+            - sizeof(zint);
         p->head.block_used[dst_type]++;
     }
     assert(block_prev != -1);
@@ -264,6 +268,7 @@ static void rec_write_tmp_buf(Records p, int size, SYSNO *sysnos)
     memcpy(cptr, &block_free, sizeof(block_free));
     bf_write(p->data_BFile[dst_type], block_prev, 0,
               sizeof(block_free) + (p->tmp_buf+size) - cptr, cptr);
+    return ZEBRA_OK;
 }
 
 Records rec_open(BFiles bfs, int rw, int compression_method)
@@ -271,19 +276,21 @@ Records rec_open(BFiles bfs, int rw, int compression_method)
     Records p;
     int i, r;
     int version;
+    ZEBRA_RES ret = ZEBRA_OK;
 
     p = (Records) xmalloc(sizeof(*p));
     p->compression_method = compression_method;
     p->rw = rw;
     p->tmp_size = 1024;
-    p->tmp_buf = (char *) xmalloc(p->tmp_size);
     p->index_fname = "reci";
     p->index_BFile = bf_open(bfs, p->index_fname, RIDX_CHUNK, rw);
     if (p->index_BFile == NULL)
     {
         yaz_log(YLOG_FATAL|YLOG_ERRNO, "open %s", p->index_fname);
-        exit(1);
+       xfree(p);
+       return 0;
     }
+    p->tmp_buf = (char *) xmalloc(p->tmp_size);
     r = bf_read(p->index_BFile, 0, 0, 0, p->tmp_buf);
     switch (r)
     {
@@ -308,21 +315,24 @@ Records rec_open(BFiles bfs, int rw, int compression_method)
             p->head.block_move[i] = p->head.block_size[i] * 24;
         }
         if (rw)
-            rec_write_head(p);
+       {
+            if (rec_write_head(p) != ZEBRA_OK)
+               ret = ZEBRA_FAIL;
+       }
         break;
     case 1:
         memcpy(&p->head, p->tmp_buf, sizeof(p->head));
         if (memcmp(p->head.magic, REC_HEAD_MAGIC, sizeof(p->head.magic)))
         {
             yaz_log(YLOG_FATAL, "file %s has bad format", p->index_fname);
-            exit(1);
+           ret = ZEBRA_FAIL;
         }
        version = atoi(p->head.version);
        if (version != REC_VERSION)
        {
            yaz_log(YLOG_FATAL, "file %s is version %d, but version"
                  " %d is required", p->index_fname, version, REC_VERSION);
-           exit(1);
+           ret = ZEBRA_FAIL;
        }
         break;
     }
@@ -336,12 +346,13 @@ Records rec_open(BFiles bfs, int rw, int compression_method)
     }
     for (i = 0; i<REC_BLOCK_TYPES; i++)
     {
-        if (!(p->data_BFile[i] = bf_open(bfs, p->data_fname[i],
-                                        (int) (p->head.block_size[i]),
-                                        rw)))
+        if (!(p->data_BFile[i] =
+              bf_open(bfs, p->data_fname[i],
+                      CAST_ZINT_TO_INT(p->head.block_size[i]), rw)))
         {
             yaz_log(YLOG_FATAL|YLOG_ERRNO, "bf_open %s", p->data_fname[i]);
-            exit(1);
+           ret = ZEBRA_FAIL;
+            break;
         }
     }
     p->cache_max = 400;
@@ -349,6 +360,8 @@ Records rec_open(BFiles bfs, int rw, int compression_method)
     p->record_cache = (struct record_cache_entry *)
        xmalloc(sizeof(*p->record_cache)*p->cache_max);
     zebra_mutex_init(&p->mutex);
+    if (ret == ZEBRA_FAIL)
+       rec_close(&p);
     return p;
 }
 
@@ -421,7 +434,7 @@ static void rec_cache_flush_block1(Records p, Record rec, Record last_rec,
 
     for (i = 0; i<REC_NO_INFO; i++)
     {
-       if (*out_offset + (int) rec->size[i] + 20 > *out_size)
+       if (*out_offset + CAST_ZINT_TO_INT(rec->size[i]) + 20 > *out_size)
        {
            int new_size = *out_offset + rec->size[i] + 65536;
            char *np = (char *) xmalloc(new_size);
@@ -462,7 +475,7 @@ static void rec_cache_flush_block1(Records p, Record rec, Record last_rec,
     }
 }
 
-static void rec_write_multiple(Records p, int saveCount)
+static ZEBRA_RES rec_write_multiple(Records p, int saveCount)
 {
     int i;
     short ref_count = 0;
@@ -473,6 +486,7 @@ static void rec_write_multiple(Records p, int saveCount)
     char *out_buf = (char *) xmalloc(out_size);
     SYSNO *sysnos = (SYSNO *) xmalloc(sizeof(*sysnos) * (p->cache_cur + 1));
     SYSNO *sysnop = sysnos;
+    ZEBRA_RES ret = ZEBRA_OK;
 
     for (i = 0; i<p->cache_cur - saveCount; i++)
     {
@@ -488,7 +502,10 @@ static void rec_write_multiple(Records p, int saveCount)
            last_rec = e->rec;
             break;
         case recordFlagWrite:
-           rec_release_blocks(p, rec_sysno_to_int(e->rec->sysno));
+           if (rec_release_blocks(p, rec_sysno_to_int(e->rec->sysno))
+               != ZEBRA_OK)
+               ret = ZEBRA_FAIL;
+
             rec_cache_flush_block1(p, e->rec, last_rec, &out_buf,
                                    &out_size, &out_offset);
            *sysnop++ = rec_sysno_to_int(e->rec->sysno);
@@ -497,7 +514,9 @@ static void rec_write_multiple(Records p, int saveCount)
            last_rec = e->rec;
             break;
         case recordFlagDelete:
-            rec_delete_single(p, e->rec);
+            if (rec_delete_single(p, e->rec) != ZEBRA_OK)
+               ret = ZEBRA_FAIL;
+
            e->flag = recordFlagNop;
             break;
        default:
@@ -551,31 +570,36 @@ static void rec_write_multiple(Records p, int saveCount)
                &compression_method, sizeof(compression_method));
                
        /* -------- compression */
-       rec_write_tmp_buf(p, csize + sizeof(short) + sizeof(char), sysnos);
+       if (rec_write_tmp_buf(p, csize + sizeof(short) + sizeof(char), sysnos)
+           != ZEBRA_OK)
+           ret = ZEBRA_FAIL;
     }
     xfree(out_buf);
     xfree(sysnos);
+    return ret;
 }
 
-static void rec_cache_flush(Records p, int saveCount)
+static ZEBRA_RES rec_cache_flush(Records p, int saveCount)
 {
     int i, j;
+    ZEBRA_RES ret;
 
     if (saveCount >= p->cache_cur)
         saveCount = 0;
 
-    rec_write_multiple(p, saveCount);
+    ret = rec_write_multiple(p, saveCount);
 
     for (i = 0; i<p->cache_cur - saveCount; i++)
     {
         struct record_cache_entry *e = p->record_cache + i;
-        rec_rm(&e->rec);
+        rec_free(&e->rec);
     } 
     /* i still being used ... */
     for (j = 0; j<saveCount; j++, i++)
         memcpy(p->record_cache+j, p->record_cache+i,
                 sizeof(*p->record_cache));
     p->cache_cur = saveCount;
+    return ret;
 }
 
 static Record *rec_cache_lookup(Records p, SYSNO sysno,
@@ -595,12 +619,13 @@ static Record *rec_cache_lookup(Records p, SYSNO sysno,
     return NULL;
 }
 
-static void rec_cache_insert(Records p, Record rec, enum recordCacheFlag flag)
+static ZEBRA_RES rec_cache_insert(Records p, Record rec, enum recordCacheFlag flag)
 {
     struct record_cache_entry *e;
+    ZEBRA_RES ret = ZEBRA_OK;
 
     if (p->cache_cur == p->cache_max)
-        rec_cache_flush(p, 1);
+        ret = rec_cache_flush(p, 1);
     else if (p->cache_cur > 0)
     {
         int i, j;
@@ -612,28 +637,36 @@ static void rec_cache_insert(Records p, Record rec, enum recordCacheFlag flag)
                 used += r->size[j];
         }
         if (used > 90000)
-            rec_cache_flush(p, 1);
+            ret = rec_cache_flush(p, 1);
     }
     assert(p->cache_cur < p->cache_max);
 
     e = p->record_cache + (p->cache_cur)++;
     e->flag = flag;
     e->rec = rec_cp(rec);
+    return ret;
 }
 
-void rec_close(Records *pp)
+ZEBRA_RES rec_close(Records *pp)
 {
     Records p = *pp;
     int i;
+    ZEBRA_RES ret = ZEBRA_OK;
 
-    assert(p);
+    if (!p)
+       return ret;
 
     zebra_mutex_destroy(&p->mutex);
-    rec_cache_flush(p, 0);
+    if (rec_cache_flush(p, 0) != ZEBRA_OK)
+       ret = ZEBRA_FAIL;
+
     xfree(p->record_cache);
 
     if (p->rw)
-        rec_write_head(p);
+    {
+        if (rec_write_head(p) != ZEBRA_OK)
+           ret = ZEBRA_FAIL;
+    }
 
     if (p->index_BFile)
         bf_close(p->index_BFile);
@@ -647,6 +680,7 @@ void rec_close(Records *pp)
     xfree(p->tmp_buf);
     xfree(p);
     *pp = NULL;
+    return ret;
 }
 
 static Record rec_get_int(Records p, SYSNO sysno)
@@ -735,7 +769,7 @@ static Record rec_get_int(Records p, SYSNO sysno)
        in_size = bz_size;
 #else
        yaz_log(YLOG_FATAL, "cannot decompress record(s) in BZIP2 format");
-       exit(1);
+       return 0;
 #endif
        break;
     case REC_COMPRESS_NONE:
@@ -789,7 +823,8 @@ static Record rec_get_int(Records p, SYSNO sysno)
        }
     }
     xfree(bz_buf);
-    rec_cache_insert(p, rec, recordFlagNop);
+    if (rec_cache_insert(p, rec, recordFlagNop) != ZEBRA_OK)
+       return 0;
     return rec;
 }
 
@@ -822,7 +857,11 @@ static Record rec_new_int(Records p)
     {
         struct record_index_entry entry;
 
-        read_indx(p, p->head.index_free, &entry, sizeof(entry), 0);
+        if (read_indx(p, p->head.index_free, &entry, sizeof(entry), 0) < 1)
+       {
+           xfree(rec);
+           return 0;
+       }
         sysno = p->head.index_free;
         p->head.index_free = entry.next;
     }
@@ -847,46 +886,50 @@ Record rec_new(Records p)
     return rec;
 }
 
-void rec_del(Records p, Record *recpp)
+ZEBRA_RES rec_del(Records p, Record *recpp)
 {
     Record *recp;
+    ZEBRA_RES ret = ZEBRA_OK;
 
     zebra_mutex_lock(&p->mutex);
     (p->head.no_records)--;
     if ((recp = rec_cache_lookup(p, (*recpp)->sysno, recordFlagDelete)))
     {
-        rec_rm(recp);
+        rec_free(recp);
         *recp = *recpp;
     }
     else
     {
-        rec_cache_insert(p, *recpp, recordFlagDelete);
-        rec_rm(recpp);
+        ret = rec_cache_insert(p, *recpp, recordFlagDelete);
+        rec_free(recpp);
     }
     zebra_mutex_unlock(&p->mutex);
     *recpp = NULL;
+    return ret;
 }
 
-void rec_put(Records p, Record *recpp)
+ZEBRA_RES rec_put(Records p, Record *recpp)
 {
     Record *recp;
+    ZEBRA_RES ret = ZEBRA_OK;
 
     zebra_mutex_lock(&p->mutex);
     if ((recp = rec_cache_lookup(p, (*recpp)->sysno, recordFlagWrite)))
     {
-        rec_rm(recp);
+        rec_free(recp);
         *recp = *recpp;
     }
     else
     {
-        rec_cache_insert(p, *recpp, recordFlagWrite);
-        rec_rm(recpp);
+        ret = rec_cache_insert(p, *recpp, recordFlagWrite);
+        rec_free(recpp);
     }
     zebra_mutex_unlock(&p->mutex);
     *recpp = NULL;
+    return ret;
 }
 
-void rec_rm(Record *recpp)
+void rec_free(Record *recpp)
 {
     int i;
 
@@ -914,8 +957,9 @@ Record rec_cp(Record rec)
         else
         {
             n->size[i] = rec->size[i];
-            n->info[i] = (char *) xmalloc(rec->size[i]);
+            n->info[i] = (char *) xmalloc(rec->size[i]+1);
             memcpy(n->info[i], rec->info[i], rec->size[i]);
+            n->info[i][rec->size[i]] = '\0';
         }
     return n;
 }
@@ -936,3 +980,11 @@ char *rec_strdup(const char *s, size_t *len)
     return p;
 }
 
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+