cedric pushed a commit to branch master.

commit f2de8970a137a6291ff35e42cfbf556120337ce5
Author: Cedric Bail <[email protected]>
Date:   Wed Jul 31 11:51:51 2013 +0900

    eina: add support for in memory only Eina_File.
---
 ChangeLog                       |   4 +
 NEWS                            |   1 +
 src/lib/eina/eina_file.c        |  43 +++++-----
 src/lib/eina/eina_file.h        |  26 +++++-
 src/lib/eina/eina_file_common.c | 173 +++++++++++++++++++++++++++++++++++++++-
 src/lib/eina/eina_file_common.h |  13 +++
 src/lib/eina/eina_file_win32.c  |  37 +++------
 7 files changed, 245 insertions(+), 52 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9c4c2b4..2e2d234 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-07-31  Cedric Bail
+
+       * Eina: add eina_file_virtualize() and eina_file_virtual().
+
 2013-07-25  ChunEon Park (Hermet)
 
         * Evas: Skip the map rendering if all points are transparent.
diff --git a/NEWS b/NEWS
index 8df3505..0bacd4e 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,7 @@ Additions:
      - Add eina_tiler_area_size_set(), eina_tiler_strict_set(), 
eina_tiler_area_size_get()
      - Add eina_file_map_populate()
      - Add eina_tiler_empty()
+     - Add eina_file_virtualize() and eina_file_virtual()
     * Eet:
      - Add eet_mmap()
      - Add eet_data_descriptor_name_get()
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index 6cc1e38..32ae4ea 100644
--- a/src/lib/eina/eina_file.c
+++ b/src/lib/eina/eina_file.c
@@ -324,27 +324,6 @@ _eina_file_map_close(Eina_File_Map *map)
    free(map);
 }
 
-static unsigned int
-_eina_file_map_key_length(const void *key EINA_UNUSED)
-{
-   return sizeof (unsigned long int) * 2;
-}
-
-static int
-_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length 
EINA_UNUSED,
-                       const unsigned long int *key2, int key2_length 
EINA_UNUSED)
-{
-   if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
-   return key1[0] - key2[0];
-}
-
-static int
-_eina_file_map_key_hash(const unsigned long int *key, int key_length 
EINA_UNUSED)
-{
-   return eina_hash_int64(&key[0], sizeof (unsigned long int))
-     ^ eina_hash_int64(&key[1], sizeof (unsigned long int));
-}
-
 #ifndef MAP_POPULATE
 static unsigned int
 _eina_file_map_populate(char *map, unsigned int size, Eina_Bool hugetlb)
@@ -880,9 +859,9 @@ eina_file_open(const char *path, Eina_Bool shared)
         memset(n, 0, sizeof(Eina_File));
         n->filename = (char*) (n + 1);
         strcpy((char*) n->filename, filename);
-        n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length),
-                               EINA_KEY_CMP(_eina_file_map_key_cmp),
-                               EINA_KEY_HASH(_eina_file_map_key_hash),
+        n->map = eina_hash_new(EINA_KEY_LENGTH(eina_file_map_key_length),
+                               EINA_KEY_CMP(eina_file_map_key_cmp),
+                               EINA_KEY_HASH(eina_file_map_key_hash),
                                EINA_FREE_CB(_eina_file_map_close),
                                3);
         n->rmap = eina_hash_pointer_new(NULL);
@@ -931,7 +910,9 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
 
-// bsd people will lack this feature
+   if (file->virtual) return eina_file_virtual_map_all(file);
+
+   // bsd people will lack this feature
 #ifdef MAP_POPULATE
    if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
 #endif
@@ -984,6 +965,9 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
    if (offset == 0 && length == file->length)
      return eina_file_map_all(file, rule);
 
+   if (file->virtual)
+     return eina_file_virtual_map_new(file, offset, length);
+
    key[0] = offset;
    key[1] = length;
 
