This a mechanism by which self-check may know what objects were updated
and thus should not be disturbed if their checksums fail.

Signed-off-by: Pete Zaitcev <[email protected]>

---
 include/Makefile.am  |    2 
 include/objcache.h   |   72 +++++++++++++++++++++++
 server/Makefile.am   |    3 
 server/chunkd.h      |    3 
 server/objcache.c    |  128 +++++++++++++++++++++++++++++++++++++++++
 server/object.c      |    9 ++
 server/server.c      |    7 ++
 test/.gitignore      |    1 
 test/Makefile.am     |    5 +
 test/objcache-unit.c |   58 ++++++++++++++++++
 10 files changed, 285 insertions(+), 3 deletions(-)

commit ab575b65211f00c73feffd4c8c58044142b1163f
Author: Master <[email protected]>
Date:   Sun Dec 27 16:04:43 2009 -0700

    Add the objcache.

diff --git a/include/Makefile.am b/include/Makefile.am
index ddc2b8a..7abe0b5 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,5 +1,5 @@
 
 include_HEADERS = chunkc.h chunk_msg.h
 
-EXTRA_DIST     = elist.h chunk_msg.h chunksrv.h chunk-private.h
+EXTRA_DIST     = elist.h chunk_msg.h chunksrv.h chunk-private.h objcache.h
 
diff --git a/include/objcache.h b/include/objcache.h
new file mode 100644
index 0000000..fce1485
--- /dev/null
+++ b/include/objcache.h
@@ -0,0 +1,72 @@
+
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or 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 this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef _CHUNKD_OBJCACHE_H_
+#define _CHUNKD_OBJCACHE_H_
+
+#include <glib.h>
+#include <elist.h>
+#include <stdbool.h>
+
+struct objcache {
+       struct list_head head;
+       GMutex *lock;
+};
+
+struct objcache_entry {
+       struct list_head link;
+       unsigned int hash;
+       unsigned int flags;
+       int ref;
+};
+
+#define OC_F_DIRTY   0x1
+
+/*
+ * Get an entry and set flags.
+ * A method for every flag is needed because our locks are internal to
+ * the cache, and we want this to be atomic.
+ */
+#define objcache_get(c, k, l)          __objcache_get(c, k, l, 0)
+#define objcache_get_dirty(c, k, l)    __objcache_get(c, k, l, OC_F_DIRTY)
+extern struct objcache_entry *__objcache_get(struct objcache *cache,
+                                            const char *key, int klen,
+                                            unsigned int flag);
+
+/*
+ * Test for dirty.
+ */
+extern bool objcache_test_dirty(struct objcache *cache,
+                               struct objcache_entry *entry);
+
+/*
+ * Put an entry (decrement and free, or an equivalent).
+ */
+extern void objcache_put(struct objcache *cache, struct objcache_entry *entry);
+
+/*
+ * Init a cache. Call once. May fail since it allocates a mutex.
+ */
+extern int objcache_init(struct objcache *cache);
+
+/*
+ * Terminate a cache.
+ */
+extern void objcache_fini(struct objcache *cache);
+
+#endif
diff --git a/server/Makefile.am b/server/Makefile.am
index 516b081..824c0b3 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -6,7 +6,8 @@ sbin_PROGRAMS   = chunkd
 
 chunkd_SOURCES = chunkd.h              \
                  ../lib/chunksrv.c     \
-                 be-fs.c object.c server.c config.c cldu.c util.c
+                 be-fs.c object.c server.c config.c cldu.c util.c \
+                 objcache.c
 chunkd_LDADD   = \
                  @CLDC_LIBS@ @GLIB_LIBS@ @CRYPTO_LIBS@ \
                  @SSL_LIBS@ @EVENT_LIBS@ @TOKYOCABINET_LIBS@
diff --git a/server/chunkd.h b/server/chunkd.h
index a97088d..18dd31a 100644
--- a/server/chunkd.h
+++ b/server/chunkd.h
@@ -28,6 +28,7 @@
 #include <chunk_msg.h>
 #include <hail_log.h>
 #include <tchdb.h>
