Work on in-memory filesystem representation.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Fri, 21 Aug 2009 00:15:41 +0000 (17:15 -0700)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Fri, 21 Aug 2009 00:15:41 +0000 (17:15 -0700)
Makefile
bluesky.h [new file with mode: 0644]
dir.c [new file with mode: 0644]
inode.c
inode.h [deleted file]
main.c [new file with mode: 0644]

index 593f4d4..386cc23 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,17 @@
-PACKAGES=glib-2.0
+PACKAGES=glib-2.0 gthread-2.0
 DEBUG=-g
 CFLAGS=-O -Wall -D_FILE_OFFSET_BITS=64 $(DEBUG) \
        $(shell pkg-config --cflags $(PACKAGES))
 LDFLAGS=$(DEBUG) $(shell pkg-config --libs $(PACKAGES))
 
-SRCS=nfsd.c rpc.c mount.c mount_prot_xdr.c
+SRCS=dir.c inode.c main.c
 OBJS=$(SRCS:.c=.o)
 
-nfsproxy : $(OBJS)
+bluesky : $(OBJS)
        $(CC) $(LDFLAGS) -o $@ $^
 
 clean :
-       rm -f $(OBJS) nfsproxy
+       rm -f $(OBJS) bluesky
 
 dep :
        touch Makefile.dep