@@ -1048,6 +1032,9 @@ eina_file_map_free(Eina_File *file, void *map)
 {
    EINA_SAFETY_ON_NULL_RETURN(file);
 
+   if (file->virtual)
+     return eina_file_virtual_map_free(file, map);
+
    eina_lock_take(&file->lock);
 
    if (file->global_map == map)
@@ -1104,6 +1091,8 @@ eina_file_map_faulted(Eina_File *file, void *map)
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
 
+   if (file->virtual) return EINA_FALSE;
+
    eina_lock_take(&file->lock);
 
    if (file->global_map == map)
@@ -1126,6 +1115,8 @@ eina_file_xattr_get(Eina_File *file)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
 
+   if (file->virtual) return NULL;
+
    return eina_xattr_fd_ls(file->fd);
 }
 
@@ -1134,6 +1125,8 @@ eina_file_xattr_value_get(Eina_File *file)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
 
+   if (file->virtual) return NULL;
+
    return eina_xattr_value_fd_ls(file->fd);
 }
 
diff --git a/src/lib/eina/eina_file.h b/src/lib/eina/eina_file.h
index 265f4bd..36aac58 100644
--- a/src/lib/eina/eina_file.h
+++ b/src/lib/eina/eina_file.h
@@ -444,8 +444,6 @@ typedef enum {
  */
 EAPI Eina_Bool eina_file_copy(const char *src, const char *dst, 
Eina_File_Copy_Flags flags, Eina_File_Copy_Progress cb, const void *cb_data) 
EINA_ARG_NONNULL(1, 2);
 
-
-
 /**
  * @brief Get a read-only handler to a file.
  *
@@ -462,6 +460,30 @@ EAPI Eina_Bool eina_file_copy(const char *src, const char 
*dst, Eina_File_Copy_F
 EAPI Eina_File *eina_file_open(const char *name, Eina_Bool shared) 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
 
 /**
+ * @brief Create a virtual file from a memory pointer.
+ *
+ * @param data The memory pointer to take data from
+ * @param length The length of the data in memory
+ * @param copy #EINA_TRUE if the data must be copied
+ * @return Eina_File handle to the file
+ *
+ * @since 1.8
+ */
+EAPI Eina_File *
+eina_file_virtualize(const void *data, unsigned long long length, Eina_Bool 
copy) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Tell if a file is a real file or only exist in memory
+ *
+ * @param file The file to test
+ * @return #EINA_TRUE if the file is a virtual file
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool
+eina_file_virtual(Eina_File *file) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
  * @brief Dup a read-only handler of a previously open file.
  *
  * @param file To duplicate a reference to
diff --git a/src/lib/eina/eina_file_common.c b/src/lib/eina/eina_file_common.c
index f52b39f..75c9256 100644
--- a/src/lib/eina/eina_file_common.c
+++ b/src/lib/eina/eina_file_common.c
@@ -129,6 +129,116 @@ _eina_file_escape(char *path, size_t len)
    return result;
 }
 
+
+unsigned int
+eina_file_map_key_length(const void *key EINA_UNUSED)
+{
+   return sizeof (unsigned long int) * 2;
+}
+
+int
+eina_file_map_key_cmp(const unsigned long int *key1, int key1_length 
EINA_UNUSED,
+                       const unsigned long int *key2, int key2_length 
EINA_UNUSED)
+{
+   if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
+   return key1[0] - key2[0];
+}
+
+int
+eina_file_map_key_hash(const unsigned long int *key, int key_length 
EINA_UNUSED)
+{
+   return eina_hash_int64(&key[0], sizeof (unsigned long int))
+     ^ eina_hash_int64(&key[1], sizeof (unsigned long int));
+}
+
+void *
+eina_file_virtual_map_all(Eina_File *file)
+{
+   eina_lock_take(&file->lock);
+   file->global_refcount++;
+   eina_lock_release(&file->lock);
+
+   return file->global_map;
+}
+
+void *
+eina_file_virtual_map_new(Eina_File *file,
+                          unsigned long int offset, unsigned long int length)
+{
+   Eina_File_Map *map;
+   unsigned long int key[2];
+
+   // offset and length has already been checked by the caller function
+
+   key[0] = offset;
+   key[1] = length;
+
+   eina_lock_take(&file->lock);
+
+   map = eina_hash_find(file->map, &key);
+   if (!map)
+     {
+        map = malloc(sizeof (Eina_File_Map));
+        goto on_error;
+
+        map->map = ((char*) file->global_map) + offset;
+        map->offset = offset;
+        map->length = length;
+        map->refcount = 0;
+
+        eina_hash_add(file->map, &key, map);
+        eina_hash_direct_add(file->rmap, map->map, map);
+     }
+
+   map->refcount++;
+
+ on_error:
+   eina_lock_release(&file->lock);
+   return map ? map->map : NULL;
+}
+
+void
+eina_file_virtual_map_free(Eina_File *file, void *map)
+{
+   Eina_File_Map *em;
+
+   eina_lock_take(&file->lock);
+
+   // map could equal global_map even if length != file->length
+   em = eina_hash_find(file->rmap, &map);
+   if (em)
+     {
+        unsigned long int key[2];
+
+        em->refcount--;
+
+        if (em->refcount > 0) goto on_exit;
+
+        key[0] = em->offset;
+        key[1] = em->length;
+
+        eina_hash_del(file->rmap, &map, em);
+        eina_hash_del(file->map, &key, em);
+     }
+   else
+     {
+        if (file->global_map == map)
+          {
+             file->global_refcount--;
+          }
+     }
+
+ on_exit:
+   eina_lock_release(&file->lock);
+}
+
+// Private to this file API
+static void
+_eina_file_map_close(Eina_File_Map *map)
+{
+   free(map);
+}
+
 // Global API
 
 EAPI char *
