From 48aa917403de1599a02924e429a9f43ea31e9cc1 Mon Sep 17 00:00:00 2001
From: Robert Morris <rtm@csail.mit.edu>
Date: Thu, 28 Aug 2014 05:57:47 -0400
Subject: [PATCH] i think this is a working concurrent logging scheme

---
 bio.c       |   2 +
 log.c       |  21 +++++-
 mkfs.c      |   2 +-
 param.h     |   5 +-
 usertests.c | 186 ++++++++++++++++++++++++++--------------------------
 5 files changed, 117 insertions(+), 99 deletions(-)

diff --git a/bio.c b/bio.c
index de1d0f2..d2ebc4b 100644
--- a/bio.c
+++ b/bio.c
@@ -80,6 +80,8 @@ bget(uint dev, uint sector)
   }
 
   // Not cached; recycle some non-busy and clean buffer.
+  // "clean" because B_DIRTY and !B_BUSY means log.c
+  // hasn't yet committed the changes to the buffer.
   for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
     if((b->flags & B_BUSY) == 0 && (b->flags & B_DIRTY) == 0){
       b->dev = dev;
diff --git a/log.c b/log.c
index 159df98..9d42ea8 100644
--- a/log.c
+++ b/log.c
@@ -52,6 +52,10 @@ struct log log;
 static void recover_from_log(void);
 static void commit();
 
+// statistics, delete eventually XXX.
+static int maxsize;
+static int maxoutstanding;
+
 void
 initlog(void)
 {
@@ -131,10 +135,15 @@ begin_op(void)
   while(1){
     if(log.committing){
       sleep(&log, &log.lock);
+    } else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
+      // this op might exhaust log space; wait for commit.
+      sleep(&log, &log.lock);
     } else {
-      // XXX wait (for a commit) if log is longish.
-      //     need to reserve to avoid over-commit of log space.
       log.outstanding += 1;
+      if(log.outstanding > maxoutstanding){
+        maxoutstanding = log.outstanding;
+        cprintf("%d outstanding\n", log.outstanding);
+      }
       release(&log.lock);
       break;
     }
@@ -155,6 +164,9 @@ end_op(void)
   if(log.outstanding == 0){
     do_commit = 1;
     log.committing = 1;
+  } else {
+    // begin_op() may be waiting for log space.
+    wakeup(&log);
   }
   release(&log.lock);
 
@@ -208,6 +220,11 @@ log_write(struct buf *b)
   if (i == log.lh.n)
     log.lh.n++;
   b->flags |= B_DIRTY; // XXX prevent eviction
+
+  if(log.lh.n > maxsize){
+    maxsize = log.lh.n;
+    cprintf("log size %d/%d\n", log.lh.n, LOGSIZE);
+  }
 }
 
 //PAGEBREAK!
diff --git a/mkfs.c b/mkfs.c
index 4b0e329..c168377 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -13,7 +13,7 @@
 
 #define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
 
-int nblocks = 985;
+int nblocks = (995-LOGSIZE);
 int nlog = LOGSIZE;
 int ninodes = 200;
 int size = 1024;
diff --git a/param.h b/param.h
index b6f6f46..bdac60c 100644
--- a/param.h
+++ b/param.h
@@ -3,10 +3,11 @@
 #define NCPU          8  // maximum number of CPUs
 #define NOFILE       16  // open files per process
 #define NFILE       100  // open files per system
-#define NBUF         10  // size of disk block cache
 #define NINODE       50  // maximum number of active i-nodes
 #define NDEV         10  // maximum major device number
 #define ROOTDEV       1  // device number of file system root disk
 #define MAXARG       32  // max exec arguments
-#define LOGSIZE      10  // max data sectors in on-disk log
+#define MAXOPBLOCKS  10  // max # of blocks any FS op writes
+#define LOGSIZE      (MAXOPBLOCKS*3)  // max data sectors in on-disk log
+#define NBUF         (MAXOPBLOCKS*3)  // size of disk block cache (>= LOGSIZE)
 
diff --git a/usertests.c b/usertests.c
index 5a78c7c..22a7bfb 100644
--- a/usertests.c
+++ b/usertests.c
@@ -512,51 +512,56 @@ sharedfd(void)
   }
 }
 
-// two processes write two different files at the same
+// four processes write different files at the same
 // time, to test block allocation.
 void
