[Pvfs2-cvs] commit by shuangy in pvfs2/src/common/misc: mkspace.c

CVS commit program cvs at parl.clemson.edu
Fri May 13 17:15:06 EDT 2011


Update of /projects/cvsroot/pvfs2/src/common/misc
In directory parlweb1:/tmp/cvs-serv16847/src/common/misc

Modified Files:
      Tag: Orange-Elaine-Distr-Dir-Branch
	mkspace.c 
Log Message:
distributed directory structure for root and lost+found directory. In pvfs2-server.c, it will check if the root directory is set. Need 10~20 seconds for creation when the servers are launched at first time.


Index: mkspace.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/mkspace.c,v
diff -p -u -r1.44.10.1.8.7 -r1.44.10.1.8.8
--- mkspace.c	17 Mar 2011 22:17:23 -0000	1.44.10.1.8.7
+++ mkspace.c	13 May 2011 21:15:06 -0000	1.44.10.1.8.8
@@ -27,7 +27,9 @@
 #include "pint-event.h"
 #include "dist-dir-utils.h"
 
+/*
 static char *lost_and_found_string = "lost+found";
+*/
 
 static TROVE_handle s_used_handles[4] =
 {
@@ -43,6 +45,8 @@ do {                                    
    fprintf(stderr,format, ##f);                     \
 } while(0)
 
+
+#if 0
 static int handle_is_excluded(
     TROVE_handle handle, TROVE_handle *handles_to_exclude,
     int num_handles_to_exclude)
@@ -110,6 +114,7 @@ static void get_handle_extent_from_range
         }
     }
 }