@@ -153,9 +263,70 @@ eina_file_path_sanitize(const char *path)
 }
 
 EAPI Eina_File *
+eina_file_virtualize(const void *data, unsigned long long length, Eina_Bool 
copy)
+{
+   Eina_File *file;
+   Eina_Nano_Time tp;
+   long int ti;
+   const char *tmpname = "/dev/mem/virtual\\/%16x";
+
+   // Generate an almost uniq filename based on current nsec time.
+   if (_eina_time_get(&tp)) return NULL;
+   ti = _eina_time_convert(&tp);
+
+   file = malloc(sizeof (Eina_File) +
+                 strlen(tmpname) + 17 +
+                 (copy ? length : 0));
+   if (!file) return NULL;
+
+   memset(file, 0, sizeof(Eina_File));
+   file->filename = (char*) (file + 1);
+   sprintf((char*) file->filename, tmpname, ti);
+
+   eina_lock_new(&file->lock);
+   file->mtime = ti / 1000;
+   file->length = length;
+   file->mtime_nsec = ti;
+   file->refcount = 1;
+   file->fd = -1;
+   file->virtual = EINA_TRUE;
+   file->map = eina_hash_new(EINA_KEY_LENGTH(eina_file_map_key_length),
+                             EINA_KEY_CMP(eina_file_map_key_cmp),
+                             EINA_KEY_HASH(eina_file_map_key_hash),
+                             EINA_FREE_CB(_eina_file_map_close),
+                             3);
+   file->rmap = eina_hash_pointer_new(NULL);
+
+   if (copy)
+     {
+        file->global_map = (void*)(file->filename +
+                                   strlen(file->filename) + 1);
+        memcpy((char*) file->global_map, data, length);
+     }
+   else
+     {
+        file->global_map = (void*) data;
+     }
+
+   return file;
+}
+
+EAPI Eina_Bool
+eina_file_virtual(Eina_File *file)
+{
+   if (file) return file->virtual;
+   return EINA_FALSE;
+}
+
+EAPI Eina_File *
 eina_file_dup(Eina_File *file)
 {
-   if (file) file->refcount++;
+   if (file)
+     {
+        eina_lock_take(&file->lock);
+        file->refcount++;
+        eina_lock_release(&file->lock);
+     }
    return file;
 }
 
diff --git a/src/lib/eina/eina_file_common.h b/src/lib/eina/eina_file_common.h
index 3d56f7b..31f6b6d 100644
--- a/src/lib/eina/eina_file_common.h
+++ b/src/lib/eina/eina_file_common.h
@@ -61,6 +61,7 @@ struct _Eina_File
    Eina_Bool shared : 1;
    Eina_Bool delete_me : 1;
    Eina_Bool global_faulty : 1;
+   Eina_Bool virtual : 1;
 };
 
 struct _Eina_File_Map
@@ -123,4 +124,16 @@ extern Eina_Hash *_eina_file_cache;
 extern Eina_Lock _eina_file_lock_cache;
 extern int _eina_file_log_dom;
 