-twofiles(void)
+fourfiles(void)
 {
-  int fd, pid, i, j, n, total;
+  int fd, pid, i, j, n, total, pi;
+  char *names[] = { "f0", "f1", "f2", "f3" };
   char *fname;
 
-  printf(1, "twofiles test\n");
+  printf(1, "fourfiles test\n");
 
-  unlink("f1");
-  unlink("f2");
+  for(pi = 0; pi < 4; pi++){
+    fname = names[pi];
+    unlink(fname);
 
-  pid = fork();
-  if(pid < 0){
-    printf(1, "fork failed\n");
-    exit();
-  }
+    pid = fork();
+    if(pid < 0){
+      printf(1, "fork failed\n");
+      exit();
+    }
 
-  fname = pid ? "f1" : "f2";
-  fd = open(fname, O_CREATE | O_RDWR);
-  if(fd < 0){
-    printf(1, "create failed\n");
-    exit();
-  }
-
-  memset(buf, pid?'p':'c', 512);
-  for(i = 0; i < 12; i++){
-    if((n = write(fd, buf, 500)) != 500){
-      printf(1, "write failed %d\n", n);
+    if(pid == 0){
+      fd = open(fname, O_CREATE | O_RDWR);
+      if(fd < 0){
+        printf(1, "create failed\n");
+        exit();
+      }
+      
+      memset(buf, '0'+pi, 512);
+      for(i = 0; i < 12; i++){
+        if((n = write(fd, buf, 500)) != 500){
+          printf(1, "write failed %d\n", n);
+          exit();
+        }
+      }
       exit();
     }
   }
-  close(fd);
-  if(pid)
+
+  for(pi = 0; pi < 4; pi++){
     wait();
-  else
-    exit();
+  }
 
   for(i = 0; i < 2; i++){
-    fd = open(i?"f1":"f2", 0);
+    fname = names[i];
+    fd = open(fname, 0);
     total = 0;
     while((n = read(fd, buf, sizeof(buf))) > 0){
       for(j = 0; j < n; j++){
-        if(buf[j] != (i?'p':'c')){
+        if(buf[j] != '0'+i){
           printf(1, "wrong char\n");
           exit();
         }
@@ -568,87 +573,80 @@ twofiles(void)
       printf(1, "wrong length %d\n", total);
       exit();
     }
+    unlink(fname);
   }
 
-  unlink("f1");
-  unlink("f2");
-
-  printf(1, "twofiles ok\n");
+  printf(1, "fourfiles ok\n");
 }
 
-// two processes create and delete different files in same directory
+// four processes create and delete different files in same directory
 void
 createdelete(void)
 {
   enum { N = 20 };
-  int pid, i, fd;
+  int pid, i, fd, pi;
   char name[32];
 
   printf(1, "createdelete test\n");
-  pid = fork();
-  if(pid < 0){
-    printf(1, "fork failed\n");
-    exit();
-  }
 
-  name[0] = pid ? 'p' : 'c';
-  name[2] = '\0';
-  for(i = 0; i < N; i++){
-    name[1] = '0' + i;
-    fd = open(name, O_CREATE | O_RDWR);
-    if(fd < 0){
-      printf(1, "create failed\n");
+  for(pi = 0; pi < 4; pi++){
+    pid = fork();
+    if(pid < 0){
+      printf(1, "fork failed\n");
       exit();
     }
-    close(fd);
-    if(i > 0 && (i % 2 ) == 0){
-      name[1] = '0' + (i / 2);
-      if(unlink(name) < 0){
-        printf(1, "unlink failed\n");
+
+    if(pid == 0){
+      name[0] = 'p' + pi;
+      name[2] = '\0';
+      for(i = 0; i < N; i++){
+        name[1] = '0' + i;
+        fd = open(name, O_CREATE | O_RDWR);
+        if(fd < 0){
+          printf(1, "create failed\n");
+          exit();
+        }
+        close(fd);
+        if(i > 0 && (i % 2 ) == 0){
+          name[1] = '0' + (i / 2);
+          if(unlink(name) < 0){
+            printf(1, "unlink failed\n");
+            exit();
+          }
+        }
+      }
+      exit();
+    }
+  }
+
+  for(pi = 0; pi < 4; pi++){
+    wait();
+  }
+
+  name[0] = name[1] = name[2] = 0;
+  for(i = 0; i < N; i++){
+    for(pi = 0; pi < 4; pi++){
+      name[0] = 'p' + pi;
+      name[1] = '0' + i;
+      fd = open(name, 0);
+      if((i == 0 || i >= N/2) && fd < 0){
+        printf(1, "oops createdelete %s didn't exist\n", name);
+        exit();
+      } else if((i >= 1 && i < N/2) && fd >= 0){
+        printf(1, "oops createdelete %s did exist\n", name);
         exit();
       }
+      if(fd >= 0)
+        close(fd);
     }
   }
 
-  if(pid==0)
-    exit();
-  else
-    wait();
-
   for(i = 0; i < N; i++){
-    name[0] = 'p';
-    name[1] = '0' + i;
-    fd = open(name, 0);
-    if((i == 0 || i >= N/2) && fd < 0){
-      printf(1, "oops createdelete %s didn't exist\n", name);
-      exit();
-    } else if((i >= 1 && i < N/2) && fd >= 0){
-      printf(1, "oops createdelete %s did exist\n", name);
-      exit();
+    for(pi = 0; pi < 4; pi++){
+      name[0] = 'p' + i;
+      name[1] = '0' + i;
+      unlink(name);
     }
-    if(fd >= 0)
-      close(fd);
-
-    name[0] = 'c';
-    name[1] = '0' + i;
-    fd = open(name, 0);
-    if((i == 0 || i >= N/2) && fd < 0){
-      printf(1, "oops createdelete %s didn't exist\n", name);
-      exit();
-    } else if((i >= 1 && i < N/2) && fd >= 0){
-      printf(1, "oops createdelete %s did exist\n", name);
-      exit();
-    }
-    if(fd >= 0)
-      close(fd);
-  }
-
-  for(i = 0; i < N; i++){
-    name[0] = 'p';
-    name[1] = '0' + i;
-    unlink(name);
-    name[0] = 'c';
-    unlink(name);
   }
 
   printf(1, "createdelete ok\n");
@@ -1716,6 +1714,12 @@ main(int argc, char *argv[])
   }
   close(open("usertests.ran", O_CREATE));
 
+  createdelete();
+  linkunlink();
+  concreate();
+  fourfiles();
+  sharedfd();
+
   bigargtest();
   bigwrite();
   bigargtest();
@@ -1741,18 +1745,12 @@ main(int argc, char *argv[])
   fourteen();
   bigfile();
   subdir();
-  concreate();
-  linkunlink();
   linktest();
   unlinkread();
-  createdelete();
-  twofiles();
-  sharedfd();
   dirfile();
   iref();
   forktest();
   bigdir(); // slow
-
   exectest();
 
   exit();