Browse code

implement redata_compact

Dario Rodriguez authored on 21/03/2019 22:55:07
Showing 1 changed files
... ...
@@ -43,6 +43,25 @@ static char sep_select(char *buf, int bufsize, char **pos);
43 43
 static void *mymemrchr(const void *s, int c, size_t n);
44 44
 static void meminvert(void *start, void *end);
45 45
 
46
+#if 0
47
+static void
48
+redata_debug_chunkdump(redata_t *redata, char *title)
49
+{
50
+        int m,k;
51
+        char c;
52
+        title=(title==NULL)?"":title;
53
+        fprintf(stderr,"%s:CHUNKDUMP (sizechunks:%i)\n",title,redata->sizechunks);
54
+        for(m=0;m<redata->sizechunks;m++) {
55
+                fprintf(stderr,"%s:chunk[%i]:\"",title,m);
56
+                for(k=0;k<redata->chunks[m]->useddata;k++) {
57
+                        c=redata->chunks[m]->data[k];
58
+                        c=(c>=' ' && c<='~')?c:'.';
59
+                        fprintf(stderr,"%c",c);
60
+                }
61
+                fprintf(stderr,"\"\n");
62
+        }
63
+}
64
+#endif
46 65
 
47 66
 redata_t *
48 67
 redata_init(void)
... ...
@@ -534,6 +553,8 @@ redata_unsaved_trunc(redata_t *redata)
534 553
                 return(-1); /* malformed filename */
535 554
         if(redata->unsavedfd!=-1)
536 555
                 close(redata->unsavedfd),redata->unsavedfd=-1;
556
+        redata_hash(redata,redata->initialhash);
557
+        redata->unsaved.usedbuf=0;
537 558
         if((redata->unsavedfd=open(unsname,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
538 559
                 return(-1); /* couldn't open file for writing */
539 560
         if((n=write(redata->unsavedfd,header,sizeof(header)-1))==-1
... ...
@@ -879,12 +900,13 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
879 900
         for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
880 901
                 redata_whatin_refresh(redata,chunkno);
881 902
         /* unsaved */
882
-        redata_hash(redata,redata->initialhash);
883 903
         if(use_unsaved) {
884 904
                 /* apply missing changes and append new changes to unsaved */
905
+                redata_hash(redata,redata->initialhash);
885 906
                 redata_unsaved_loadappend(redata);
886 907
         } else {
887 908
                 /* nuke existing unsaved (if exists) and prepare new unsaved */
909
+                /* _trunc() fills itself redata->initialhash */
888 910
                 redata_unsaved_trunc(redata);
889 911
         }
890 912
         /* all done */
... ...
@@ -918,8 +940,9 @@ redata_save(redata_t *redata, char *filename)
918 940
                 return(-1); /* couldn't overwrite old file */
919 941
         }
920 942
         redata_unsaved_unlink(redata);
921
-        redata_hash(redata,redata->initialhash);
922
-        redata->unsaved.usedbuf=0;
943
+        strncpy(redata->filename,filename,sizeof(redata->filename));
944
+        redata->filename[sizeof(redata->filename)-1]='\0';
945
+        redata_unsaved_trunc(redata);
923 946
         return(0);
924 947
 }
925 948
 
... ...
@@ -1461,6 +1484,8 @@ redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1461 1484
         return(0);
1462 1485
 }
1463 1486
 
1487
+
1488
+
1464 1489
 int
1465 1490
 redata_compact(redata_t *redata)
1466 1491
 {
... ...
@@ -1468,8 +1493,44 @@ redata_compact(redata_t *redata)
1468 1493
         /* criterion: */
1469 1494
         /* 1. if two neighbouring chunks could join with 10% free in result chunk, do it */
1470 1495
         /* 2. if there are more than 2 unused chunks free at the end, free all unused chunks except two */
1471
-#warning TODO
1472
-        return(-1);
1496
+        int i,l;
1497
+        rechunk_t *chunk,**newchunks;
1498
+        if(redata==NULL)
1499
+                return(-1); /* sanity check failed */
1500
+        /* skip free chunks at end */
1501
+        for(i=redata->sizechunks-1;i>=0;i--) {
1502
+                if(redata->chunks[i]->useddata!=0)
1503
+                        break;
1504
+        }
1505
+        /* join neighbouring chunks where appropiate */
1506
+        l=redata->chunkdatasize-(redata->chunkdatasize)/10;
1507
+        for(;i>0;i--) {
1508
+                if((redata->chunks[i]->useddata+redata->chunks[i-1]->useddata)>=l)
1509
+                        continue;
1510
+                /* move data to prev. chunk, move chunk to end */
1511
+                redata_chunk_fillfromnext(redata,i-1,redata->chunks[i]->useddata);
1512
+                if(redata->chunks[i]->useddata>0)
1513
+                        continue; /* couldn't move data */
1514
+                chunk=redata->chunks[i];
1515
+                memmove(redata->chunks+i,redata->chunks+i+1,sizeof(rechunk_t *)*(redata->sizechunks-i-1));
1516
+                redata->chunks[redata->sizechunks-1]=chunk;
1517
+        }
1518
+        /* free unused chunks at end (leave two empty chunks, free the rest) */
1519
+        for(i=redata->sizechunks-1;i>=0;i--) {
1520
+                if(redata->chunks[i]->useddata!=0)
1521
+                        break;
1522
+        }
1523
+        l=i+3;
1524
+        if(l<redata->sizechunks) {
1525
+                for(i=l;i<redata->sizechunks;i++) {
1526
+                        free(redata->chunks[i]),redata->chunks[i]=NULL;
1527
+                        redata->available-=redata->chunkdatasize;
1528
+                }
1529
+                if((newchunks=realloc(redata->chunks,l*sizeof(rechunk_t *)))!=NULL)
1530
+                        redata->chunks=newchunks;
1531
+                redata->sizechunks=l;
1532
+        }
1533
+        return(0);
1473 1534
 }
1474 1535
 
1475 1536
 int