evas/cserve2: Use Shared_Array storage for File_Data

File_Entry and File_Data are now two different types,
one being stored in the shared array, the other one
is only a reference counting entry.
This commit is contained in:
Jean-Philippe Andre 2013-07-22 16:28:42 +09:00
parent c57a319df3
commit acae35b4d1
2 changed files with 310 additions and 152 deletions

View File

@ -14,20 +14,15 @@
#include <Evas_Loader.h> #include <Evas_Loader.h>
// For testing purposes only.
#define EXPERIMENTAL_SHARED_INDEX 0
#if EXPERIMENTAL_SHARED_INDEX
typedef int string_t; typedef int string_t;
#else #define ENTRY Entry base
#define cserve2_shared_string_get(str) (str) #define ASENTRY(a) (&(a->base))
#define cserve2_shared_string_del(str) (eina_stringshare_del(str)) #define SHMOBJECT unsigned int id; unsigned int refcount
#define cserve2_shared_string_add(str) (eina_stringshare_add(str))
#define cserve2_shared_string_ref(str) (eina_stringshare_ref(str))
typedef Eina_Stringshare* string_t;
#endif
typedef struct _Entry Entry; typedef struct _Entry Entry;
typedef struct _Shm_Object Shm_Object;
typedef struct _Reference Reference; typedef struct _Reference Reference;
typedef struct _File_Entry File_Entry;
typedef struct _File_Data File_Data; typedef struct _File_Data File_Data;
typedef struct _Image_Data Image_Data; typedef struct _Image_Data Image_Data;
typedef struct _File_Watch File_Watch; typedef struct _File_Watch File_Watch;
@ -55,8 +50,19 @@ struct _Entry {
#endif #endif
}; };
struct _Shm_Object
{
SHMOBJECT;
};
struct _File_Entry {
ENTRY;
File_Watch *watcher;
Eina_List *images;
};
struct _File_Data { struct _File_Data {
Entry base; SHMOBJECT;
string_t path; string_t path;
string_t key; string_t key;
string_t loader_data; string_t loader_data;
@ -64,8 +70,6 @@ struct _File_Data {
int frame_count; int frame_count;
int loop_count; int loop_count;
int loop_hint; int loop_hint;
File_Watch *watcher;
Eina_List *images;
Eina_Bool alpha : 1; Eina_Bool alpha : 1;
Eina_Bool invalid : 1; Eina_Bool invalid : 1;
}; };
@ -74,7 +78,6 @@ struct _File_Data {
struct _Image_Data { struct _Image_Data {
Entry base; Entry base;
unsigned int file_id; unsigned int file_id;
File_Data *file;
Evas_Image_Load_Opts opts; Evas_Image_Load_Opts opts;
Shm_Handle *shm; Shm_Handle *shm;
Eina_Bool alpha_sparse : 1; Eina_Bool alpha_sparse : 1;
@ -172,6 +175,8 @@ struct _File_Watch {
}; };
static unsigned int _entry_id = 0; static unsigned int _entry_id = 0;
static Shared_Array *_file_data_array = NULL;
static Eina_Hash *file_ids = NULL; // maps path + key --> file_id static Eina_Hash *file_ids = NULL; // maps path + key --> file_id
static Eina_Hash *file_entries = NULL; // maps file_id --> entry static Eina_Hash *file_entries = NULL; // maps file_id --> entry
@ -235,6 +240,54 @@ _entry_load_reused(Entry *e)
#endif #endif
} }
static int
_shm_object_id_find_cb(const void *data1, const void *data2)
{
const Shm_Object *obj;
unsigned int key;
if (data1 == data2) return 0;
if (!data1) return 1;
if (!data2) return -1;
obj = data1;
key = *((unsigned int *) data2);
if (obj->id == key) return 0;
if (obj->id < key)
return -1;
else
return +1;
}
static inline File_Data *
_file_data_find(unsigned int file_id)
{
File_Data *fd;
fd = cserve2_shared_array_item_data_find(_file_data_array, &file_id,
_shm_object_id_find_cb);
if (fd && !fd->refcount)
{
ERR("Can not access object %u with refcount 0", file_id);
return NULL;
}
return fd;
}
static inline File_Entry *
_file_entry_find(unsigned int entry_id)
{
Entry *e;
e = (Entry *) eina_hash_find(file_entries, &entry_id);
if (!e || e->type != CSERVE2_IMAGE_FILE)
return NULL;
return (File_Entry *) e;
}
static Msg_Opened * static Msg_Opened *
_image_opened_msg_create(File_Data *fd, int *size) _image_opened_msg_create(File_Data *fd, int *size)
{ {
@ -260,7 +313,7 @@ _image_opened_send(Client *client, File_Data *fd, unsigned int rid)
int size; int size;
Msg_Opened *msg; Msg_Opened *msg;
DBG("Sending OPENED reply for entry: %d and RID: %d.", fd->base.id, rid); DBG("Sending OPENED reply for entry: %d and RID: %d.", fd->id, rid);
// clear the struct with possible paddings, since it is not aligned. // clear the struct with possible paddings, since it is not aligned.
msg = _image_opened_msg_create(fd, &size); msg = _image_opened_msg_create(fd, &size);
@ -334,12 +387,20 @@ _font_loaded_send(Client *client, unsigned int rid)
} }
static void * static void *
_open_request_build(File_Data *fd, int *bufsize) _open_request_build(Entry *entry, int *bufsize)
{ {
const char *loader_data; const char *loader_data;
char *buf; char *buf;
int size, pathlen, keylen, loaderlen; int size, pathlen, keylen, loaderlen;
Slave_Msg_Image_Open msg; Slave_Msg_Image_Open msg;
File_Data *fd;
fd = _file_data_find(entry->id);
if (!fd)
{
ERR("Could not find file data for entry %u", entry->id);
return NULL;
}
pathlen = strlen(cserve2_shared_string_get(fd->path)) + 1; pathlen = strlen(cserve2_shared_string_get(fd->path)) + 1;
keylen = strlen(cserve2_shared_string_get(fd->key)) + 1; keylen = strlen(cserve2_shared_string_get(fd->key)) + 1;
@ -361,7 +422,7 @@ _open_request_build(File_Data *fd, int *bufsize)
*bufsize = size; *bufsize = size;
_entry_load_start(&fd->base); _entry_load_start(entry);
return buf; return buf;
} }
@ -373,11 +434,19 @@ _request_free(void *msg, void *data EINA_UNUSED)
} }
static Msg_Opened * static Msg_Opened *
_open_request_response(File_Data *fd, Slave_Msg_Image_Opened *resp, int *size) _open_request_response(Entry *entry, Slave_Msg_Image_Opened *resp, int *size)
{ {
_entry_load_finish(&fd->base); File_Data *fd;
fd->base.request = NULL; _entry_load_finish(entry);
entry->request = NULL;
fd = _file_data_find(entry->id);
if (!fd)
{
ERR("Could not find file data for entry %u", entry->id);
return NULL;
}
fd->w = resp->w; fd->w = resp->w;
fd->h = resp->h; fd->h = resp->h;
@ -436,18 +505,26 @@ _load_request_build(Image_Data *i, int *bufsize)
int size; int size;
int shmlen, filelen, keylen, loaderlen; int shmlen, filelen, keylen, loaderlen;
Slave_Msg_Image_Load msg; Slave_Msg_Image_Load msg;
File_Data *fd;
fd = _file_data_find(i->file_id);
if (!fd)
{
ERR("Could not find file data %u for image %u", i->file_id, i->base.id);
return NULL;
}
// opening shm for this file // opening shm for this file
i->shm = cserve2_shm_request("img", i->file->w * i->file->h * 4); i->shm = cserve2_shm_request("img", fd->w * fd->h * 4);
if (!i->shm) if (!i->shm)
return NULL; return NULL;
shmpath = cserve2_shm_name_get(i->shm); shmpath = cserve2_shm_name_get(i->shm);
shmlen = strlen(shmpath) + 1; shmlen = strlen(shmpath) + 1;
filelen = strlen(cserve2_shared_string_get(i->file->path)) + 1; filelen = strlen(cserve2_shared_string_get(fd->path)) + 1;
keylen = strlen(cserve2_shared_string_get(i->file->key)) + 1; keylen = strlen(cserve2_shared_string_get(fd->key)) + 1;
loader_data = cserve2_shared_string_get(i->file->loader_data); loader_data = cserve2_shared_string_get(fd->loader_data);
if (loader_data) if (loader_data)
loaderlen = strlen(loader_data) + 1; loaderlen = strlen(loader_data) + 1;
else else
@ -458,9 +535,9 @@ _load_request_build(Image_Data *i, int *bufsize)
if (!buf) return NULL; if (!buf) return NULL;
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
msg.w = i->file->w; msg.w = fd->w;
msg.h = i->file->h; msg.h = fd->h;
msg.alpha = i->file->alpha; msg.alpha = fd->alpha;
// NOTE: Not passing scale_load options // NOTE: Not passing scale_load options
msg.opts.w = i->opts.w; msg.opts.w = i->opts.w;
@ -483,11 +560,11 @@ _load_request_build(Image_Data *i, int *bufsize)
memcpy(ptr, shmpath, shmlen); memcpy(ptr, shmpath, shmlen);
ptr += shmlen; ptr += shmlen;
memcpy(ptr, cserve2_shared_string_get(i->file->path), filelen); memcpy(ptr, cserve2_shared_string_get(fd->path), filelen);
ptr += filelen; ptr += filelen;
memcpy(ptr, cserve2_shared_string_get(i->file->key), keylen); memcpy(ptr, cserve2_shared_string_get(fd->key), keylen);
ptr += keylen; ptr += keylen;
if (loaderlen > 0) memcpy(ptr, cserve2_shared_string_get(i->file->loader_data), loaderlen); if (loaderlen > 0) memcpy(ptr, cserve2_shared_string_get(fd->loader_data), loaderlen);
*bufsize = size; *bufsize = size;
@ -509,6 +586,15 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
{ {
char *scale_map, *orig_map; char *scale_map, *orig_map;
void *src_data, *dst_data; void *src_data, *dst_data;
File_Data *fd;
fd = _file_data_find(entry->file_id);
if (!fd)
{
ERR("Could not find file data %u for image %u",
entry->file_id, entry->base.id);
return -1;
}
scale_map = cserve2_shm_map(scale_shm); scale_map = cserve2_shm_map(scale_shm);
if (scale_map == MAP_FAILED) if (scale_map == MAP_FAILED)
@ -540,7 +626,7 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
entry->opts.scale_load.src_w, entry->opts.scale_load.src_h, entry->opts.scale_load.src_w, entry->opts.scale_load.src_h,
0, 0, 0, 0,
entry->opts.scale_load.dst_w, entry->opts.scale_load.dst_h, entry->opts.scale_load.dst_w, entry->opts.scale_load.dst_h,
entry->file->alpha, entry->opts.scale_load.smooth); fd->alpha, entry->opts.scale_load.smooth);
cserve2_shm_unmap(original->shm); cserve2_shm_unmap(original->shm);
cserve2_shm_unmap(scale_shm); cserve2_shm_unmap(scale_shm);
@ -572,9 +658,6 @@ _scaling_prepare_and_do(Image_Data *orig)
static Msg_Loaded * static Msg_Loaded *
_load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp, int *size) _load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp, int *size)
{ {
const char *path = cserve2_shared_string_get(e->file->path);
const char *key = cserve2_shared_string_get(e->file->key);
_entry_load_finish(&e->base); _entry_load_finish(&e->base);
e->base.request = NULL; e->base.request = NULL;
@ -586,17 +669,15 @@ _load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp, int *size)
if (_scaling_needed(e, resp)) if (_scaling_needed(e, resp))
{ {
DBG("About to scale down image '%s%s'", path, key); DBG("About to scale down image %u", ASENTRY(e)->id);
if (!_scaling_prepare_and_do(e)) if (!_scaling_prepare_and_do(e))
DBG("Image '%s:%s' has been scaled down.", DBG("Image %u has been scaled down.", ASENTRY(e)->id);
path, key);
else else
ERR("Failed to scale down image '%s%s'", ERR("Failed to scale down image %u", ASENTRY(e)->id);
path, key);
} }
else else
DBG("No scaling needed for image '%s%s'", path, key); DBG("No scaling needed for image %u", ASENTRY(e)->id);
return _image_loaded_msg_create(e, size); return _image_loaded_msg_create(e, size);
} }
@ -652,9 +733,11 @@ _file_id_free(File_Data *fd)
char buf[4096]; char buf[4096];
DBG("Removing entry file id: %d, file: \"%s:%s\"", DBG("Removing entry file id: %d, file: \"%s:%s\"",
fd->base.id, cserve2_shared_string_get(fd->path), cserve2_shared_string_get(fd->key)); fd->id, cserve2_shared_string_get(fd->path),
cserve2_shared_string_get(fd->key));
snprintf(buf, sizeof(buf), "%s:%s", snprintf(buf, sizeof(buf), "%s:%s",
cserve2_shared_string_get(fd->path), cserve2_shared_string_get(fd->key)); cserve2_shared_string_get(fd->path),
cserve2_shared_string_get(fd->key));
eina_hash_del_by_key(file_ids, buf); eina_hash_del_by_key(file_ids, buf);
} }
@ -672,7 +755,8 @@ _image_id_free(Image_Data *entry)
static void static void
_image_entry_free(Image_Data *entry) _image_entry_free(Image_Data *entry)
{ {
File_Data *fd = entry->file; File_Data *fd;
File_Entry *fentry;
if (entry->base.request) if (entry->base.request)
cserve2_request_cancel_all(entry->base.request, CSERVE2_REQUEST_CANCEL); cserve2_request_cancel_all(entry->base.request, CSERVE2_REQUEST_CANCEL);
@ -683,12 +767,17 @@ _image_entry_free(Image_Data *entry)
unused_mem_usage -= _image_entry_size_get(entry); unused_mem_usage -= _image_entry_size_get(entry);
} }
fd = _file_data_find(entry->file_id);
if (fd) if (fd)
{ {
fd->images = eina_list_remove(fd->images, entry); fentry = _file_entry_find(fd->id);
if (!fd->images && !fd->base.references) fentry->images = eina_list_remove(fentry->images, entry);
eina_hash_del_by_key(file_entries, &fd->base.id); if (fentry && !fentry->images && !ASENTRY(fentry)->references)
eina_hash_del_by_key(file_entries, &fd->id);
} }
else
ERR("Could not find file data %u for image %u",
entry->file_id, ASENTRY(entry)->id);
if (entry->shm) if (entry->shm)
cserve2_shm_unref(entry->shm); cserve2_shm_unref(entry->shm);
free(entry); free(entry);
@ -704,44 +793,60 @@ _hash_image_entry_free(void *data)
} }
static void static void
_file_entry_free(File_Data *fd) _file_entry_free(File_Entry *fentry)
{ {
File_Watch *fw; File_Watch *fw;
if (!fentry) return;
// Should we call free for each of the images too? // Should we call free for each of the images too?
// If everything goes fine, it's not necessary. // If everything goes fine, it's not necessary.
if (fd->images)
if (fentry->images)
{ {
ERR("Freeing file %d (\"%s:%s\") image data still referenced.", ERR("Freeing file %u image data still referenced.", ASENTRY(fentry)->id);
fd->base.id, cserve2_shared_string_get(fd->path), cserve2_shared_string_get(fd->key)); eina_list_free(fentry->images);
eina_list_free(fd->images);
} }
if (ASENTRY(fentry)->request)
cserve2_request_cancel_all(ASENTRY(fentry)->request,
CSERVE2_REQUEST_CANCEL);
if (fd->base.request) if ((fw = fentry->watcher))
cserve2_request_cancel_all(fd->base.request, CSERVE2_REQUEST_CANCEL);
if ((fw = fd->watcher))
{ {
fw->entries = eina_list_remove(fw->entries, fd); fw->entries = eina_list_remove(fw->entries, fentry);
if (!fw->entries) if (!fw->entries)
eina_hash_del_by_key(file_watch, fw->path); eina_hash_del_by_key(file_watch, fw->path);
} }
cserve2_shared_string_del(fd->key); free(fentry);
cserve2_shared_string_del(fd->path); }
cserve2_shared_string_del(fd->loader_data);
free(fd); static void
_file_data_free(File_Data *fd)
{
if (!fd) return;
if (!fd->refcount) return;
if (--fd->refcount == 0)
{
cserve2_shared_string_del(fd->key);
cserve2_shared_string_del(fd->path);
cserve2_shared_string_del(fd->loader_data);
memset((char *) fd + sizeof(fd->id), 0, sizeof(*fd) - sizeof(fd->id));
}
} }
static void static void
_hash_file_entry_free(void *data) _hash_file_entry_free(void *data)
{ {
File_Data *fd = data; File_Entry *fentry = data;
File_Data *fd;
// TODO: Add some checks to make sure that we are freeing an // TODO: Add some checks to make sure that we are freeing an
// unused entry. // unused entry.
fd = _file_data_find(ASENTRY(fentry)->id);
_file_id_free(fd); _file_id_free(fd);
_file_entry_free(fd); _file_entry_free(fentry);
_file_data_free(fd);
} }
static void static void
@ -904,6 +1009,8 @@ cserve2_cache_init(void)
EINA_KEY_HASH(_font_entry_key_hash), EINA_KEY_HASH(_font_entry_key_hash),
EINA_FREE_CB(_font_entry_free), EINA_FREE_CB(_font_entry_free),
5); 5);
_file_data_array = cserve2_shared_array_new(1, sizeof(File_Data), 0);
} }
void void
@ -922,6 +1029,8 @@ cserve2_cache_shutdown(void)
eina_hash_free(font_entries); eina_hash_free(font_entries);
eina_hash_free(font_sources); eina_hash_free(font_sources);
cserve2_shared_array_del(_file_data_array);
} }
static Reference * static Reference *
@ -983,22 +1092,32 @@ _entry_reference_del(Entry *entry, Reference *ref)
if (entry->type == CSERVE2_IMAGE_FILE) if (entry->type == CSERVE2_IMAGE_FILE)
{ {
File_Data *fd = (File_Data *)entry; File_Entry *fentry = (File_Entry *) entry;
File_Data *fd = _file_data_find(entry->id);
if (fd->invalid) if (fd)
_file_entry_free(fd); {
else if (!fd->images) if (fd->invalid)
eina_hash_del_by_key(file_entries, &entry->id); {
_file_entry_free(fentry);
_file_data_free(fd);
}
else if (!fentry->images)
eina_hash_del_by_key(file_entries, &entry->id);
}
else
ERR("File data not found for id %u", entry->id);
/* don't free file entries that have images attached to it, they will /* don't free file entries that have images attached to it, they will
* be freed when the last unused image is freed */ * be freed when the last unused image is freed */
} }
else if (entry->type == CSERVE2_IMAGE_DATA) else if (entry->type == CSERVE2_IMAGE_DATA)
{ {
Image_Data *ientry = (Image_Data *)entry; Image_Data *ientry = (Image_Data *) entry;
File_Data *fd = _file_data_find(entry->id);
if (!ientry->file) if (!fd)
eina_hash_del_by_key(image_entries, &entry->id); eina_hash_del_by_key(image_entries, &entry->id);
else if (ientry->file->invalid) else if (fd->invalid)
_image_entry_free(ientry); _image_entry_free(ientry);
else else
_entry_unused_push(ientry); _entry_unused_push(ientry);
@ -1090,22 +1209,24 @@ cserve2_cache_client_del(Client *client)
static Image_Data * static Image_Data *
_image_entry_new(Client *client, int rid, _image_entry_new(Client *client, int rid,
unsigned int file_id, unsigned int image_id, unsigned int client_file_id, unsigned int image_id,
Evas_Image_Load_Opts *opts) Evas_Image_Load_Opts *opts)
{ {
Reference *ref; Reference *ref;
Image_Data *im_entry; Image_Data *im_entry;
File_Data *fd;
ref = eina_hash_find(client->files.referencing, &file_id); ref = eina_hash_find(client->files.referencing, &client_file_id);
if (!ref) if (!ref)
{ {
ERR("Couldn't find file id: %d, for image id: %d", ERR("Couldn't find file id: %d, for image id: %d",
file_id, image_id); client_file_id, image_id);
cserve2_client_error_send(client, rid, cserve2_client_error_send(client, rid,
CSERVE2_INVALID_CACHE); CSERVE2_INVALID_CACHE);
return NULL; return NULL;
} }
if (((File_Data *)ref->entry)->invalid) fd = _file_data_find(ref->entry->id);
if (!fd || fd->invalid)
{ {
cserve2_client_error_send(client, rid, cserve2_client_error_send(client, rid,
CSERVE2_FILE_CHANGED); CSERVE2_FILE_CHANGED);
@ -1115,7 +1236,6 @@ _image_entry_new(Client *client, int rid,
im_entry = calloc(1, sizeof(*im_entry)); im_entry = calloc(1, sizeof(*im_entry));
im_entry->base.type = CSERVE2_IMAGE_DATA; im_entry->base.type = CSERVE2_IMAGE_DATA;
im_entry->file_id = ref->entry->id; im_entry->file_id = ref->entry->id;
im_entry->file = (File_Data *)ref->entry;
if (opts) if (opts)
{ {
im_entry->opts.dpi = opts->dpi; im_entry->opts.dpi = opts->dpi;
@ -1152,11 +1272,19 @@ _file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, vo
{ {
Eina_List *ll; Eina_List *ll;
Image_Data *ie; Image_Data *ie;
File_Entry *fentry;
fd->invalid = EINA_TRUE; fd->invalid = EINA_TRUE;
fd->watcher = NULL; fentry = _file_entry_find(fd->id);
if (!fentry)
{
ERR("Could not find file entry for id %u", fd->id);
continue;
}
EINA_LIST_FOREACH(fd->images, ll, ie) fentry->watcher = NULL;
EINA_LIST_FOREACH(fentry->images, ll, ie)
{ {
_image_id_free(ie); _image_id_free(ie);
eina_hash_set(image_entries, &ie->base.id, NULL); eina_hash_set(image_entries, &ie->base.id, NULL);
@ -1169,12 +1297,19 @@ _file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, vo
} }
_file_id_free(fd); _file_id_free(fd);
eina_hash_set(file_entries, &fd->base.id, NULL); eina_hash_set(file_entries, &fd->id, NULL);
if (fd->base.request /*&& !fd->base.request->processing*/) if (ASENTRY(fentry)->request
cserve2_request_cancel_all(fd->base.request, CSERVE2_FILE_CHANGED); /*&& !ASENTRY(fentry)->request->processing*/)
fd->base.request = NULL; {
if (!fd->images && !fd->base.references) cserve2_request_cancel_all(ASENTRY(fentry)->request,
_file_entry_free(fd); CSERVE2_FILE_CHANGED);
ASENTRY(fentry)->request = NULL;
}
if (!fentry->images && !ASENTRY(fentry)->references)
{
_file_entry_free(fentry);
_file_data_free(fd);
}
} }
eina_hash_del_by_key(file_watch, fw->path); eina_hash_del_by_key(file_watch, fw->path);
@ -1220,8 +1355,6 @@ _font_load_request_build(void *data, int *size)
msg->rend_flags = fe->rend_flags; msg->rend_flags = fe->rend_flags;
msg->size = fe->size; msg->size = fe->size;
msg->dpi = fe->dpi; msg->dpi = fe->dpi;
#warning TODO Use shared index on client side
msg->name = cserve2_shared_string_get(fe->src->name); msg->name = cserve2_shared_string_get(fe->src->name);
msg->file = cserve2_shared_string_get(fe->src->file); msg->file = cserve2_shared_string_get(fe->src->file);
@ -1751,21 +1884,21 @@ static Eina_Bool
_image_file_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata) _image_file_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
{ {
Msg_Stats *msg = fdata; Msg_Stats *msg = fdata;
File_Data *fd = data; File_Entry *fentry = data;
// accounting numbers // accounting numbers
msg->images.files_loaded++; msg->images.files_loaded++;
// accounting size // accounting size
msg->images.files_size += sizeof(File_Data) + msg->images.files_size += sizeof(File_Data) +
eina_list_count(fd->images) * sizeof(Eina_List *) + eina_list_count(fentry->images) * sizeof(Eina_List *) +
eina_list_count(fd->base.references) * eina_list_count(ASENTRY(fentry)->references) *
(sizeof(Slave_Request *) + sizeof(Eina_List *)); (sizeof(Slave_Request *) + sizeof(Eina_List *));
#ifdef DEBUG_LOAD_TIME #ifdef DEBUG_LOAD_TIME
// accounting file entries load time // accounting file entries load time
msg->images.files_load_time += fd->base.load_time; msg->images.files_load_time += ASENTRY(fentry)->load_time;
msg->images.files_saved_time += fd->base.saved_time; msg->images.files_saved_time += ASENTRY(fentry)->saved_time;
#endif #endif
return EINA_TRUE; return EINA_TRUE;
@ -1776,7 +1909,7 @@ _image_data_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EI
{ {
Msg_Stats *msg = fdata; Msg_Stats *msg = fdata;
Image_Data *id = data; Image_Data *id = data;
unsigned int image_size; File_Data *fd;
// accounting numbers // accounting numbers
msg->images.images_loaded++; msg->images.images_loaded++;
@ -1786,9 +1919,13 @@ _image_data_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EI
msg->images.images_size += _image_entry_size_get(id) * 1024; msg->images.images_size += _image_entry_size_get(id) * 1024;
if (id->unused) msg->images.unused_size += _image_entry_size_get(id) * 1024; if (id->unused) msg->images.unused_size += _image_entry_size_get(id) * 1024;
image_size = id->file->w * id->file->h * 4; fd = _file_data_find(id->file_id);
msg->images.requested_size += if (fd)
(image_size * eina_list_count(id->base.references)); {
unsigned int image_size = fd->w * fd->h * 4;
msg->images.requested_size +=
(image_size * eina_list_count(id->base.references));
}
#ifdef DEBUG_LOAD_TIME #ifdef DEBUG_LOAD_TIME
// accounting image entries load time // accounting image entries load time
@ -2047,15 +2184,17 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id,
Reference *ref; Reference *ref;
File_Watch *fw; File_Watch *fw;
char buf[4906]; char buf[4906];
File_Entry *fentry;
int idx;
// look for this file on client references // look for this file on client references
ref = eina_hash_find(client->files.referencing, &client_file_id); ref = eina_hash_find(client->files.referencing, &client_file_id);
if (ref) if (ref)
{ {
fd = (File_Data *)ref->entry;
_entry_load_reused(ref->entry); _entry_load_reused(ref->entry);
if (fd->invalid) fd = _file_data_find(ref->entry->id);
if (!fd || fd->invalid)
{ {
cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED); cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
return -1; return -1;
@ -2065,8 +2204,8 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id,
ref->count++; ref->count++;
// File already being loaded, just add the request to be replied // File already being loaded, just add the request to be replied
if (fd->base.request) if (ref->entry->request)
cserve2_request_waiter_add(fd->base.request, rid, client); cserve2_request_waiter_add(ref->entry->request, rid, client);
else else
_image_opened_send(client, fd, rid); _image_opened_send(client, fd, rid);
return 0; return 0;
@ -2079,8 +2218,8 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id,
{ {
DBG("found file_id %u for client file id %d", DBG("found file_id %u for client file id %d",
file_id, client_file_id); file_id, client_file_id);
fd = eina_hash_find(file_entries, &file_id); fentry = _file_entry_find(file_id);
if (!fd) if (!fentry)
{ {
ERR("file \"%s\" is in file_ids hash but not in entries hash.", ERR("file \"%s\" is in file_ids hash but not in entries hash.",
buf); buf);
@ -2088,30 +2227,43 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id,
// FIXME: Maybe we should remove the entry from file_ids then? // FIXME: Maybe we should remove the entry from file_ids then?
return -1; return -1;
} }
ref = _entry_reference_add((Entry *)fd, client, client_file_id); ref = _entry_reference_add(ASENTRY(fentry), client, client_file_id);
_entry_load_reused(ref->entry); _entry_load_reused(ref->entry);
eina_hash_add(client->files.referencing, &client_file_id, ref); eina_hash_add(client->files.referencing, &client_file_id, ref);
if (fd->base.request) if (ref->entry->request)
cserve2_request_waiter_add(fd->base.request, rid, client); cserve2_request_waiter_add(ref->entry->request, rid, client);
else // File already loaded, otherwise there would be a request else // File already loaded, otherwise there would be a request
_image_opened_send(client, fd, rid); {
fd = _file_data_find(file_id);
_image_opened_send(client, fd, rid);
}
return 0; return 0;
} }
file_id = ++_entry_id; file_id = ++_entry_id;
while ((file_id == 0) || (eina_hash_find(file_entries, &file_id))) while (eina_hash_find(file_entries, &file_id))
file_id = ++_entry_id; file_id = ++_entry_id;
DBG("Creating new entry with file_id: %u for file \"%s:%s\"", idx = cserve2_shared_array_item_new(_file_data_array);
file_id, path, key); fd = cserve2_shared_array_item_data_get(_file_data_array, idx);
fd = calloc(1, sizeof(*fd)); DBG("Creating new entry with file_id: %u for file \"%s:%s\". Index %d at %p",
fd->base.type = CSERVE2_IMAGE_FILE; file_id, path, key, idx, fd);
if (!fd)
{
ERR("Could not create new file entry!");
return -1;
}
fd->id = file_id; // FIXME: write last (?)
fd->refcount = 1;
fd->path = cserve2_shared_string_add(path); fd->path = cserve2_shared_string_add(path);
fd->key = cserve2_shared_string_add(key); fd->key = cserve2_shared_string_add(key);
fd->base.id = file_id;
eina_hash_add(file_entries, &file_id, fd); fentry = calloc(1, sizeof(File_Entry));
ASENTRY(fentry)->type = CSERVE2_IMAGE_FILE;
ASENTRY(fentry)->id = file_id;
eina_hash_add(file_entries, &file_id, fentry);
eina_hash_add(file_ids, buf, (void*)(intptr_t)file_id); eina_hash_add(file_ids, buf, (void*)(intptr_t)file_id);
ref = _entry_reference_add((Entry *)fd, client, client_file_id); ref = _entry_reference_add(ASENTRY(fentry), client, client_file_id);
eina_hash_add(client->files.referencing, &client_file_id, ref); eina_hash_add(client->files.referencing, &client_file_id, ref);
fw = eina_hash_find(file_watch, cserve2_shared_string_get(fd->path)); fw = eina_hash_find(file_watch, cserve2_shared_string_get(fd->path));
@ -2122,14 +2274,12 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id,
cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw); cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw);
eina_hash_direct_add(file_watch, fw->path, fw); eina_hash_direct_add(file_watch, fw->path, fw);
} }
fw->entries = eina_list_append(fw->entries, fd); fw->entries = eina_list_append(fw->entries, fentry);
fd->watcher = fw; fentry->watcher = fw;
fd->base.request = cserve2_request_add(CSERVE2_REQ_IMAGE_OPEN, ASENTRY(fentry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_OPEN,
rid, client, NULL, &_open_funcs, rid, client, NULL,
fd); &_open_funcs, fentry);
// _open_image_default_set(fd);
return 0; return 0;
} }
@ -2163,9 +2313,9 @@ _cserve2_cache_fast_scaling_check(Client *client, Image_Data *entry)
int scaled_count = 0; int scaled_count = 0;
int dst_w, dst_h; int dst_w, dst_h;
Eina_Bool first_attempt = EINA_TRUE; Eina_Bool first_attempt = EINA_TRUE;
File_Entry *fentry;
if (!entry) return -1; if (!entry) return -1;
if (!entry->file) return -1;
dst_w = entry->opts.scale_load.dst_w; dst_w = entry->opts.scale_load.dst_w;
dst_h = entry->opts.scale_load.dst_h; dst_h = entry->opts.scale_load.dst_h;
@ -2206,7 +2356,9 @@ try_again:
goto try_again; goto try_again;
} }
iter = eina_list_iterator_new(entry->file->images); fentry = _file_entry_find(entry->file_id);
iter = eina_list_iterator_new(fentry->images);
//iter = eina_list_iterator_new(entry->file->images);
EINA_ITERATOR_FOREACH(iter, i) EINA_ITERATOR_FOREACH(iter, i)
{ {
if (i == entry) continue; if (i == entry) continue;
@ -2228,16 +2380,13 @@ try_again:
if (!original) if (!original)
{ {
DBG("Found %d scaled images for %s:%s but none matches", DBG("Found %d scaled images for image %u but none matches",
scaled_count, cserve2_shared_string_get(entry->file->path), scaled_count, entry->base.id);
cserve2_shared_string_get(entry->file->key));
if (scaled_count >= 4) if (scaled_count >= 4)
{ {
DBG("Forcing load of original image now!"); DBG("Forcing load of original image now!");
File_Data *fd;
original = _image_entry_new(client, 0, entry->file_id, original = _image_entry_new(client, 0, entry->file_id,
0, &unscaled); 0, &unscaled);
if (!original) return -1; if (!original) return -1;
@ -2252,8 +2401,8 @@ try_again:
eina_hash_add(image_ids, buf, (void *)(intptr_t)image_id); eina_hash_add(image_ids, buf, (void *)(intptr_t)image_id);
_entry_unused_push(original); _entry_unused_push(original);
fd = original->file; fentry = _file_entry_find(original->file_id);
fd->images = eina_list_append(fd->images, original); fentry->images = eina_list_append(fentry->images, original);
} }
else else
return -1; return -1;
@ -2299,8 +2448,8 @@ cserve2_cache_image_entry_create(Client *client, int rid,
Evas_Image_Load_Opts *opts) Evas_Image_Load_Opts *opts)
{ {
Image_Data *entry; Image_Data *entry;
File_Data *fd = NULL;
Reference *ref, *oldref; Reference *ref, *oldref;
File_Entry *fentry;
unsigned int image_id; unsigned int image_id;
char buf[4096]; char buf[4096];
@ -2360,8 +2509,8 @@ cserve2_cache_image_entry_create(Client *client, int rid,
eina_hash_del_by_key(client->images.referencing, &client_image_id); eina_hash_del_by_key(client->images.referencing, &client_image_id);
eina_hash_add(client->images.referencing, &client_image_id, ref); eina_hash_add(client->images.referencing, &client_image_id, ref);
fd = entry->file; fentry = _file_entry_find(entry->file_id);
fd->images = eina_list_append(fd->images, entry); fentry->images = eina_list_append(fentry->images, entry);
if (opts && opts->scale_load.dst_w && opts->scale_load.dst_h) if (opts && opts->scale_load.dst_w && opts->scale_load.dst_h)
{ {
@ -2369,9 +2518,9 @@ cserve2_cache_image_entry_create(Client *client, int rid,
return 0; return 0;
} }
entry->base.request = cserve2_request_add(CSERVE2_REQ_IMAGE_SPEC_LOAD, ASENTRY(entry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_SPEC_LOAD,
0, NULL, fd->base.request, 0, NULL, ASENTRY(fentry)->request,
&_load_funcs, entry); &_load_funcs, entry);
return 0; return 0;
} }
@ -2380,6 +2529,7 @@ cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned
{ {
Image_Data *entry; Image_Data *entry;
Reference *ref; Reference *ref;
File_Data *fd;
ref = eina_hash_find(client->images.referencing, &client_image_id); ref = eina_hash_find(client->images.referencing, &client_image_id);
if (!ref) if (!ref)
@ -2389,9 +2539,9 @@ cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned
return; return;
} }
entry = (Image_Data *)ref->entry; entry = (Image_Data *) ref->entry;
fd = _file_data_find(entry->file_id);
if (entry->file->invalid) if (!fd || fd->invalid)
{ {
cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED); cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
return; return;
@ -2409,11 +2559,14 @@ cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned
else if (entry->shm) else if (entry->shm)
_image_loaded_send(client, entry, rid); _image_loaded_send(client, entry, rid);
else else
entry->base.request = cserve2_request_add(CSERVE2_REQ_IMAGE_LOAD, {
rid, client, File_Entry *fentry = _file_entry_find(entry->file_id);
entry->file->base.request, ASENTRY(entry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_LOAD,
&_load_funcs, rid, client,
entry); ASENTRY(fentry)->request,
&_load_funcs,
entry);
}
entry->doload = EINA_TRUE; entry->doload = EINA_TRUE;
} }
@ -2423,6 +2576,7 @@ cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsign
{ {
Image_Data *entry; Image_Data *entry;
Reference *ref; Reference *ref;
File_Data *fd;
ref = eina_hash_find(client->images.referencing, &client_image_id); ref = eina_hash_find(client->images.referencing, &client_image_id);
if (!ref) if (!ref)
@ -2432,9 +2586,9 @@ cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsign
return; return;
} }
entry = (Image_Data *)ref->entry; entry = (Image_Data *) ref->entry;
fd = _file_data_find(entry->file_id);
if (entry->file->invalid) if (!fd || fd->invalid)
{ {
cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED); cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
return; return;
@ -2452,11 +2606,14 @@ cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsign
else if (entry->shm) else if (entry->shm)
_image_loaded_send(client, entry, rid); _image_loaded_send(client, entry, rid);
else else
entry->base.request = cserve2_request_add(CSERVE2_REQ_IMAGE_LOAD, {
rid, client, File_Entry *fentry = _file_entry_find(entry->file_id);
entry->file->base.request, ASENTRY(entry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_LOAD,
&_load_funcs, rid, client,
entry); ASENTRY(fentry)->request,
&_load_funcs,
entry);
}
entry->doload = EINA_TRUE; entry->doload = EINA_TRUE;
} }

View File

@ -462,7 +462,7 @@ cserve2_shared_array_item_find(Shared_Array *sa, void *data,
// TODO: Fast search in the sorted zone // TODO: Fast search in the sorted zone
ptr = sa->ds->data; ptr = sa->ds->data + sizeof(Shared_Array_Header);
// Linear search O(n) // Linear search O(n)
for (k = 0; k < sa->header->emptyidx; k++) for (k = 0; k < sa->header->emptyidx; k++)
@ -482,7 +482,8 @@ cserve2_shared_array_item_data_find(Shared_Array *sa, void *data,
int elemid; int elemid;
elemid = cserve2_shared_array_item_find(sa, data, cmp); elemid = cserve2_shared_array_item_find(sa, data, cmp);
if (elemid < 0) return NULL; if (elemid < 0)
return NULL;
return cserve2_shared_array_item_data_get(sa, elemid); return cserve2_shared_array_item_data_get(sa, elemid);
} }