Whamcloud - gitweb
LU-13799 osc: Always set aio in anchor
[fs/lustre-release.git] / lustre / utils / ofd_access_batch.c
index aebc940..75cd43e 100644 (file)
  *
  * Access log entry batching for ofd_access_log_reader.
  */
+#include <stdlib.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <assert.h>
 #include <malloc.h>
+#include <unistd.h>
+#include <pthread.h>
 #include <linux/lustre/lustre_access_log.h>
 #include <linux/lustre/lustre_fid.h>
 #include <linux/lustre/lustre_idl.h>
 #include "ofd_access_batch.h"
 
 /* XXX Weird param order to be consistent with list_replace_init(). */
-static inline void hlist_replace_init(struct hlist_node *old_node,
-                               struct hlist_node *new_node)
+static inline void list_replace_init(struct list_head *old_node,
+                               struct list_head *new_node)
 {
-       hlist_add_before(new_node, old_node);
-       hlist_del_init(old_node);
+       list_add(new_node, old_node);
+       list_del_init(old_node);
 }
 
 struct fid_hash_node {
-       struct hlist_node fhn_node;
+       struct list_head fhn_node;
        struct lu_fid fhn_fid;
 };
 
@@ -118,45 +121,44 @@ static unsigned long fid_hash(const struct lu_fid *f, unsigned int shift)
 
 static void fhn_init(struct fid_hash_node *fhn, const struct lu_fid *fid)
 {
-       INIT_HLIST_NODE(&fhn->fhn_node);
+       INIT_LIST_HEAD(&fhn->fhn_node);
        fhn->fhn_fid = *fid;
 }
 
-static bool fhn_is_hashed(const struct fid_hash_node *fhn)
+static bool fhn_is_hashed(struct fid_hash_node *fhn)
 {
-       return !hlist_unhashed(&fhn->fhn_node);
+       return !list_empty(&fhn->fhn_node);
 }
 
 static void fhn_del_init(struct fid_hash_node *fhn)
 {
        if (fhn_is_hashed(fhn))
-               hlist_del_init(&fhn->fhn_node);
+               list_del_init(&fhn->fhn_node);
 }
 
 static inline void fhn_replace_init(struct fid_hash_node *old_fhn,
                                struct fid_hash_node *new_fhn)
 {
-       hlist_add_before(&new_fhn->fhn_node, &old_fhn->fhn_node);
-       hlist_del_init(&old_fhn->fhn_node);
+       list_add(&new_fhn->fhn_node, &old_fhn->fhn_node);
+       list_del_init(&old_fhn->fhn_node);
 }
 