+#include <objcache.h>
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
@@ -118,6 +119,7 @@ struct client {
        long                    out_len;
 
        struct backend_obj      *out_bo;
+       struct objcache_entry   *out_ce;
 
        long                    in_len;
        struct backend_obj      *in_obj;
@@ -210,6 +212,7 @@ struct server {
        struct geo              loc;
 
        TCHDB                   *tbl_master;
+       struct objcache         actives;
 
        struct server_stats     stats;          /* global statistics */
 };
diff --git a/server/objcache.c b/server/objcache.c
new file mode 100644
index 0000000..475ac23
--- /dev/null
+++ b/server/objcache.c
@@ -0,0 +1,128 @@
+
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or 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 this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <objcache.h>
+#include <stdlib.h>
+
+/*
+ * We really should not screw around with hand-rolled garbage and use
+ * something like Paul Hsieh's SuperFastHash, but licenses are too confusing.
+ */
+static unsigned int objcache_hash(const char *key, int klen)
+{
+       unsigned int hash;
+       int i;
+       unsigned char c;
+
+       hash = 0x55555555;
+       for (i = 0; i < klen; i++) {
+               c = (unsigned char) *key++;
+               hash ^= hash << 16;
+               hash ^= c;
+               hash = (hash << 8) | (hash >> 24);
+       }
+       return hash;
+}
+
+static struct objcache_entry *objcache_lookup(struct objcache *cache,
+                                             unsigned int hash)
+{
+       struct objcache_entry *cep;
+
+       list_for_each_entry(cep, &cache->head, link) {
+               if (cep->hash == hash)
+                       return cep;
+       }
+       return NULL;
+}
+
+static struct objcache_entry *objcache_insert(struct objcache *cache,
+                                             unsigned int hash)
+{
+       struct objcache_entry *cep;
+
+       cep = malloc(sizeof(struct objcache_entry));
+       if (!cep)
+               return NULL;
+       cep->hash = hash;
+       cep->flags = 0;
+       cep->ref = 1;
+       list_add(&cep->link, &cache->head);
+       return cep;
+}
+
+struct objcache_entry *__objcache_get(struct objcache *cache,
+                                     const char *key, int klen,
+                                     unsigned int flag)
+{
+       struct objcache_entry *cep;
+       unsigned int hash;
+
+       hash = objcache_hash(key, klen);
+       g_mutex_lock(cache->lock);
+       cep = objcache_lookup(cache, hash);
+       if (cep) {
+               cep->ref++;
+       } else {
+               cep = objcache_insert(cache, hash);
+       }
+       cep->flags |= flag;
+       g_mutex_unlock(cache->lock);
+       return cep;
+}
+
+bool objcache_test_dirty(struct objcache *cache, struct objcache_entry *cep)
+{
+       bool ret;
+
+       g_mutex_lock(cache->lock);
+       ret = cep->flags & OC_F_DIRTY;
+       g_mutex_unlock(cache->lock);
+       return ret;
+}
+
+void objcache_put(struct objcache *cache, struct objcache_entry *cep)
+{
+       g_mutex_lock(cache->lock);
+       if (!cep->ref) {
+               g_mutex_unlock(cache->lock);
+               /* Must not happen, or a leak for Valgrind to catch. */
+               return;
+       }
+       --cep->ref;
+       if (!cep->ref) {
+               list_del(&cep->link);
+               free(cep);
+       }
+       g_mutex_unlock(cache->lock);
+}
+
+int objcache_init(struct objcache *cache)
+{
+       cache->lock = g_mutex_new();
+       if (!cache->lock)
+               return -1;
+       INIT_LIST_HEAD(&cache->head);
+       return 0;
+}
+
+void objcache_fini(struct objcache *cache)
+{
+       g_mutex_free(cache->lock);
+}
diff --git a/server/object.c b/server/object.c
index a1205f5..5cc596a 100644
--- a/server/object.c
+++ b/server/object.c
@@ -73,6 +73,10 @@ void cli_out_end(struct client *cli)
                fs_obj_free(cli->out_bo);
                cli->out_bo = NULL;
        }
+       if (cli->out_ce) {
+               objcache_put(&chunkd_srv.actives, cli->out_ce);
+               cli->out_ce = NULL;
+       }
 
        free(cli->out_user);
        cli->out_user = NULL;