+// Common function to handle virtual file
+void *eina_file_virtual_map_all(Eina_File *file);
+void *eina_file_virtual_map_new(Eina_File *file,
+                                unsigned long int offset, unsigned long int 
length);
+void eina_file_virtual_map_free(Eina_File *file, void *map);
+
+// Common hash function
+unsigned int eina_file_map_key_length(const void *key);
+int eina_file_map_key_cmp(const unsigned long int *key1, int key1_length,
+                          const unsigned long int *key2, int key2_length);
+int eina_file_map_key_hash(const unsigned long int *key, int key_length);
+
 #endif /* EINA_FILE_COMMON_H_ */
diff --git a/src/lib/eina/eina_file_win32.c b/src/lib/eina/eina_file_win32.c
index e795f60..d96720b 100644
--- a/src/lib/eina/eina_file_win32.c
+++ b/src/lib/eina/eina_file_win32.c
@@ -384,27 +384,6 @@ _eina_file_map_close(Eina_File_Map *map)
    free(map);
 }
 
-static unsigned int
-_eina_file_map_key_length(const void *key EINA_UNUSED)
-{
-   return sizeof (unsigned long int) * 2;
-}
-
-static int
-_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length 
EINA_UNUSED,
-                       const unsigned long int *key2, int key2_length 
EINA_UNUSED)
-{
-   if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
-   return key1[0] - key2[0];
-}
-
-static int
-_eina_file_map_key_hash(const unsigned long int *key, int key_length 
EINA_UNUSED)
-{
-   return eina_hash_int64(&key[0], sizeof (unsigned long int))
-     ^ eina_hash_int64(&key[1], sizeof (unsigned long int));
-}
-
 /**
  * @endcond
  */
@@ -804,9 +783,9 @@ eina_file_open(const char *path, Eina_Bool shared)
         memset(n, 0, sizeof(Eina_File));
         n->filename = (char*) (n + 1);
         strcpy((char*) n->filename, filename);
-        n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length),
-                               EINA_KEY_CMP(_eina_file_map_key_cmp),
-                               EINA_KEY_HASH(_eina_file_map_key_hash),
+        n->map = eina_hash_new(EINA_KEY_LENGTH(eina_file_map_key_length),
+                               EINA_KEY_CMP(eina_file_map_key_cmp),
+                               EINA_KEY_HASH(eina_file_map_key_hash),
                                EINA_FREE_CB(_eina_file_map_close),
                                3);
         n->rmap = eina_hash_pointer_new(NULL);
@@ -859,6 +838,8 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule 
EINA_UNUSED)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
 
+   if (file->virtual) return eina_file_virtual_map_all(file);
+
    eina_lock_take(&file->lock);
    if (file->global_map == MAP_FAILED)
      {
@@ -875,6 +856,7 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule 
EINA_UNUSED)
    if (file->global_map != MAP_FAILED)
      {
         file->global_refcount++;
+       eina_lock_release(&file->lock);
         return file->global_map;
      }
 
@@ -899,6 +881,9 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
    if (offset == 0 && length == file->length)
      return eina_file_map_all(file, rule);
 
+   if (file->virtual)
+     return eina_file_virtual_map_new(file, offset, length);
+
    key[0] = offset;
    key[1] = length;
 
@@ -952,6 +937,9 @@ eina_file_map_free(Eina_File *file, void *map)
 {
    EINA_SAFETY_ON_NULL_RETURN(file);
 
+   if (file->virtual)
+     return eina_file_virtual_map_free(file, map);
+
    eina_lock_take(&file->lock);
 
    if (file->global_map == map)
@@ -989,6 +977,7 @@ eina_file_map_free(Eina_File *file, void *map)
 EAPI Eina_Bool
 eina_file_map_faulted(Eina_File *file, void *map)
 {
+  if (file->virtual) return EINA_FALSE;
   /*
    * FIXME:
    * vc++ : 
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366801%28v=vs.85%29.aspx

-- 

------------------------------------------------------------------------------
Get your SQL database under version control now!
Version control is standard for application code, but databases havent 
caught up. So what steps can you take to put your SQL databases under 
version control? Why should you start doing it? Read more to find out.
http://pubads.g.doubleclick.net/gampad/clk?id=49501711&iu=/4140/ostg.clktrk

Reply via email to