+#endif
 
 int pvfs2_mkspace(
     char *data_path,
@@ -122,7 +127,7 @@ int pvfs2_mkspace(
     int create_collection_only,
     int verbose)
 {
-    int ret = - 1, count = 0, keyval_count, i;
+    int ret = - 1, count = 0;
     TROVE_op_id op_id;
     TROVE_ds_state state;
     TROVE_keyval_s key, val;
@@ -132,19 +137,7 @@ int pvfs2_mkspace(
     TROVE_handle_extent_array extent_array;
     TROVE_context_id trove_context = -1;
     char *merged_handle_ranges = NULL;
-    unsigned char *c = NULL;
     TROVE_handle new_root_handle = TROVE_HANDLE_NULL;
-    TROVE_handle root_dirdata_handle = TROVE_HANDLE_NULL;
-    TROVE_handle lost_and_found_handle = TROVE_HANDLE_NULL;
-    TROVE_handle lost_and_found_dirdata_handle = TROVE_HANDLE_NULL;
-
-    /* distributed directory parameters */
-    PVFS_dist_dir_attr meta_dist_dir_attr;
-    PVFS_dist_dir_attr dirdata_dist_dir_attr;
-    PVFS_dist_dir_bitmap dist_dir_bitmap = NULL;
-    /* only one dirdata_handle for root and lost_and_found, not using arrays
-    PVFS_handle *dirdata_handles;
-    */
 
     mkspace_print(verbose,"Data storage space     : %s\n",data_path);
     mkspace_print(verbose,"Metadata storage space : %s\n", meta_path);
@@ -290,8 +283,9 @@ int pvfs2_mkspace(
 
     /*
       if a root_handle is specified, 1) create a dataspace to hold the
-      root directory 2) create the dspace for dir entries, 3) set
-      attributes on the dspace
+      root directory  2) set attributes on the dspace
+
+      The dirdata objects and the lost+found directory are created in pvfs2-server.c
     */
     if (new_root_handle != TROVE_HANDLE_NULL)
     {
@@ -371,546 +365,12 @@ int pvfs2_mkspace(
             return -1;
         }
 
-        /*
-          create a dataspace to hold directory entries; if we have a
-          meta handle range, use that one of those ranges (being
-          careful to make sure the range has enough space for an
-          allocation) to allocate a dataspace to hold directory
-          entries.  if we don't have a meta handle range, use
-          TROVE_HANDLE_NULL which tells the allocator to use any
-          handle available
-        */
-        cur_extent.first = cur_extent.last = TROVE_HANDLE_NULL;
-        if (meta_handle_ranges)
-        {
-            get_handle_extent_from_ranges(
-                meta_handle_ranges, &cur_extent, s_used_handles, 1);
-
-            if ((cur_extent.first == TROVE_HANDLE_NULL) &&
-                (cur_extent.last == TROVE_HANDLE_NULL))
-            {
-                gossip_err("No valid meta handle ranges available! "
-                           "Using a default\n");
-            }
-            else
-            {
-                mkspace_print(
-                    verbose, "info: using meta handle range %llu-%llu for "
-                    "root dirent dspace\n", llu(cur_extent.first),
-                    llu(cur_extent.last));
-            }
-        }
-
-        extent_array.extent_count = 1;
-        extent_array.extent_array = &cur_extent;
-
-        ret = trove_dspace_create(
-            coll_id, &extent_array, &root_dirdata_handle,
-            PVFS_TYPE_DIRDATA, NULL, TROVE_SYNC, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if ((ret != 1) && (state != 0))
-        {
-            gossip_err("dspace create (for dirent storage) failed.\n");
-            return -1;
-        }
-
-        mkspace_print(verbose, "info: created dspace for dirents "
-                      "with handle %llu\n", llu(root_dirdata_handle));
-        s_used_handles[1] = root_dirdata_handle;
-
-        /* set root dirdata dspace attributes */
-        memset(&attr, 0, sizeof(TROVE_ds_attributes_s));
-        attr.uid = getuid();
-        attr.gid = getgid();
-        attr.mode = 0777;
-        attr.type = PVFS_TYPE_DIRDATA;
-	attr.atime = attr.ctime = PINT_util_get_current_time();
-        attr.mtime = PINT_util_mktime_version(attr.ctime);
-
-        ret = trove_dspace_setattr(
-            coll_id, root_dirdata_handle, &attr, TROVE_SYNC, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: dspace setattr for root dirdata handle "
-                       "attributes failed; aborting!\n");
-            return -1;
-        }
-
-
-        key.buffer = DIRECTORY_ENTRY_KEYSTR;
-        key.buffer_sz = DIRECTORY_ENTRY_KEYLEN;
-        val.buffer = &root_dirdata_handle;
-        val.buffer_sz = sizeof(TROVE_handle);
-            
-        ret = trove_keyval_write(
-            coll_id, new_root_handle, &key, &val,
-            TROVE_SYNC, 0, NULL,
-            trove_context, &op_id, NULL);
-            
-        while (ret == 0)
-        {           
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-        
-        if (ret < 0)
-        {
-            gossip_err("error: keyval write for handle used to store "
-                       "dirents failed; aborting!\n");
-            return -1;
-        }   
-
-        mkspace_print(
-            verbose, "info: wrote attributes for root directory.\n");
-            
-
-        /* !!! set dist-dir-struct keyvals for root handle and its dirdata handle */
-        /* init meta handle dist_dir_struct, num_servers=1, server_no = -1, pre_dsg_num_server=1 */
-        /* should be reusable when init lost+found */
-        ret = PINT_init_dist_dir_state(&meta_dist_dir_attr,
-                &dist_dir_bitmap, 1, 0, 1);
-        assert(ret == 0);
-
-        /* gossip dist_dir_attr and dist_dir_bitmap */
-        mkspace_print(verbose, "info: init dist_dir_attr for root handle %llu: \n"
-                "with tree_height=%d, num_servers=%d, bitmap_size=%d, "
-                "split_size=%d, server_no=%d and branch_level=%d\n",
-                llu(new_root_handle),
-                meta_dist_dir_attr.tree_height,
-                meta_dist_dir_attr.num_servers,
-                meta_dist_dir_attr.bitmap_size,
-                meta_dist_dir_attr.split_size,
-                meta_dist_dir_attr.server_no,
-                meta_dist_dir_attr.branch_level);
-        mkspace_print(verbose, "info: init dist_dir_bitmap as:\n");
-        for(i = meta_dist_dir_attr.bitmap_size - 1;
-                i >= 0 ; i--)
-        {
-            c = (unsigned char *)(dist_dir_bitmap + i);
-            mkspace_print(verbose,
-                    " i=%d : %02x %02x %02x %02x\n",
-                    i, c[3], c[2], c[1], c[0]);
-        }
-        mkspace_print(verbose, "\n");
-
-        /* init dirdata_dist_dir_attr */
-        PINT_dist_dir_attr_copyto(dirdata_dist_dir_attr, meta_dist_dir_attr);
-        PINT_dist_dir_set_serverno(0, &dirdata_dist_dir_attr, dist_dir_bitmap);
-
-        mkspace_print(verbose, "info: init dist_dir_attr for root dirdata handle %llu: \n"
-                "with tree_height=%d, num_servers=%d, bitmap_size=%d, "
-                "split_size=%d, server_no=%d and branch_level=%d\n",
-                llu(root_dirdata_handle),
-                dirdata_dist_dir_attr.tree_height,
-                dirdata_dist_dir_attr.num_servers,
-                dirdata_dist_dir_attr.bitmap_size,
-                dirdata_dist_dir_attr.split_size,
-                dirdata_dist_dir_attr.server_no,
-                dirdata_dist_dir_attr.branch_level);
-
-        keyval_count = 3;
-
-        key_a = malloc(sizeof(TROVE_keyval_s) * keyval_count);
-        if(!key_a)
-        {
-            gossip_err("keyval space create (for root and lost+found storage) failed.\n");
-            return -1;
-        }
-        memset(key_a, 0, sizeof(TROVE_keyval_s) * keyval_count);
-
-        val_a = malloc(sizeof(TROVE_keyval_s) * keyval_count);
-        if(!val_a)
-        {
-            free(key_a);
-            gossip_err("keyval space create (for root and lost+found storage) failed.\n");
-            return -1;
-        }
-        memset(val_a, 0, sizeof(TROVE_keyval_s) * keyval_count);
-
-        /* set keyval for root meta handle */
-        key_a[0].buffer = DIST_DIR_ATTR_KEYSTR;
-        key_a[0].buffer_sz = DIST_DIR_ATTR_KEYLEN;
-
-        val_a[0].buffer = &meta_dist_dir_attr;
-        val_a[0].buffer_sz =
-            sizeof(meta_dist_dir_attr);
-
-        key_a[1].buffer = DIST_DIRDATA_BITMAP_KEYSTR;
-        key_a[1].buffer_sz = DIST_DIRDATA_BITMAP_KEYLEN;
-
-        val_a[1].buffer_sz =
-            meta_dist_dir_attr.bitmap_size *  /* bitmap_size = 1 */
-            sizeof(PVFS_dist_dir_bitmap_basetype);
-        val_a[1].buffer = dist_dir_bitmap;
-
-        key_a[2].buffer = DIST_DIRDATA_HANDLES_KEYSTR;
-        key_a[2].buffer_sz = DIST_DIRDATA_HANDLES_KEYLEN;
-
-        val_a[2].buffer = &root_dirdata_handle; /* only one dirdata server */
-        val_a[2].buffer_sz = meta_dist_dir_attr.num_servers * 
-            sizeof(root_dirdata_handle);
-
-        mkspace_print(verbose, 
-                " info: writing dist-dir-struct keyvals for root handle: %llu "
-                " with server_no=%d and branch_level=%d \n", 
-                llu(new_root_handle),
-                meta_dist_dir_attr.server_no,
-                meta_dist_dir_attr.branch_level);
-
-        /* write to root meta handle keyval space */
-        ret = trove_keyval_write_list(
-            coll_id, new_root_handle, key_a, val_a, keyval_count,
-            TROVE_SYNC, 0, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: keyval write for handle used to store "
-                       "dirents failed; aborting!\n");
-            return -1;
-        }
-
-        /* adjust dist_dir_attr val_a */
-        val_a[0].buffer = &dirdata_dist_dir_attr;
-        
-        mkspace_print(verbose, 
-                " info: writing dist-dir-struct keyvals for root dirdata handle: %llu "
-                " with server_no=%d and branch_level=%d \n", 
-                llu(root_dirdata_handle),
-                dirdata_dist_dir_attr.server_no,
-                dirdata_dist_dir_attr.branch_level);
-
-        /* write to root dirdata handle keyval space */
-        ret = trove_keyval_write_list(
-            coll_id, root_dirdata_handle, key_a, val_a, keyval_count,
-            TROVE_SYNC, 0, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: dist-dir-struct keyval write for root dirdata handle "
-                       "failed; aborting!\n");
-            return -1;
-        }
-
-        mkspace_print(
-            verbose, "info: wrote attributes for root directory.\n");
-
-
-        /****************************************************
-          at this point we need to create and initialize the
-          lost+found directory as well
-        *****************************************************/
-        cur_extent.first = cur_extent.last = TROVE_HANDLE_NULL;
-        if (meta_handle_ranges)
-        {
-            get_handle_extent_from_ranges(
-                meta_handle_ranges, &cur_extent, s_used_handles, 2);
-
-            if ((cur_extent.first == TROVE_HANDLE_NULL) &&
-                (cur_extent.last == TROVE_HANDLE_NULL))
-            {
-                gossip_err("No valid meta handle ranges available! "
-                           "Using a default\n");
-            }
-            else
-            {
-                mkspace_print(
-                    verbose, "info: using meta handle range %llu-%llu for "
-                    "lost+found directory dspace\n", llu(cur_extent.first),
-                    llu(cur_extent.last));
-            }
-        }
-        extent_array.extent_count = 1;
-        extent_array.extent_array = &cur_extent;
-
-        ret = trove_dspace_create(
-            coll_id, &extent_array, &lost_and_found_handle,
-            PVFS_TYPE_DIRECTORY, NULL, TROVE_SYNC, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if ((ret != 1) && (state != 0))
-        {
-            mkspace_print(verbose,
-                          "dspace create (for lost+found dir) failed.\n");
-            return -1;
-        }
 
-        mkspace_print(verbose,"info: created lost+found directory "
-                      "with handle %llu.\n", llu(lost_and_found_handle));
-        s_used_handles[2] = lost_and_found_handle;
+        /* The creation of dirdata objects for the root directory is 
+         * moved to pvfs2_server.c to setup distributed directory struct.
+         * lost+found directory is also created there. 
+         */
 
-        /* set lost+found directory dspace attributes */
-        memset(&attr, 0, sizeof(TROVE_ds_attributes_s));
-        attr.uid = getuid();
-        attr.gid = getgid();
-        attr.mode = 0777;
-        attr.type = PVFS_TYPE_DIRECTORY;
-	attr.atime = attr.ctime = PINT_util_get_current_time();
-        attr.mtime = PINT_util_mktime_version(attr.ctime);
-
-        ret = trove_dspace_setattr(
-            coll_id, lost_and_found_handle, &attr, TROVE_SYNC, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: dspace setattr for lost+found handle "
-                       "attributes failed; aborting!\n");
-            return -1;
-        }
-
-        /* create a dataspace to hold directory entries */
-        cur_extent.first = cur_extent.last = TROVE_HANDLE_NULL;
-        if (meta_handle_ranges)
-        {
-            get_handle_extent_from_ranges(
-                meta_handle_ranges, &cur_extent, s_used_handles, 3);
-
-            if ((cur_extent.first == TROVE_HANDLE_NULL) &&
-                (cur_extent.last == TROVE_HANDLE_NULL))
-            {
-                gossip_err("No valid meta handle ranges available! "
-                           "Using a default\n");
-            }
-            else
-            {
-                mkspace_print(
-                    verbose, "info: using meta handle range %llu-%llu for "
-                    "lost+found dirent dspace\n", llu(cur_extent.first),
-                    llu(cur_extent.last));
-            }
-        }
-        extent_array.extent_count = 1;
-        extent_array.extent_array = &cur_extent;
-
-        ret = trove_dspace_create(
-            coll_id, &extent_array, &lost_and_found_dirdata_handle,
-            PVFS_TYPE_DIRDATA, NULL, TROVE_SYNC, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if ((ret != 1) && (state != 0))
-        {
-            gossip_err("dspace create (for dirent storage) failed.\n");
-            return -1;
-        }
-
-        mkspace_print(
-            verbose, "info: created dspace for dirents "
-            "with handle %llu\n", llu(lost_and_found_dirdata_handle));
-        s_used_handles[3] = lost_and_found_dirdata_handle;
-
-        /* set lost+found dirdata dspace attributes */
-        memset(&attr, 0, sizeof(TROVE_ds_attributes_s));
-        attr.uid = getuid();
-        attr.gid = getgid();
-        attr.mode = 0777;
-        attr.type = PVFS_TYPE_DIRDATA;
-	attr.atime = attr.ctime = PINT_util_get_current_time();
-        attr.mtime = PINT_util_mktime_version(attr.ctime);
-
-        ret = trove_dspace_setattr(
-            coll_id, lost_and_found_dirdata_handle, &attr, TROVE_SYNC, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: dspace setattr for lost+found handle "
-                       "attributes failed; aborting!\n");
-            return -1;
-        }
-
-        key.buffer = DIRECTORY_ENTRY_KEYSTR;
-        key.buffer_sz = DIRECTORY_ENTRY_KEYLEN;
-        val.buffer = &lost_and_found_dirdata_handle;
-        val.buffer_sz = sizeof(TROVE_handle);
-
-        ret = trove_keyval_write(
-            coll_id, lost_and_found_handle, &key, &val,
-            TROVE_SYNC,
-            0, NULL, trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: keyval write for handle used to store "
-                       "dirents failed; aborting!\n");
-            return -1;
-        }
-
-        mkspace_print(verbose, "info: wrote attributes for "
-                      "lost+found directory.\n");
-
-
-        /* set dist-dir-struct keyvals for lost+find handle and its dirdata handle 
-         * use 1 dirdata server now, just as root handle
-         * */
-
-        /* adjust keyval values, others should be the same as the root handle */
-        val_a[0].buffer = &meta_dist_dir_attr;
-        val_a[2].buffer = &lost_and_found_dirdata_handle;
-        /* bitmap should be the same as the root handle for now */
-
-        mkspace_print(verbose, 
-                " info: writing dist-dir-struct keyvals for lost+found handle: %llu "
-                " with server_no=%d and branch_level=%d \n", 
-                llu(lost_and_found_handle),
-                meta_dist_dir_attr.server_no,
-                meta_dist_dir_attr.branch_level);
-
-        /* write to lost+found meta handle keyval space */
-        ret = trove_keyval_write_list(
-            coll_id, lost_and_found_handle, key_a, val_a, keyval_count,
-            TROVE_SYNC, 0, NULL,
-            trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: keyval write for handle used to store "
-                       "dirents failed; aborting!\n");
-            return -1;
-        }
-
-
-        /* adjust dist_dir_attr val */
-        val_a[0].buffer = &dirdata_dist_dir_attr;
-
-        mkspace_print(verbose, 
-                " info: writing dist-dir-struct keyvals for lost+found dirdata handle: %llu "
-                " with server_no=%d and branch_level=%d \n", 
-                llu(lost_and_found_dirdata_handle),
-                dirdata_dist_dir_attr.server_no,
-                dirdata_dist_dir_attr.branch_level);
-
-        /* write to lost+found dirdata handle keyval space */
-        ret = trove_keyval_write_list(
-                coll_id, lost_and_found_dirdata_handle, key_a, val_a, keyval_count,
-                TROVE_SYNC, 0, NULL,
-                trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                    coll_id, op_id, trove_context, &count, NULL, NULL,
-                    &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: dist-dir-struct keyval write for lost+found dirdata handle "
-                    "failed; aborting!\n");
-            return -1;
-        }
-
-        mkspace_print(verbose, "info: wrote attributes for "
-                      "lost+found directory.\n");
-
-
-        /*
-          finally, crdirent the lost+found directory into the root
-          directory by writing the appropriate keyval info into the
-          root dirdata handle space
-        */
-        key.buffer = lost_and_found_string;
-        key.buffer_sz = strlen(lost_and_found_string) + 1;
-        val.buffer = &lost_and_found_handle;
-        val.buffer_sz = sizeof(TROVE_handle);
-
-        ret = trove_keyval_write(
-            coll_id, root_dirdata_handle, &key, &val, 
-            TROVE_SYNC | TROVE_NOOVERWRITE | TROVE_KEYVAL_HANDLE_COUNT | TROVE_KEYVAL_DIRECTORY_ENTRY, 
-	    0,
-            NULL, trove_context, &op_id, NULL);
-
-        while (ret == 0)
-        {
-            ret = trove_dspace_test(
-                coll_id, op_id, trove_context, &count, NULL, NULL,
-                &state, TROVE_DEFAULT_TEST_TIMEOUT);
-        }
-
-        if (ret < 0)
-        {
-            gossip_err("error: keyval write for handle used to store "
-                       "dirents failed; aborting!\n");
-            return -1;
-        }
-
-        mkspace_print(verbose, "info: adding lost+found directory to "
-                      "the root directory.\n");
     }
     	
     if (trove_context != -1)
@@ -925,10 +385,6 @@ int pvfs2_mkspace(
                   llu(root_handle), coll_id, ROOT_HANDLE_KEYSTR);
 
     /* free space */
-    if (dist_dir_bitmap)
-    {
-        free(dist_dir_bitmap);
-    }
     if (key_a)
     {
         free(key_a);



More information about the Pvfs2-cvs mailing list