@@ -217,6 +221,11 @@ bool object_put(struct client *cli)
        if (!user)
                return cli_err(cli, che_AccessDenied, true);
 
+       cli->out_ce = objcache_get_dirty(&chunkd_srv.actives,
+                                        cli->key, cli->key_len);
+       if (!cli->out_ce)
+               return cli_err(cli, che_InternalError, true);
+
        cli->out_bo = fs_obj_new(cli->table_id, cli->key, cli->key_len, &err);
        if (!cli->out_bo)
                return cli_err(cli, err, true);
diff --git a/server/server.c b/server/server.c
index 3f38cca..e955dc8 100644
--- a/server/server.c
+++ b/server/server.c
@@ -1659,6 +1659,11 @@ int main (int argc, char *argv[])
                goto err_out_session;
        }
 
+       if (objcache_init(&chunkd_srv.actives) != 0) {
+               rc = 1;
+               goto err_out_objcache;
+       }
+
        INIT_LIST_HEAD(&chunkd_srv.wr_trash);
        chunkd_srv.trash_sz = 0;
 
@@ -1692,6 +1697,8 @@ err_out_listen:
 err_out_cld:
        fs_close();
 err_out_fs:
+       objcache_fini(&chunkd_srv.actives);
+err_out_objcache:
        if (strict_free)
                g_hash_table_destroy(chunkd_srv.fd_info);
 err_out_session:
diff --git a/test/.gitignore b/test/.gitignore
index ccb6bdb..a929882 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -4,6 +4,7 @@ it-works
 large-object
 lotsa-objects
 nop
+objcache-unit
 
 .libs
 libtest.a
diff --git a/test/Makefile.am b/test/Makefile.am
index d9c10b5..84b4837 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,6 +15,7 @@ EXTRA_DIST =                  \
        ssl-key.pem ssl-cert.pem
 
 TESTS =                                \
+       objcache-unit           \
        prep-db                 \
        start-daemon            \
        pid-exists              \
@@ -29,7 +30,7 @@ TESTS =                               \
        clean-db
 
 check_PROGRAMS         = auth basic-object it-works large-object \
-                         lotsa-objects nop
+                         lotsa-objects nop objcache-unit
 
 TESTLDADD              = ../lib/libchunkdc.la  \
                          libtest.a             \
@@ -42,6 +43,8 @@ large_object_LDADD    = $(TESTLDADD)
 lotsa_objects_LDADD    = $(TESTLDADD)
 nop_LDADD              = $(TESTLDADD)
 
+objcache_unit_LDADD    = @GLIB_LIBS@
+
 noinst_LIBRARIES       = libtest.a
 
 libtest_a_SOURCES      = libtest.c
diff --git a/test/objcache-unit.c b/test/objcache-unit.c
new file mode 100644
index 0000000..f101445
--- /dev/null
+++ b/test/objcache-unit.c
@@ -0,0 +1,58 @@
+
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or 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 this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "../server/objcache.c"
+#include "test.h"
+
+int main(int argc, char *argv[])
+{
+       static char k1[] = { 'a' };
+       static char k2[] = { 'a', 'a' };
+       static char k3[] = { 'a', '\0', 'a' };
+       struct objcache cache;
+       struct objcache_entry *ep1, *ep2, *ep3;
+       int rc;
+
+       g_thread_init(NULL);
+       rc = objcache_init(&cache);
+       OK(rc==0);
+
+       ep1 = objcache_get(&cache, k1, sizeof(k1));
+       OK(ep1 != NULL);
+
+       ep2 = objcache_get(&cache, k2, sizeof(k2));
+       OK(ep2 != NULL);
+
+       ep3 = objcache_get(&cache, k3, sizeof(k3));
+       OK(ep3 != NULL);
+
+       OK(ep1->ref == 1);      /* no collisions */
+
+       objcache_put(&cache, ep1);
+       objcache_put(&cache, ep2);
+       objcache_put(&cache, ep3);
+
+       ep2 = objcache_get(&cache, k2, sizeof(k2));
+       OK(ep2 != NULL);
+       OK(ep2->ref == 1);      /* new */
+       objcache_put(&cache, ep2);
+
+       objcache_fini(&cache);
+       return 0;
+}
--
To unsubscribe from this list: send the line "unsubscribe hail-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to