diff --git a/bluesky.h b/bluesky.h
new file mode 100644 (file)
index 0000000..068173f
--- /dev/null
+++ b/bluesky.h
@@ -0,0 +1,92 @@
+/* Blue Sky: File Systems in the Cloud
+ *
+ * Copyright (C) 2009  The Regents of the University of California
+ * Written by Michael Vrable <mvrable@cs.ucsd.edu>
+ *
+ * TODO: Licensing
+ */
+
+#ifndef _BLUESKY_H
+#define _BLUESKY_H
+
+#include <stdint.h>
+#include <glib.h>
+
+/* File types.  The numeric values are chosen to match with those used in
+ * NFSv3. */
+enum BlueSkyFileType {
+    BLUESKY_INVALID = 0,
+    BLUESKY_REGULAR = 1,
+    BLUESKY_DIRECTORY = 2,
+    BLUESKY_BLOCK = 3,
+    BLUESKY_CHARACTER = 4,
+    BLUESKY_SYMLINK = 5,
+    BLUESKY_SOCKET = 6,
+    BLUESKY_FIFO = 7,
+};
+
+/* Filesystem state.  Each filesystem which is exported is represented by a
+ * single bluesky_fs structure in memory. */
+typedef struct {
+    GMutex *lock;
+
+    gchar *name;                /* Descriptive name for the filesystem */
+    GHashTable *inodes;         /* Cached inodes */
+    uint64_t next_inum;         /* Next available inode for allocation */
+} BlueSkyFS;
+
+/* Timestamp, measured in microseconds since the Unix epoch. */
+typedef int64_t bluesky_time;
+
+/* In-memory representation of an inode within a Blue Sky server.  This
+ * corresponds roughly with information that is committed to persistent
+ * storage. */
+typedef struct {
+    gint refcnt;                /* May be accessed atomically without lock */
+    GMutex *lock;
+
+    int type;
+    uint32_t mode;
+    uint32_t uid, gid;
+    uint32_t nlink;
+
+    /* Rather than track an inode number and generation number, we will simply
+     * never re-use a fileid after a file is deleted.  64 bits should be enough
+     * that we don't exhaust the identifier space. */
+    uint64_t inum;
+
+    uint64_t change_count;      /* Incremented each with each change made */
+    int64_t atime;              /* Microseconds since the Unix epoch */
+    int64_t ctime;
+    int64_t mtime;
+    int64_t ntime;              /* "new time": time object was created */
+
+    /* File-specific fields */
+    uint64_t size;
+
+    /* Directory-specific fields */
+    GSequence *dirents;
+} BlueSkyInode;
+
+/* A directory entry.  The name is UTF-8 and is a freshly-allocated string.
+ * The name is hashed to a 64-bit value, and the directory entries are sorted
+ * by hash value (the hash value can then be used as a cookie for resuming a
+ * READDIR call). */
+typedef struct {
+    gchar *name;
+    uint64_t hash;
+    uint64_t inum;
+} BlueSkyDirent ;
+
+int64_t bluesky_get_current_time();
+uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs);
+BlueSkyInode *bluesky_new_inode(uint64_t inum);
+
+void bluesky_dirent_destroy(gpointer dirent);
+uint64_t bluesky_directory_hash(gchar *name);
+uint64_t bluesky_directory_lookup(BlueSkyInode *inode, gchar *name);
+gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name,
+                                  uint64_t inum);
+void bluesky_directory_dump(BlueSkyInode *dir);
+
+#endif
diff --git a/dir.c b/dir.c
new file mode 100644 (file)
index 0000000..c4cbec2
--- /dev/null
+++ b/dir.c
@@ -0,0 +1,122 @@
+/* Blue Sky: File Systems in the Cloud
+ *
+ * Copyright (C) 2009  The Regents of the University of California
+ * Written by Michael Vrable <mvrable@cs.ucsd.edu>
+ *
+ * TODO: Licensing
+ */
+
+#include <stdint.h>
+#include <glib.h>
+
+#include "bluesky.h"
+
+/* Core filesystem: handling of directories. */
+
+/* Hash a filename for a directory lookup.  The string is hashed to a 64-bit
+ * value.  It is guaranteed that the hash values 0, 1, and 2 are never returned
+ * (to allow the hash value to be used as an NFS cookie for a READDIR
+ * operation). */
+uint64_t bluesky_directory_hash(gchar *name)
+{
+    GChecksum *csum = g_checksum_new(G_CHECKSUM_MD5);
+    g_checksum_update(csum, (guchar *)name, -1);
+
+    guint64 hashbytes[2];
+    gsize hashsize = sizeof(hashbytes);
+    g_checksum_get_digest(csum, (guint8 *)hashbytes, &hashsize);
+
+    uint64_t hash = GUINT64_FROM_BE(hashbytes[0]);
+    if (hash < 3)
+        hash = 3;
+
+    g_checksum_free(csum);
+
+    return hash;
+}
+
+void bluesky_dirent_destroy(gpointer data)
+{
+    BlueSkyDirent *dirent = (BlueSkyDirent *)data;
+    g_free(dirent->name);
+    g_free(dirent);
+}
+
+static gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,
+                                   gpointer unused)
+{
+    /* We can't simply subtract the hash values, since they are 64-bit and the
+     * result could overflow when converted to a gint. */
+    uint64_t hash1 = ((const BlueSkyDirent *)a)->hash;
+    uint64_t hash2 = ((const BlueSkyDirent *)b)->hash;
+
+    if (hash1 < hash2)
+        return -1;
+    else if (hash1 > hash2)
+        return 1;
+    else
+        return 0;
+}
+
+/* Perform a lookup for a file name within a directory.  Returns the inode
+ * number if found, or 0 if not (0 is never a valid inode number).  Should be
+ * called with the inode lock already held. */
+uint64_t bluesky_directory_lookup(BlueSkyInode *inode, gchar *name)
+{
+    g_return_val_if_fail(inode->type == BLUESKY_DIRECTORY, 0);
+    g_return_val_if_fail(inode->dirents != NULL, 0);
+
+    /* First, construct a hash of the file name.  Search the directory for a
+     * match, then check to see if it does really match. */
+    uint64_t hash = bluesky_directory_hash(name);
+
+    BlueSkyDirent d = {name, hash, 0};
+    GSequenceIter *i = g_sequence_search(inode->dirents, &d,
+                                         bluesky_dirent_compare, NULL);
+    i = g_sequence_iter_prev(i);
+
+    if (g_sequence_iter_is_end(i))
+        return 0;
+    BlueSkyDirent *dirent = g_sequence_get(i);
+    g_print("Lookup(%s) -> 0x%016llx\n", name, dirent->hash);
+    if (dirent->hash != hash)
+        return 0;
+    if (g_strcmp0(name, dirent->name) != 0)
+        return 0;
+
+    return dirent->inum;
+}
+
+/* Insert a new entry into a directory.  Should be called with the inode lock
+ * already held. */
+gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum)
+{
+    /* First, construct a hash of the file name.  Search the directory for a
+     * match, then check to see if it does really match. */
+    uint64_t hash = bluesky_directory_hash(name);
+
+    BlueSkyDirent *d = g_new(BlueSkyDirent, 1);
+    d->name = name;
+    d->hash = hash;
+    d->inum = inum;
+
+    GSequenceIter *i = g_sequence_search(dir->dirents, d,
+                                         bluesky_dirent_compare, NULL);
+    g_sequence_insert_before(i, d);
+
+    return TRUE;
+}
+
+/* Dump the contents of a directory to stdout.  Debugging only. */
+void bluesky_directory_dump(BlueSkyInode *dir)
+{
+    g_print("Directory dump:\n");
+
+    GSequenceIter *i = g_sequence_get_begin_iter(dir->dirents);
+
+    while (!g_sequence_iter_is_end(i)) {
+        BlueSkyDirent *d = g_sequence_get(i);
+        g_print("    0x%016llx [inum=%lld] %s\n", d->hash, d->inum, d->name);
+        i = g_sequence_iter_next(i);
+    }
+}
diff --git a/inode.c b/inode.c
index 5f31326..ec90757 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -9,27 +9,13 @@
 #include <stdint.h>
 #include <glib.h>
 