-void fid_hash_add(struct hlist_head *head, unsigned int shift,
+void fid_hash_add(struct list_head *head, unsigned int shift,
                struct fid_hash_node *fhn)
 {
        assert(!fhn_is_hashed(fhn));
 
-       hlist_add_head(&fhn->fhn_node, &head[fid_hash(&fhn->fhn_fid, shift)]);
+       list_add(&fhn->fhn_node, &head[fid_hash(&fhn->fhn_fid, shift)]);
 }
 
 struct fid_hash_node *
-fid_hash_find(struct hlist_head *head, unsigned int shift, const struct lu_fid *fid)
+fid_hash_find(struct list_head *head, unsigned int shift, const struct lu_fid *fid)
 {
-       struct hlist_head *hash_list;
-       struct hlist_node *node, *next;
-       struct fid_hash_node *fhn;
+       struct list_head *hash_list;
+       struct fid_hash_node *fhn, *next;
 
        hash_list = &head[fid_hash(fid, shift)];
-       hlist_for_each_entry_safe(fhn, node, next, hash_list, fhn_node) {
+       list_for_each_entry_safe(fhn, next, hash_list, fhn_node) {
                assert(fhn_is_hashed(fhn));
 
                if (fid_eq(fid, &fhn->fhn_fid))
@@ -167,28 +169,27 @@ fid_hash_find(struct hlist_head *head, unsigned int shift, const struct lu_fid *
 }
 
 struct fid_hash_node *
-fid_hash_insert(struct hlist_head *head, unsigned int shift, struct fid_hash_node *new_fhn)
+fid_hash_insert(struct list_head *head, unsigned int shift, struct fid_hash_node *new_fhn)
 {
-       struct hlist_head *list;
-       struct hlist_node *node, *next;
-       struct fid_hash_node *old_fhn;
+       struct list_head *list;
+       struct fid_hash_node *old_fhn, *next;
 
        list = &head[fid_hash(&new_fhn->fhn_fid, shift)];
-       hlist_for_each_entry_safe(old_fhn, node, next, list, fhn_node) {
+       list_for_each_entry_safe(old_fhn, next, list, fhn_node) {
                assert(fhn_is_hashed(old_fhn));
 
                if (fid_eq(&old_fhn->fhn_fid, &new_fhn->fhn_fid))
                        return old_fhn;
        }
 
-       hlist_add_head(&new_fhn->fhn_node, list);
+       list_add(&new_fhn->fhn_node, list);
 
        return new_fhn;
 }
 
-int fid_hash_init(struct hlist_head **phead, unsigned int *pshift, unsigned int shift)
+int fid_hash_init(struct list_head **phead, unsigned int *pshift, unsigned int shift)
 {
-       struct hlist_head *new_head;
+       struct list_head *new_head;
        unsigned int i;
 
        new_head = malloc(sizeof(*new_head) << shift);
@@ -196,7 +197,7 @@ int fid_hash_init(struct hlist_head **phead, unsigned int *pshift, unsigned int
                return -1;
 
        for (i = 0; i < (1 << shift); i++)
-               INIT_HLIST_HEAD(&new_head[i]);
+               INIT_LIST_HEAD(&new_head[i]);
 
        *phead = new_head;
        *pshift = shift;
@@ -204,9 +205,9 @@ int fid_hash_init(struct hlist_head **phead, unsigned int *pshift, unsigned int
        return 0;
 }
 
-int fid_hash_resize(struct hlist_head **phead, unsigned int *pshift, unsigned int new_shift)
+int fid_hash_resize(struct list_head **phead, unsigned int *pshift, unsigned int new_shift)
 {
-       struct hlist_head *new_head;
+       struct list_head *new_head;
        unsigned int i;
        int rc;
 
@@ -218,11 +219,10 @@ int fid_hash_resize(struct hlist_head **phead, unsigned int *pshift, unsigned in
                return rc;
 
        for (i = 0; i < (1 << *pshift); i++) {
-               struct hlist_head *list = &(*phead)[i];
-               struct hlist_node *node, *next;
-               struct fid_hash_node *fhn;
+               struct list_head *list = &(*phead)[i];
+               struct fid_hash_node *fhn, *next;
 
-               hlist_for_each_entry_safe(fhn, node, next, list, fhn_node) {
+               list_for_each_entry_safe(fhn, next, list, fhn_node) {
                        fhn_del_init(fhn);
                        fid_hash_add(new_head, new_shift, fhn);
                }
@@ -258,7 +258,7 @@ enum {
 };
 
 struct alr_batch {
-       struct hlist_head *alrb_hash;
+       struct list_head *alrb_hash;
        unsigned int alrb_hash_shift;
        unsigned int alrb_count;
 };
@@ -323,52 +323,175 @@ out:
        return rc;
 }
 
+int sort_compare(const void *a1, const void *a2)
+{
+       int l = *(const int*)a1;
+       int r = *(const int *)a2;
+       if (l > r) return -1;
+       if (l < r) return  1;
+       return 0;
+}
+
+static void alre_printf(FILE *f, struct alr_entry *alre, int d)
+{
+       fprintf(f, "o=%s f="DFID" t=%lld b=%llu e=%llu s=%llu g=%llu n=%llu d=%c\n",
+               alre->alre_obd_name,
+               PFID(&alre->alre_fid_hash_node.fhn_fid),
+               (long long)alre->alre_time[d],
+               (unsigned long long)alre->alre_begin[d],
+               (unsigned long long)alre->alre_end[d],
+               (unsigned long long)alre->alre_size[d],
+               (unsigned long long)alre->alre_segment_count[d],
+               (unsigned long long)alre->alre_count[d],
+               (d == ALR_READ) ? 'r' : 'w');
+}
+
+struct alr_thread_arg {
+       struct list_head list;
+       int fraction;
+       FILE *file;
+       pthread_mutex_t *file_mutex;
+};
+
+void *alr_sort_and_print_thread(void *arg)
+{
+       struct alr_entry *alre, *next;
+       struct alr_thread_arg *aa = arg;
+       struct list_head *tmp = &aa->list;
+       int *sa = NULL;
+       int rc, d, i, nr = 0;
+       unsigned long cut;
+
+       list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
+               if (alre->alre_count[0] > 0)
+                       nr++;
+               if (alre->alre_count[1] > 0)
+                       nr++;
+       }
+
+       if (nr == 0)
+               goto out;
+
+       sa = calloc(nr, sizeof(*sa));
+       if (!sa) {
+               fprintf(stderr, "cannot allocate memory for sorting\n");
+               exit(1);
+       }
+
+       i = 0;
+       list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
+               if (alre->alre_count[0] > 0)
+                       sa[i++] = alre->alre_count[0];
+               if (alre->alre_count[1] > 0)
+                       sa[i++] = alre->alre_count[1];
+       }
+
+       qsort(sa, nr, sizeof(*sa), sort_compare);
+       i = nr * aa->fraction / 100;
+       cut = sa[i];
+       if (cut < 1)
+               cut = 1;
+       free(sa);
+
+       /* Prevent jumbled output from multiple concurrent sort and
+        * print threads. */
+       rc = pthread_mutex_lock(aa->file_mutex);
+       if (rc != 0) {
+               fprintf(stderr, "cannot lock batch file: %s\n",
+                       strerror(rc));
+               exit(1);
+       }
+
+       /* there might be lots of items at @cut, but we want to limit total
+        * output. so the first loop dumps all items > @cut and the second
+        * loop dumps items=@cut so that total number (@i) is not exceeeded.
+        * XXX: possible optimization - move items=@cut to another list, so
+        * that 2nd pass takes < O(n) */
+       list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
+               for (d = 0; d < 2; d++) {
+                       if (alre->alre_count[d] <= cut)
+                               continue;
+                       alre_printf(aa->file, alre, d);
+                       i--;
+               }
+       }
+
+       list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
+               for (d = 0; d < 2 && i > 0; d++) {
+                       if (alre->alre_count[d] != cut)
+                               continue;
+                       alre_printf(aa->file, alre, d);
+                       i--;
+               }
+       }
+
+       rc = pthread_mutex_unlock(aa->file_mutex);
+       if (rc != 0) {
+               fprintf(stderr, "cannot unlock batch file: %s\n",
+                       strerror(rc));
+               exit(1);
+       }
+
+out:
+       fflush(aa->file);
+
+       list_for_each_entry_safe(alre, next, tmp, alre_fid_hash_node.fhn_node) {
+               alre_del_init(alre);
+               free(alre);
+       }
+
+       free(aa);
+
+       return NULL;
+}
+
 /* Print, clear, and resize the batch. */
-int alr_batch_print(struct alr_batch *alrb, FILE *file)
+int alr_batch_print(struct alr_batch *alrb, FILE *file,
+                   pthread_mutex_t *file_mutex, int fraction)
 {
-       unsigned int i;
        unsigned int new_hash_shift;
-       int rc = 0;
+       pthread_attr_t attr, *pattr = NULL;
+       struct alr_thread_arg *aa = NULL;
+       pthread_t pid;
+       int i, rc;
 
        if (alrb == NULL)
                return 0;
 
-       for (i = 0; i < (1 << alrb->alrb_hash_shift); i++) {
-               struct hlist_head *list = &alrb->alrb_hash[i];
-               struct hlist_node *node, *next;
-               struct alr_entry *alre;
-
-               hlist_for_each_entry_safe(alre, node, next, list,
-                                       alre_fid_hash_node.fhn_node) {
-                       unsigned int d;
-
-                       for (d = 0; d < 2; d++) {
-                               int rc2;
-
-                               if (alre->alre_count[d] == 0)
-                                       continue;
-
-                               /* stdio stream error state is sticky. */
-                               rc2 = fprintf(file,
-                                       "%s "DFID" %lld %llu %llu %llu %llu %llu %c\n",
-                                       alre->alre_obd_name,
-                                       PFID(&alre->alre_fid_hash_node.fhn_fid),
-                                       (long long)alre->alre_time[d],
-                                       (unsigned long long)alre->alre_begin[d],
-                                       (unsigned long long)alre->alre_end[d],
-                                       (unsigned long long)alre->alre_size[d],
-                                       (unsigned long long)alre->alre_segment_count[d],
-                                       (unsigned long long)alre->alre_count[d],
-                                       (d == ALR_READ) ? 'r' : 'w');
-                               if (rc2 < 0)
-                                       rc = rc2;
-                       }
+       aa = calloc(1, sizeof(*aa));
+       if (aa == NULL)
+               return -ENOMEM;
 
-                       alre_del_init(alre);
-                       free(alre);
-               }
+       /* move all collected items to the temp list */
+       INIT_LIST_HEAD(&aa->list);
+       for (i = 0; i < (1 << alrb->alrb_hash_shift); i++) {
+               if (list_empty(&alrb->alrb_hash[i]))
+                       continue;
+               list_splice(&alrb->alrb_hash[i], &aa->list);
+               INIT_LIST_HEAD(&alrb->alrb_hash[i]);
        }
+       aa->file = file;
+       aa->file_mutex = file_mutex;
+       aa->fraction = fraction;
+
+       rc = pthread_attr_init(&attr);
+       if (rc != 0)
+               goto out;
 
+       pattr = &attr;
+
+       rc = pthread_attr_setdetachstate(pattr, PTHREAD_CREATE_DETACHED);
+       if (rc != 0)
+               goto out;
+
+       /* as sorting may take time and we don't want to lose access
+        * records we better do sorting and printing in a different thread */
+       rc = pthread_create(&pid, pattr, &alr_sort_and_print_thread, aa);
+       if (rc != 0)
+               goto out;
+
+       aa = NULL; /* Sort and print thread owns it now. */
+out:
        /* Resize hash based on previous count. */
        new_hash_shift = alrb->alrb_hash_shift;
 
@@ -381,6 +504,24 @@ int alr_batch_print(struct alr_batch *alrb, FILE *file)
 
        alrb->alrb_count = 0;
 
+       if (pattr != NULL)
+               pthread_attr_destroy(pattr);
+
+       if (aa != NULL) {
+               struct alr_entry *alre, *next;
+
+               list_for_each_entry_safe(alre, next, &aa->list,
+                                        alre_fid_hash_node.fhn_node) {
+                       alre_del_init(alre);
+                       free(alre);
+               }
+       }
+
+       free(aa);
+
+       if (rc > 0)
+               rc = -rc; /* Fixup pthread return conventions. */
+
        return rc;
 }
 
@@ -413,11 +554,10 @@ void alr_batch_destroy(struct alr_batch *alrb)
                return;
 
        for (i = 0; i < (1 << alrb->alrb_hash_shift); i++) {
-               struct hlist_head *list = &alrb->alrb_hash[i];
-               struct hlist_node *node, *next;
-               struct alr_entry *alre;
+               struct list_head *list = &alrb->alrb_hash[i];
+               struct alr_entry *alre, *next;
 
-               hlist_for_each_entry_safe(alre, node, next, list, alre_fid_hash_node.fhn_node) {
+               list_for_each_entry_safe(alre, next, list, alre_fid_hash_node.fhn_node) {
                        alre_del_init(alre);
                        free(alre);
                }