[libchamplain] Introduce new memory cache and remove non-persistent file cache
- From: Jiří Techet <jiritechet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libchamplain] Introduce new memory cache and remove non-persistent file cache
- Date: Sun, 1 Aug 2010 23:16:29 +0000 (UTC)
commit 2841c81b38554bebfc8056f76db37a1c5e82cb00
Author: JiÅ?Ã Techet <techet gmail com>
Date: Sun Aug 1 13:41:14 2010 +0200
Introduce new memory cache and remove non-persistent file cache
The new memory cache can store specified number of tiles in
memory without storing them to the disk. It replaces
the temporary file cache - it was a bit scary to recursively
delete some directories and libchamplain shouldn't do things
like that.
Signed-off-by: JiÅ?Ã Techet <techet gmail com>
champlain/Makefile.am | 3 +
champlain/champlain-file-cache.c | 182 +---------
champlain/champlain-file-cache.h | 2 +-
champlain/champlain-file-tile-source.c | 2 +-
champlain/champlain-memory-cache.c | 422 ++++++++++++++++++++++++
champlain/champlain-memory-cache.h | 69 ++++
champlain/champlain-network-bbox-tile-source.c | 2 +-
champlain/champlain-network-tile-source.c | 2 +-
champlain/champlain-null-tile-source.c | 2 +-
champlain/champlain-tile-cache.c | 117 -------
champlain/champlain-tile-cache.h | 4 -
champlain/champlain.h | 1 +
demos/local-rendering.c | 3 +-
13 files changed, 519 insertions(+), 292 deletions(-)
---
diff --git a/champlain/Makefile.am b/champlain/Makefile.am
index f4142a1..9665126 100644
--- a/champlain/Makefile.am
+++ b/champlain/Makefile.am
@@ -34,6 +34,7 @@ libchamplain_headers = \
champlain-map-source-chain.h \
champlain-tile-source.h \
champlain-tile-cache.h \
+ champlain-memory-cache.h \
champlain-network-tile-source.h \
champlain-file-cache.h \
champlain-map-source-factory.h \
@@ -70,6 +71,7 @@ libchamplain_ CHAMPLAIN_API_VERSION@_la_SOURCES = \
champlain-map-source-chain.c \
champlain-tile-source.c \
champlain-tile-cache.c \
+ champlain-memory-cache.c \
champlain-network-tile-source.c \
champlain-file-cache.c \
champlain-map-source-factory.c \
@@ -101,6 +103,7 @@ libchamplain_include_HEADERS = \
champlain-map-source-chain.h \
champlain-tile-source.h \
champlain-tile-cache.h \
+ champlain-memory-cache.h \
champlain-network-tile-source.h \
champlain-file-cache.h \
champlain-map-source-factory.h \
diff --git a/champlain/champlain-file-cache.c b/champlain/champlain-file-cache.c
index 01dc84b..3aab7c7 100644
--- a/champlain/champlain-file-cache.c
+++ b/champlain/champlain-file-cache.c
@@ -22,8 +22,7 @@
* @short_description: Stores and loads cached tiles from the file system
*
* #ChamplainFileCache is a map source that stores and retrieves tiles from the
- * file system. It can be temporary (deleted when the object is destroyed) or
- * permanent. Tiles most frequently loaded gain in "popularity". This popularity
+ * file system. Tiles most frequently loaded gain in "popularity". This popularity
* is taken into account when purging the cache.
*/
@@ -55,14 +54,12 @@ struct _ChamplainFileCachePrivate
guint size_limit;
gchar *cache_dir;
- gchar *real_cache_dir;
sqlite3 *db;
sqlite3_stmt *stmt_select;
sqlite3_stmt *stmt_update;
};
static void finalize_sql (ChamplainFileCache *file_cache);
-static void delete_temp_cache (ChamplainFileCache *file_cache);
static void init_cache (ChamplainFileCache *file_cache);
static gchar *get_filename (ChamplainFileCache *file_cache,
ChamplainTile *tile);
@@ -70,7 +67,6 @@ static gboolean tile_is_expired (ChamplainFileCache *file_cache,
ChamplainTile *tile);
static void delete_tile (ChamplainFileCache *file_cache,
const gchar *filename);
-static void delete_dir_recursive (GFile *parent);
static gboolean create_cache_dir (const gchar *dir_name);
static void fill_tile (ChamplainMapSource *map_source,
@@ -84,7 +80,6 @@ static void refresh_tile_time (ChamplainTileCache *tile_cache,
ChamplainTile *tile);
static void on_tile_filled (ChamplainTileCache *tile_cache,
ChamplainTile *tile);
-static void clean (ChamplainTileCache *tile_cache);
static void
champlain_file_cache_get_property (GObject *object,
@@ -164,41 +159,16 @@ finalize_sql (ChamplainFileCache *file_cache)
}
}
-static void
-delete_temp_cache (ChamplainFileCache *file_cache)
-{
- ChamplainTileCache *tile_cache = CHAMPLAIN_TILE_CACHE(file_cache);
- ChamplainFileCachePrivate *priv = file_cache->priv;
-
- if (!champlain_tile_cache_get_persistent (tile_cache) && priv->real_cache_dir)
- {
- GFile *file = NULL;
-
- /* delete the directory contents */
- file = g_file_new_for_path (priv->real_cache_dir);
- delete_dir_recursive (file);
- /* delete the directory itself */
- if (!g_file_delete (file, NULL, NULL))
- g_warning ("Failed to remove temporary cache main directory");
-
- g_object_unref (file);
- }
-}
static void
champlain_file_cache_finalize (GObject *object)
{
ChamplainFileCache *file_cache = CHAMPLAIN_FILE_CACHE(object);
- ChamplainTileCache *tile_cache = CHAMPLAIN_TILE_CACHE(file_cache);
ChamplainFileCachePrivate *priv = file_cache->priv;
finalize_sql (file_cache);
- if (!champlain_tile_cache_get_persistent (tile_cache))
- delete_temp_cache (file_cache);
-
- g_free (priv->real_cache_dir);
g_free (priv->cache_dir);
G_OBJECT_CLASS (champlain_file_cache_parent_class)->finalize (object);
@@ -220,64 +190,18 @@ create_cache_dir (const gchar *dir_name)
return TRUE;
}
-#ifdef G_OS_WIN32
-#include <io.h>
-#include <glib/gstdio.h>
-static char *mkdtemp(char *template)
-{
- gunichar2 *wtemplate;
- gchar *tmpl;
- if (!template)
- return NULL;
- wtemplate = g_utf8_to_utf16 (template, -1, NULL, NULL, NULL);
- if (!_wmktemp (wtemplate)) {
- g_free (wtemplate);
- return NULL;
- }
- tmpl = g_utf16_to_utf8 (wtemplate, -1, NULL, NULL, NULL);
- g_free (wtemplate);
- if ((strlen (template) != strlen (tmpl)) || g_mkdir (tmpl, 0700)) {
- g_free (tmpl);
- return NULL;
- }
- strcpy (template,tmpl);
- g_free (tmpl);
- return template;
-}
-#endif
static void
init_cache (ChamplainFileCache *file_cache)
{
- ChamplainTileCache *tile_cache = CHAMPLAIN_TILE_CACHE(file_cache);
ChamplainFileCachePrivate *priv = file_cache->priv;
gchar *filename = NULL;
gchar *error_msg = NULL;
gint error;
- if (champlain_tile_cache_get_persistent (tile_cache))
- {
- priv->real_cache_dir = g_strdup (priv->cache_dir);
- g_return_if_fail (create_cache_dir (priv->real_cache_dir));
- }
- else
- {
- /* Create temporary directory for non-persistent caches */
- gchar *tmplate = NULL;
-
- tmplate = g_build_filename (priv->cache_dir, "champlain-XXXXXX", NULL);
-
- priv->real_cache_dir = mkdtemp (tmplate);
-
- if (!priv->real_cache_dir)
- {
- g_warning ("Failed to create filename for temporary cache: template '%s'", tmplate);
- g_free (tmplate);
- return;
- }
- }
+ g_return_if_fail (create_cache_dir (priv->cache_dir));
- filename = g_build_filename (priv->real_cache_dir,
+ filename = g_build_filename (priv->cache_dir,
"cache.db", NULL);
error = sqlite3_open_v2 (filename, &priv->db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
@@ -343,23 +267,17 @@ static void
champlain_file_cache_constructed (GObject *object)
{
ChamplainFileCache *file_cache = CHAMPLAIN_FILE_CACHE(object);
- ChamplainTileCache *tile_cache = CHAMPLAIN_TILE_CACHE(file_cache);
ChamplainFileCachePrivate *priv = file_cache->priv;
if (!priv->cache_dir)
{
- if (champlain_tile_cache_get_persistent (tile_cache))
- {
#ifdef CHAMPLAIN_HAS_MAEMO
- priv->cache_dir = g_strdup ("/home/user/MyDocs/.Maps/");
+ priv->cache_dir = g_strdup ("/home/user/MyDocs/.Maps/");
#else
- priv->cache_dir = g_build_path (G_DIR_SEPARATOR_S,
- g_get_user_cache_dir (),
- "champlain", NULL);
+ priv->cache_dir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_user_cache_dir (),
+ "champlain", NULL);
#endif
- }
- else
- priv->cache_dir = g_strdup (g_get_tmp_dir ());
}
init_cache (file_cache);
@@ -419,7 +337,6 @@ champlain_file_cache_class_init (ChamplainFileCacheClass *klass)
tile_cache_class->store_tile = store_tile;
tile_cache_class->refresh_tile_time = refresh_tile_time;
tile_cache_class->on_tile_filled = on_tile_filled;
- tile_cache_class->clean = clean;
map_source_class->fill_tile = fill_tile;
}
@@ -433,7 +350,7 @@ champlain_file_cache_init (ChamplainFileCache *file_cache)
priv->cache_dir = NULL;
priv->size_limit = 100000000;
- priv->real_cache_dir = NULL;
+ priv->cache_dir = NULL;
priv->db = NULL;
priv->stmt_select = NULL;
priv->stmt_update = NULL;
@@ -444,7 +361,7 @@ champlain_file_cache_init (ChamplainFileCache *file_cache)
*
* Default constructor of #ChamplainFileCache.
*
- * Returns: a constructed permanent cache of maximal size 100000000 B inside
+ * Returns: a constructed cache of maximal size 100000000 B inside
* ~/.cache/champlain.
*
* Since: 0.6
@@ -459,10 +376,7 @@ ChamplainFileCache* champlain_file_cache_new (void)
* @size_limit: maximal size of the cache in bytes
* @cache_dir: the directory where the cache is created. For temporary caches
* one more directory with random name is created inside this directory.
- * When cache_dir == NULL, a cache in ~/.cache/champlain is used for permanent
- * caches and /tmp for temporary caches.
- * @persistent: if TRUE, the cache is persistent; otherwise the cache is
- * temporary and will be deleted when the cache object is destructed.
+ * When cache_dir == NULL, a cache in ~/.cache/champlain is used.
*
* Constructor of #ChamplainFileCache.
*
@@ -471,12 +385,11 @@ ChamplainFileCache* champlain_file_cache_new (void)
* Since: 0.6
*/
ChamplainFileCache* champlain_file_cache_new_full (guint size_limit,
- const gchar *cache_dir,
- gboolean persistent)
+ const gchar *cache_dir)
{
ChamplainFileCache * cache;
cache = g_object_new (CHAMPLAIN_TYPE_FILE_CACHE, "size-limit", size_limit,
- "cache-dir", cache_dir, "persistent-cache", persistent, NULL);
+ "cache-dir", cache_dir, NULL);
return cache;
}
@@ -545,7 +458,7 @@ get_filename (ChamplainFileCache *file_cache,
g_return_val_if_fail (CHAMPLAIN_IS_FILE_CACHE (file_cache), NULL);
g_return_val_if_fail (CHAMPLAIN_IS_TILE (tile), NULL);
- g_return_val_if_fail (priv->real_cache_dir, NULL);
+ g_return_val_if_fail (priv->cache_dir, NULL);
ChamplainMapSource* map_source = CHAMPLAIN_MAP_SOURCE(file_cache);
@@ -553,7 +466,7 @@ get_filename (ChamplainFileCache *file_cache,
"%s" G_DIR_SEPARATOR_S
"%d" G_DIR_SEPARATOR_S
"%d" G_DIR_SEPARATOR_S "%d.png",
- priv->real_cache_dir,
+ priv->cache_dir,
champlain_map_source_get_id (map_source),
champlain_tile_get_zoom_level (tile),
champlain_tile_get_x (tile),
@@ -784,9 +697,7 @@ refresh_tile_time (ChamplainTileCache *tile_cache,
g_object_unref (info);
if (CHAMPLAIN_IS_TILE_CACHE(next_source))
- {
- refresh_tile_time (CHAMPLAIN_TILE_CACHE(next_source), tile);
- }
+ champlain_tile_cache_refresh_tile_time (CHAMPLAIN_TILE_CACHE(next_source), tile);
}
static void
@@ -863,7 +774,7 @@ store_tile (ChamplainTileCache *tile_cache,
store_next:
if (CHAMPLAIN_IS_TILE_CACHE(next_source))
- store_tile (CHAMPLAIN_TILE_CACHE(next_source), tile, contents, size);
+ champlain_tile_cache_store_tile (CHAMPLAIN_TILE_CACHE(next_source), tile, contents, size);
g_free (filename);
g_free (path);
@@ -906,27 +817,9 @@ on_tile_filled (ChamplainTileCache *tile_cache,
call_next:
if (CHAMPLAIN_IS_TILE_CACHE(next_source))
- on_tile_filled (CHAMPLAIN_TILE_CACHE(next_source), tile);
+ champlain_tile_cache_on_tile_filled (CHAMPLAIN_TILE_CACHE(next_source), tile);
}
-static void
-clean (ChamplainTileCache *tile_cache)
-{
- g_return_if_fail (CHAMPLAIN_IS_FILE_CACHE (tile_cache));
-
- ChamplainFileCache *file_cache = CHAMPLAIN_FILE_CACHE(tile_cache);
- ChamplainFileCachePrivate *priv = file_cache->priv;
-
- g_return_if_fail (!champlain_tile_cache_get_persistent (tile_cache));
-
- finalize_sql (file_cache);
- delete_temp_cache (file_cache);
-
- g_free (priv->real_cache_dir);
- priv->real_cache_dir = NULL;
-
- init_cache (file_cache);
-}
static void
delete_tile (ChamplainFileCache *file_cache, const gchar *filename)
@@ -1069,45 +962,4 @@ champlain_file_cache_purge (ChamplainFileCache *file_cache)
sqlite3_free (query);
}
-static void
-delete_dir_recursive (GFile *parent)
-{
- g_return_if_fail (parent);
-
- GError *error = NULL;
- GFileEnumerator *enumerator;
- GFileInfo *info;
- GFile *child;
-
- enumerator = g_file_enumerate_children (parent, "*",
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
-
- if (!enumerator)
- {
- DEBUG ("Failed to create file enumerator in delete_dir_recursive: %s", error->message);
- g_error_free (error);
- return;
- }
-
- info = g_file_enumerator_next_file (enumerator, NULL, NULL);
- while (info && !error)
- {
- child = g_file_get_child (parent, g_file_info_get_name (info));
-
- if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
- delete_dir_recursive (child);
- error = NULL;
- if (!g_file_delete (child, NULL, &error))
- {
- DEBUG ("Deleting tile from disk failed: %s", error->message);
- g_error_free (error);
- }
-
- g_object_unref (child);
- g_object_unref (info);
- info = g_file_enumerator_next_file (enumerator, NULL, NULL);
- }
-
- g_file_enumerator_close (enumerator, NULL, NULL);
-}
diff --git a/champlain/champlain-file-cache.h b/champlain/champlain-file-cache.h
index e3a5d9d..39243b1 100644
--- a/champlain/champlain-file-cache.h
+++ b/champlain/champlain-file-cache.h
@@ -57,7 +57,7 @@ GType champlain_file_cache_get_type (void);
ChamplainFileCache* champlain_file_cache_new (void);
ChamplainFileCache* champlain_file_cache_new_full (guint size_limit,
- const gchar *cache_dir, gboolean persistent);
+ const gchar *cache_dir);
guint champlain_file_cache_get_size_limit (ChamplainFileCache *file_cache);
void champlain_file_cache_set_size_limit (ChamplainFileCache *file_cache,
diff --git a/champlain/champlain-file-tile-source.c b/champlain/champlain-file-tile-source.c
index 191ddc4..aba3f5c 100644
--- a/champlain/champlain-file-tile-source.c
+++ b/champlain/champlain-file-tile-source.c
@@ -149,7 +149,7 @@ tile_rendered_cb (ChamplainTile *tile,
champlain_map_source_fill_tile (next_source, tile);
g_object_unref (map_source);
- g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, data);
+ g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, map_source);
}
static void
diff --git a/champlain/champlain-memory-cache.c b/champlain/champlain-memory-cache.c
new file mode 100644
index 0000000..e8f473a
--- /dev/null
+++ b/champlain/champlain-memory-cache.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#define DEBUG_FLAG CHAMPLAIN_DEBUG_CACHE
+#include "champlain-debug.h"
+
+#include "champlain-memory-cache.h"
+
+#include <glib.h>
+#include <string.h>
+
+G_DEFINE_TYPE (ChamplainMemoryCache, champlain_memory_cache, CHAMPLAIN_TYPE_TILE_CACHE);
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CHAMPLAIN_TYPE_MEMORY_CACHE, ChamplainMemoryCachePrivate))
+
+enum
+{
+ PROP_0,
+ PROP_SIZE_LIMIT
+};
+
+struct _ChamplainMemoryCachePrivate
+{
+ guint size_limit;
+ GQueue *queue;
+};
+
+typedef struct
+{
+ gchar *key;
+ gchar *data;
+ guint size;
+} QueueMember;
+
+
+static void fill_tile (ChamplainMapSource *map_source,
+ ChamplainTile *tile);
+
+static void store_tile (ChamplainTileCache *tile_cache,
+ ChamplainTile *tile,
+ const gchar *contents,
+ gsize size);
+static void refresh_tile_time (ChamplainTileCache *tile_cache,
+ ChamplainTile *tile);
+static void on_tile_filled (ChamplainTileCache *tile_cache,
+ ChamplainTile *tile);
+
+
+static void
+champlain_memory_cache_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ChamplainMemoryCache *memory_cache = CHAMPLAIN_MEMORY_CACHE (object);
+
+ switch (property_id)
+ {
+ case PROP_SIZE_LIMIT:
+ g_value_set_uint (value, champlain_memory_cache_get_size_limit (memory_cache));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+champlain_memory_cache_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ChamplainMemoryCache *memory_cache = CHAMPLAIN_MEMORY_CACHE (object);
+
+ switch (property_id)
+ {
+ case PROP_SIZE_LIMIT:
+ champlain_memory_cache_set_size_limit (memory_cache, g_value_get_uint (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+champlain_memory_cache_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (champlain_memory_cache_parent_class)->dispose (object);
+}
+
+
+static void
+champlain_memory_cache_finalize (GObject *object)
+{
+ ChamplainMemoryCache *memory_cache = CHAMPLAIN_MEMORY_CACHE (object);
+
+ g_queue_free (memory_cache->priv->queue);
+
+ G_OBJECT_CLASS (champlain_memory_cache_parent_class)->finalize (object);
+}
+
+
+static void
+champlain_memory_cache_class_init (ChamplainMemoryCacheClass *klass)
+{
+ ChamplainMapSourceClass *map_source_class = CHAMPLAIN_MAP_SOURCE_CLASS (klass);
+ ChamplainTileCacheClass *tile_cache_class = CHAMPLAIN_TILE_CACHE_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (ChamplainMemoryCachePrivate));
+
+ object_class->finalize = champlain_memory_cache_finalize;
+ object_class->dispose = champlain_memory_cache_dispose;
+ object_class->get_property = champlain_memory_cache_get_property;
+ object_class->set_property = champlain_memory_cache_set_property;
+
+ /*
+ * ChamplainMemoryCache:size-limit:
+ *
+ * The cache size limit in bytes.
+ *
+ * Note: this new value will not be applied until you call #champlain_cache_purge
+ *
+ * Since: 0.4
+ */
+ pspec = g_param_spec_uint ("size-limit",
+ "Size Limit",
+ "The cache's size limit (Mb)",
+ 1,
+ G_MAXINT,
+ 100,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_SIZE_LIMIT, pspec);
+
+ tile_cache_class->store_tile = store_tile;
+ tile_cache_class->refresh_tile_time = refresh_tile_time;
+ tile_cache_class->on_tile_filled = on_tile_filled;
+
+ map_source_class->fill_tile = fill_tile;
+}
+
+
+ChamplainMemoryCache *
+champlain_memory_cache_new (void)
+{
+ return CHAMPLAIN_MEMORY_CACHE (g_object_new (CHAMPLAIN_TYPE_MEMORY_CACHE, NULL));
+}
+
+
+ChamplainMemoryCache *
+champlain_memory_cache_new_full (guint size_limit)
+{
+ ChamplainMemoryCache *cache;
+
+ cache = g_object_new (CHAMPLAIN_TYPE_MEMORY_CACHE,
+ "size-limit", size_limit,
+ NULL);
+
+ return cache;
+}
+
+
+static void
+reload_tiles_cb (ChamplainMemoryCache *memory_cache, G_GNUC_UNUSED gpointer data)
+{
+ g_return_if_fail (CHAMPLAIN_IS_MEMORY_CACHE (memory_cache));
+
+ champlain_memory_cache_clean (memory_cache);
+}
+
+
+static void
+champlain_memory_cache_init (ChamplainMemoryCache *memory_cache)
+{
+ ChamplainMemoryCachePrivate *priv = GET_PRIVATE (memory_cache);
+
+ memory_cache->priv = priv;
+
+ g_signal_connect (memory_cache, "reload-tiles",
+ G_CALLBACK (reload_tiles_cb), NULL);
+
+ priv->queue = g_queue_new ();
+}
+
+
+guint
+champlain_memory_cache_get_size_limit (ChamplainMemoryCache *memory_cache)
+{
+ g_return_val_if_fail (CHAMPLAIN_IS_MEMORY_CACHE (memory_cache), 0);
+
+ return memory_cache->priv->size_limit;
+}
+
+
+void
+champlain_memory_cache_set_size_limit (ChamplainMemoryCache *memory_cache,
+ guint size_limit)
+{
+ g_return_if_fail (CHAMPLAIN_IS_MEMORY_CACHE (memory_cache));
+
+ ChamplainMemoryCachePrivate *priv = memory_cache->priv;
+
+ priv->size_limit = size_limit;
+ g_object_notify (G_OBJECT (memory_cache), "size-limit");
+}
+
+
+static gchar *
+generate_queue_key (ChamplainMemoryCache *memory_cache,
+ ChamplainTile *tile)
+{
+ g_return_val_if_fail (CHAMPLAIN_IS_MEMORY_CACHE (memory_cache), NULL);
+ g_return_val_if_fail (CHAMPLAIN_IS_TILE (tile), NULL);
+
+ ChamplainMapSource *map_source = CHAMPLAIN_MAP_SOURCE (memory_cache);
+
+ gchar *filename = g_strdup_printf ("%d/%d/%d/%s",
+ champlain_tile_get_zoom_level (tile),
+ champlain_tile_get_x (tile),
+ champlain_tile_get_y (tile),
+ champlain_map_source_get_id (map_source));
+ return filename;
+}
+
+
+static gint
+compare_queue_members (const QueueMember *a, const QueueMember *b)
+{
+ return g_strcmp0 (a->key, b->key);
+}
+
+
+static void
+move_queue_member_to_head (GQueue *queue, GList *link)
+{
+ g_queue_unlink (queue, link);
+ g_queue_push_head_link (queue, link);
+}
+
+
+static void
+delete_queue_member (QueueMember *member, gpointer user_data)
+{
+ if (member)
+ {
+ g_free (member->key);
+ g_free (member->data);
+ g_free (member);
+ }
+}
+
+
+static void
+tile_rendered_cb (ChamplainTile *tile,
+ ChamplainRenderCallbackData *data,
+ ChamplainMapSource *map_source)
+{
+ ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source);
+
+ if (!data->error)
+ {
+ if (CHAMPLAIN_IS_TILE_CACHE (next_source))
+ on_tile_filled (CHAMPLAIN_TILE_CACHE (next_source), tile);
+
+ champlain_tile_set_fade_in (tile, TRUE);
+ champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+ champlain_tile_display_content (tile);
+ }
+ else if (CHAMPLAIN_IS_MAP_SOURCE (next_source))
+ champlain_map_source_fill_tile (next_source, tile);
+
+ g_object_unref (map_source);
+ g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, map_source);
+}
+
+
+static void
+fill_tile (ChamplainMapSource *map_source,
+ ChamplainTile *tile)
+{
+ g_return_if_fail (CHAMPLAIN_IS_MEMORY_CACHE (map_source));
+ g_return_if_fail (CHAMPLAIN_IS_TILE (tile));
+
+ ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source);
+
+ if (champlain_tile_get_state (tile) != CHAMPLAIN_STATE_LOADED)
+ {
+ ChamplainMemoryCache *memory_cache = CHAMPLAIN_MEMORY_CACHE (map_source);
+ ChamplainMemoryCachePrivate *priv = memory_cache->priv;
+ ChamplainRenderer *renderer;
+ GList *link;
+ QueueMember key;
+
+ key.key = generate_queue_key (memory_cache, tile);
+ link = g_queue_find_custom (priv->queue, &key, (GCompareFunc) compare_queue_members);
+ if (link)
+ {
+ QueueMember *member = link->data;
+
+ move_queue_member_to_head (priv->queue, link);
+
+ renderer = champlain_map_source_get_renderer (map_source);
+
+ g_return_if_fail (CHAMPLAIN_IS_RENDERER (renderer));
+
+ g_object_ref (map_source);
+ g_signal_connect (tile, "render-complete", G_CALLBACK (tile_rendered_cb), map_source);
+ champlain_renderer_set_data (renderer, member->data, member->size);
+ champlain_renderer_render (renderer, tile);
+
+ return;
+ }
+ }
+
+ if (CHAMPLAIN_IS_MAP_SOURCE (next_source))
+ champlain_map_source_fill_tile (next_source, tile);
+ else if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADED)
+ {
+ /* if we have some content, use the tile even if it wasn't validated */
+ champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+ champlain_tile_display_content (tile);
+ }
+}
+
+
+static void
+store_tile (ChamplainTileCache *tile_cache,
+ ChamplainTile *tile,
+ const gchar *contents,
+ gsize size)
+{
+ g_return_if_fail (CHAMPLAIN_IS_MEMORY_CACHE (tile_cache));
+
+ ChamplainMemoryCache *memory_cache = CHAMPLAIN_MEMORY_CACHE (tile_cache);
+ ChamplainMemoryCachePrivate *priv = memory_cache->priv;
+ GList *link;
+ QueueMember key;
+
+ key.key = generate_queue_key (memory_cache, tile);
+ link = g_queue_find_custom (priv->queue, &key, (GCompareFunc) compare_queue_members);
+ if (link)
+ move_queue_member_to_head (priv->queue, link);
+ else
+ {
+ QueueMember *member;
+
+ if (priv->queue->length >= priv->size_limit)
+ {
+ member = g_queue_pop_tail (priv->queue);
+ delete_queue_member (member, NULL);
+ }
+
+ member = g_new0 (QueueMember, 1);
+ member->key = key.key;
+ member->data = g_memdup (contents, size);
+ member->size = size;
+
+ g_queue_push_head (priv->queue, member);
+ }
+}
+
+
+static void
+refresh_tile_time (ChamplainTileCache *tile_cache,
+ ChamplainTile *tile)
+{
+}
+
+
+void
+champlain_memory_cache_clean (ChamplainMemoryCache *memory_cache)
+{
+ ChamplainMemoryCachePrivate *priv = memory_cache->priv;
+
+ g_queue_foreach (priv->queue, (GFunc) delete_queue_member, NULL);
+ g_queue_clear (priv->queue);
+}
+
+
+static void
+on_tile_filled (ChamplainTileCache *tile_cache,
+ ChamplainTile *tile)
+{
+ g_return_if_fail (CHAMPLAIN_IS_MEMORY_CACHE (tile_cache));
+ g_return_if_fail (CHAMPLAIN_IS_TILE (tile));
+
+ ChamplainMapSource *map_source = CHAMPLAIN_MAP_SOURCE (tile_cache);
+ ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source);
+ ChamplainMemoryCache *memory_cache = CHAMPLAIN_MEMORY_CACHE (tile_cache);
+ ChamplainMemoryCachePrivate *priv = memory_cache->priv;
+ GList *link;
+ QueueMember key;
+
+ key.key = generate_queue_key (memory_cache, tile);
+ link = g_queue_find_custom (priv->queue, &key, (GCompareFunc) compare_queue_members);
+ if (link)
+ move_queue_member_to_head (priv->queue, link);
+
+ if (CHAMPLAIN_IS_TILE_CACHE (next_source))
+ champlain_tile_cache_on_tile_filled (CHAMPLAIN_TILE_CACHE (next_source), tile);
+}
diff --git a/champlain/champlain-memory-cache.h b/champlain/champlain-memory-cache.h
new file mode 100644
index 0000000..33a1993
--- /dev/null
+++ b/champlain/champlain-memory-cache.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if !defined (__CHAMPLAIN_CHAMPLAIN_H_INSIDE__) && !defined (CHAMPLAIN_COMPILATION)
+#error "Only <champlain/champlain.h> can be included directly."
+#endif
+
+#ifndef _CHAMPLAIN_MEMORY_CACHE_H_
+#define _CHAMPLAIN_MEMORY_CACHE_H_
+
+#include <glib-object.h>
+#include <champlain/champlain-tile-cache.h>
+
+G_BEGIN_DECLS
+
+#define CHAMPLAIN_TYPE_MEMORY_CACHE (champlain_memory_cache_get_type ())
+#define CHAMPLAIN_MEMORY_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CHAMPLAIN_TYPE_MEMORY_CACHE, ChamplainMemoryCache))
+#define CHAMPLAIN_MEMORY_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CHAMPLAIN_TYPE_MEMORY_CACHE, ChamplainMemoryCacheClass))
+#define CHAMPLAIN_IS_MEMORY_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CHAMPLAIN_TYPE_MEMORY_CACHE))
+#define CHAMPLAIN_IS_MEMORY_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CHAMPLAIN_TYPE_MEMORY_CACHE))
+#define CHAMPLAIN_MEMORY_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CHAMPLAIN_TYPE_MEMORY_CACHE, ChamplainMemoryCacheClass))
+
+typedef struct _ChamplainMemoryCachePrivate ChamplainMemoryCachePrivate;
+
+typedef struct _ChamplainMemoryCache ChamplainMemoryCache;
+typedef struct _ChamplainMemoryCacheClass ChamplainMemoryCacheClass;
+
+struct _ChamplainMemoryCache
+{
+ ChamplainTileCache parent_instance;
+
+ ChamplainMemoryCachePrivate *priv;
+};
+
+struct _ChamplainMemoryCacheClass
+{
+ ChamplainTileCacheClass parent_class;
+};
+
+GType champlain_memory_cache_get_type (void);
+
+ChamplainMemoryCache *champlain_memory_cache_new (void);
+ChamplainMemoryCache *champlain_memory_cache_new_full (guint size_limit);
+
+guint champlain_memory_cache_get_size_limit (ChamplainMemoryCache *memory_cache);
+void champlain_memory_cache_set_size_limit (ChamplainMemoryCache *memory_cache,
+ guint size_limit);
+
+void champlain_memory_cache_clean (ChamplainMemoryCache *memory_cache);
+
+
+G_END_DECLS
+
+#endif /* _CHAMPLAIN_MEMORY_CACHE_H_ */
diff --git a/champlain/champlain-network-bbox-tile-source.c b/champlain/champlain-network-bbox-tile-source.c
index 977d5ec..f626534 100644
--- a/champlain/champlain-network-bbox-tile-source.c
+++ b/champlain/champlain-network-bbox-tile-source.c
@@ -353,7 +353,7 @@ tile_rendered_cb (ChamplainTile *tile,
champlain_map_source_fill_tile (next_source, tile);
g_object_unref (map_source);
- g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, data);
+ g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, map_source);
}
static void
diff --git a/champlain/champlain-network-tile-source.c b/champlain/champlain-network-tile-source.c
index f877367..a18baee 100644
--- a/champlain/champlain-network-tile-source.c
+++ b/champlain/champlain-network-tile-source.c
@@ -548,7 +548,7 @@ tile_rendered_cb (ChamplainTile *tile, ChamplainRenderCallbackData *data, TileRe
g_object_unref (map_source);
g_free (user_data);
- g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, data);
+ g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, user_data);
}
diff --git a/champlain/champlain-null-tile-source.c b/champlain/champlain-null-tile-source.c
index ced41bc..9b8a959 100644
--- a/champlain/champlain-null-tile-source.c
+++ b/champlain/champlain-null-tile-source.c
@@ -104,7 +104,7 @@ tile_rendered_cb (ChamplainTile *tile,
champlain_map_source_fill_tile (next_source, tile);
g_object_unref (map_source);
- g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, data);
+ g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, map_source);
}
diff --git a/champlain/champlain-tile-cache.c b/champlain/champlain-tile-cache.c
index 25576da..19d75f6 100644
--- a/champlain/champlain-tile-cache.c
+++ b/champlain/champlain-tile-cache.c
@@ -31,16 +31,6 @@ G_DEFINE_TYPE (ChamplainTileCache, champlain_tile_cache, CHAMPLAIN_TYPE_MAP_SOUR
#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), CHAMPLAIN_TYPE_TILE_CACHE, ChamplainTileCachePrivate))
-enum
-{
- PROP_0,
- PROP_PERSISTENT_CACHE
-};
-
-struct _ChamplainTileCachePrivate
-{
- gboolean persistent;
-};
static const gchar *get_id (ChamplainMapSource *map_source);
static const gchar *get_name (ChamplainMapSource *map_source);
@@ -50,43 +40,7 @@ static guint get_min_zoom_level (ChamplainMapSource *map_source);
static guint get_max_zoom_level (ChamplainMapSource *map_source);
static guint get_tile_size (ChamplainMapSource *map_source);
static ChamplainMapProjection get_projection (ChamplainMapSource *map_source);
-static void reload_tiles_cb (ChamplainTileCache *tile_cache, G_GNUC_UNUSED gpointer data);
-
-static void
-champlain_tile_cache_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ChamplainTileCache *tile_cache = CHAMPLAIN_TILE_CACHE (object);
-
- switch (property_id)
- {
- case PROP_PERSISTENT_CACHE:
- g_value_set_boolean (value, champlain_tile_cache_get_persistent (tile_cache));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
-}
-static void
-champlain_tile_cache_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ChamplainTileCachePrivate *priv = CHAMPLAIN_TILE_CACHE (object)->priv;
-
- switch (property_id)
- {
- case PROP_PERSISTENT_CACHE:
- priv->persistent = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
-}
static void
champlain_tile_cache_dispose (GObject *object)
@@ -112,14 +66,9 @@ champlain_tile_cache_class_init (ChamplainTileCacheClass *klass)
GObjectClass* object_class = G_OBJECT_CLASS (klass);
ChamplainMapSourceClass *map_source_class = CHAMPLAIN_MAP_SOURCE_CLASS (klass);
ChamplainTileCacheClass *tile_cache_class = CHAMPLAIN_TILE_CACHE_CLASS (klass);
- GParamSpec *pspec;
-
- g_type_class_add_private (klass, sizeof (ChamplainTileCachePrivate));
object_class->finalize = champlain_tile_cache_finalize;
object_class->dispose = champlain_tile_cache_dispose;
- object_class->get_property = champlain_tile_cache_get_property;
- object_class->set_property = champlain_tile_cache_set_property;
object_class->constructed = champlain_tile_cache_constructed;
map_source_class->get_id = get_id;
@@ -136,62 +85,13 @@ champlain_tile_cache_class_init (ChamplainTileCacheClass *klass)
tile_cache_class->refresh_tile_time = NULL;
tile_cache_class->on_tile_filled = NULL;
tile_cache_class->store_tile = NULL;
- tile_cache_class->clean = NULL;
-
- /**
- * ChamplainTileCache:persistent-cache
- *
- * Determines whether the cache is persistent or temporary (cleaned upon
- * destruction)
- *
- * Since: 0.6
- */
- pspec = g_param_spec_boolean ("persistent-cache",
- "Persistent Cache",
- "Specifies whether the cache is persistent",
- TRUE,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_PERSISTENT_CACHE, pspec);
}
static void
champlain_tile_cache_init (ChamplainTileCache *tile_cache)
{
- ChamplainTileCachePrivate *priv = GET_PRIVATE (tile_cache);
-
- tile_cache->priv = priv;
-
- priv->persistent = TRUE;
- g_signal_connect (tile_cache, "reload-tiles",
- G_CALLBACK (reload_tiles_cb), NULL);
-}
-
-static
-void reload_tiles_cb (ChamplainTileCache *tile_cache, G_GNUC_UNUSED gpointer data)
-{
- g_return_if_fail (CHAMPLAIN_IS_TILE_CACHE (tile_cache));
-
- if (!champlain_tile_cache_get_persistent (tile_cache))
- champlain_tile_cache_clean (tile_cache);
}
-/**
- * champlain_tile_cache_get_persistent:
- * @tile_cache: a #ChamplainTileCache
- *
- * Gets cache persistency information.
- *
- * Returns: TRUE when the cache is persistent; FALSE otherwise.
- *
- * Since: 0.6
- */
-gboolean
-champlain_tile_cache_get_persistent (ChamplainTileCache *tile_cache)
-{
- g_return_val_if_fail (CHAMPLAIN_IS_TILE_CACHE (tile_cache), FALSE);
-
- return tile_cache->priv->persistent;
-}
/**
* champlain_tile_cache_store_tile:
@@ -257,23 +157,6 @@ champlain_tile_cache_on_tile_filled (ChamplainTileCache *tile_cache,
CHAMPLAIN_TILE_CACHE_GET_CLASS (tile_cache)->on_tile_filled (tile_cache, tile);
}
-/**
- * champlain_tile_cache_clean:
- * @tile_cache: a #ChamplainTileCache
- *
- * Erases the contents of the cache. This function will fail when the cache is
- * not temporary.
- *
- * Since: 0.6
- */
-void
-champlain_tile_cache_clean (ChamplainTileCache *tile_cache)
-{
- g_return_if_fail (CHAMPLAIN_IS_TILE_CACHE (tile_cache));
-
- CHAMPLAIN_TILE_CACHE_GET_CLASS (tile_cache)->clean (tile_cache);
-}
-
static const gchar *
get_id (ChamplainMapSource *map_source)
{
diff --git a/champlain/champlain-tile-cache.h b/champlain/champlain-tile-cache.h
index d8aa0b6..ff8ffc7 100644
--- a/champlain/champlain-tile-cache.h
+++ b/champlain/champlain-tile-cache.h
@@ -59,13 +59,10 @@ struct _ChamplainTileCacheClass
ChamplainTile *tile);
void (*on_tile_filled) (ChamplainTileCache *tile_cache,
ChamplainTile *tile);
- void (*clean) (ChamplainTileCache *tile_cache);
};
GType champlain_tile_cache_get_type (void);
-gboolean champlain_tile_cache_get_persistent (ChamplainTileCache *tile_cache);
-
void champlain_tile_cache_store_tile (ChamplainTileCache *tile_cache,
ChamplainTile *tile,
const gchar *contents,
@@ -74,7 +71,6 @@ void champlain_tile_cache_refresh_tile_time (ChamplainTileCache *tile_cache,
ChamplainTile *tile);
void champlain_tile_cache_on_tile_filled (ChamplainTileCache *tile_cache,
ChamplainTile *tile);
-void champlain_tile_cache_clean (ChamplainTileCache *tile_cache);
G_END_DECLS
diff --git a/champlain/champlain.h b/champlain/champlain.h
index a183286..8c87235 100644
--- a/champlain/champlain.h
+++ b/champlain/champlain.h
@@ -37,6 +37,7 @@
#include "champlain/champlain-map-source-chain.h"
#include "champlain/champlain-tile-source.h"
#include "champlain/champlain-tile-cache.h"
+#include "champlain/champlain-memory-cache.h"
#include "champlain/champlain-network-tile-source.h"
#include "champlain/champlain-file-cache.h"
#include "champlain/champlain-null-tile-source.h"
diff --git a/demos/local-rendering.c b/demos/local-rendering.c
index 694e547..e9d57c7 100644
--- a/demos/local-rendering.c
+++ b/demos/local-rendering.c
@@ -444,7 +444,8 @@ map_source_changed (GtkWidget *widget, ChamplainView *view)
champlain_map_source_chain_push (source_chain, src);
champlain_map_source_chain_push (source_chain, tile_source);
- src = CHAMPLAIN_MAP_SOURCE(champlain_file_cache_new_full (100000000, NULL, FALSE));
+ src = CHAMPLAIN_MAP_SOURCE(champlain_memory_cache_new_full (100));
+ champlain_map_source_set_renderer (src, CHAMPLAIN_RENDERER (champlain_image_renderer_new ()));
champlain_map_source_chain_push (source_chain, src);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]