-#include "inode.h"
+#include "bluesky.h"
 
 /* Core filesystem.  Different proxies, such as the NFSv3 one, interface to
  * this, but the core actually tracks the data which is stored.  So far we just
  * implement an in-memory filesystem, but eventually this will be state which
  * is persisted to the cloud. */
 
-
-/* Hash a filename for a directory lookup.  The string is hashed to a 64-bit
- * value. */
-uint64_t bluesky_directory_hash(gchar *name)
-{
-    GChecksum *csum = g_checksum_new(G_CHECKSUM_MD5);
-    g_checksum_update(csum, (guchar *)name, -1);
-
-    guint64 hashbytes[2];
-    gsize hashsize = sizeof(hashbytes);
-    g_checksum_get_digest(csum, (guint8 *)hashbytes, &hashsize);
-    return GUINT64_FROM_LE(hashbytes[0]);
-}
-
 /* Return the current time, in microseconds since the epoch. */
 int64_t bluesky_get_current_time()
 {
@@ -61,52 +47,3 @@ BlueSkyInode *bluesky_new_inode(uint64_t inum)
 
     return i;
 }
-
-void bluesky_dirent_destroy(BlueSkyDirent *dirent)
-{
-    g_free(dirent->name);
-    g_free(dirent);
-}
-
-gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,
-                            gpointer unused)
-{
-    /* We can't simply subtract the hash values, since they are 64-bit and the
-     * result could overflow when converted to a gint. */
-    uint64_t hash1 = ((const BlueSkyDirent *)a)->hash;
-    uint64_t hash2 = ((const BlueSkyDirent *)b)->hash;
-
-    if (hash1 < hash2)
-        return -1;
-    else if (hash1 > hash2)
-        return 1;
-    else
-        return 0;
-}
-
-/* Perform a lookup for a file name within a directory.  Returns the inode
- * number if found, or 0 if not (0 is never a valid inode number).  Should be
- * called with the inode lock already held. */
-uint64_t bluesky_directory_lookup(BlueSkyInode *inode, gchar *name)
-{
-    g_return_val_if_fail(inode->type != BLUESKY_DIRECTORY, 0);
-    g_return_val_if_fail(inode->dirents != NULL, 0);
-
-    /* First, construct a hash of the file name.  Search the directory for a
-     * match, then check to see if it does really match. */
-    uint64_t hash = bluesky_directory_hash(name);
-
-    BlueSkyDirent d = {name, hash, 0};
-    GSequenceIter *i = g_sequence_search(inode->dirents, &d,
-                                         bluesky_dirent_compare, NULL);
-
-    if (g_sequence_iter_is_end(i))
-        return 0;
-    BlueSkyDirent *dirent = g_sequence_get(i);
-    if (dirent->hash != hash)
-        return 0;
-    if (g_strcmp0(name, dirent->name) != 0)
-        return 0;
-
-    return dirent->inum;
-}
diff --git a/inode.h b/inode.h
deleted file mode 100644 (file)
index 23361c5..0000000
--- a/inode.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef _BLUESKY_INODE_H
-#define _BLUESKY_INODE_H
-
-#include <stdint.h>
-#include <glib.h>
-
-/* File types.  The numeric values are chosen to match with those used in
- * NFSv3. */
-enum BlueSkyFileType {
-    BLUESKY_INVALID = 0,
-    BLUESKY_REGULAR = 1,
-    BLUESKY_DIRECTORY = 2,
-    BLUESKY_BLOCK = 3,
-    BLUESKY_CHARACTER = 4,
-    BLUESKY_SYMLINK = 5,
-    BLUESKY_SOCKET = 6,
-    BLUESKY_FIFO = 7,
-};
-
-/* Filesystem state.  Each filesystem which is exported is represented by a
- * single bluesky_fs structure in memory. */
-typedef struct {
-    GMutex *lock;
-
-    gchar *name;                /* Descriptive name for the filesystem */
-    GHashTable *inodes;         /* Cached inodes */
-    uint64_t next_inum;         /* Next available inode for allocation */
-} BlueSkyFS;
-
-/* Timestamp, measured in microseconds since the Unix epoch. */
-typedef int64_t bluesky_time;
-
-/* In-memory representation of an inode within a Blue Sky server.  This
- * corresponds roughly with information that is committed to persistent
- * storage. */
-typedef struct {
-    gint refcnt;                /* May be accessed atomically without lock */
-    GMutex *lock;
-
-    int type;
-    uint32_t mode;
-    uint32_t uid, gid;
-    uint32_t nlink;
-
-    /* Rather than track an inode number and generation number, we will simply
-     * never re-use a fileid after a file is deleted.  64 bits should be enough
-     * that we don't exhaust the identifier space. */
-    uint64_t inum;
-
-    uint64_t change_count;      /* Incremented each with each change made */
-    int64_t atime;              /* Microseconds since the Unix epoch */
-    int64_t ctime;
-    int64_t mtime;
-    int64_t ntime;              /* "new time": time object was created */
-
-    /* File-specific fields */
-    uint64_t size;
-
-    /* Directory-specific fields */
-    GSequence *dirents;
-} BlueSkyInode;
-
-/* A directory entry.  The name is UTF-8 and is a freshly-allocated string.
- * The name is hashed to a 64-bit value, and the directory entries are sorted
- * by hash value (the hash value can then be used as a cookie for resuming a
- * READDIR call). */
-typedef struct {
-    gchar *name;
-    uint64_t hash;
-    uint64_t inum;
-} BlueSkyDirent ;
-
-uint64_t bluesky_directory_hash(gchar *name);
-
-#endif
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..6ddc7b4
--- /dev/null
+++ b/main.c
@@ -0,0 +1,39 @@
+/* Blue Sky: File Systems in the Cloud
+ *
+ * Copyright (C) 2009  The Regents of the University of California
+ * Written by Michael Vrable <mvrable@cs.ucsd.edu>
+ *
+ * TODO: Licensing
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <glib.h>
+
+#include "bluesky.h"
+
+/* Small test program for BlueSkyFS.  Doesn't do much useful. */
+
+int main(int argc, char *argv[])
+{
+    g_thread_init(NULL);
+
+    printf("BlueSkyFS starting...\n");
+
+    BlueSkyInode *root = bluesky_new_inode(1);
+    root->type = BLUESKY_DIRECTORY;
+    root->dirents = g_sequence_new(bluesky_dirent_destroy);
+
+    bluesky_directory_insert(root, "foo", 2);
+    bluesky_directory_insert(root, "bar", 3);
+    bluesky_directory_insert(root, "baz", 4);
+    bluesky_directory_insert(root, "baz", 5);
+
+    bluesky_directory_dump(root);
+    bluesky_directory_lookup(root, "foo");
+    bluesky_directory_lookup(root, "bar");
+    bluesky_directory_lookup(root, "baz");
+
+    return 0;
+}