--- /dev/null
+/*
+ * Buxton
+ *
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "buxton2.h"
+#include "log.h"
+#include "cache.h"
+
+#define CACHE_COUNT_MAX 2000
+#define CACHE_SIZE_MAX (1024 * 1024) /* 1MB per cache (MAX) */
+
+#define DEFAULT_DROP_CACHE_SIZE 50
+
+#undef LOG_TAG
+#define LOG_TAG "BXT_CACHE"
+
+typedef struct _cache {
+ GHashTable *hash_table;
+ enum buxton_layer_type layer_type;
+ int count;
+ int size;
+} bxt_cache;
+
+typedef struct _cache_data {
+ enum buxton_layer_type layer_type;
+ int len; /* data size */
+ void *data; /* raw data */
+} cache_data;
+
+static bxt_cache *g_base_db_cache;
+static bxt_cache *g_normal_db_cache;
+
+static bxt_cache *get_cache(enum buxton_layer_type layer_type)
+{
+ return (layer_type == BUXTON_LAYER_NORMAL) ?
+ g_normal_db_cache : g_base_db_cache;
+}
+
+static void destroy_key(gpointer key)
+{
+ if (key)
+ free(key);
+}
+
+static void destroy_data(gpointer data)
+{
+ cache_data *cdata = (cache_data *) data;
+ bxt_cache *cache = NULL;
+
+ if (!cdata)
+ return;
+
+ cache = get_cache(cdata->layer_type);
+
+ if (!cache)
+ return;
+
+ if (cdata->data) {
+ if (cache) {
+ cache->size -= cdata->len;
+ cache->count--;
+ }
+ free(cdata->data);
+ }
+
+ free(data);
+
+}
+
+void cache_init(void)
+{
+ g_base_db_cache = (bxt_cache *)malloc(sizeof(bxt_cache));
+ if (!g_base_db_cache)
+ return;
+ g_normal_db_cache = (bxt_cache *)malloc(sizeof(bxt_cache));
+ if (!g_normal_db_cache) {
+ free(g_base_db_cache);
+ g_base_db_cache = NULL;
+ return;
+ }
+
+ g_base_db_cache->hash_table = g_hash_table_new_full(g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)destroy_key,
+ (GDestroyNotify)destroy_data);
+ g_base_db_cache->size = 0;
+ g_base_db_cache->count = 0;
+
+ g_normal_db_cache->hash_table = g_hash_table_new_full(g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)destroy_key,
+ (GDestroyNotify)destroy_data);
+ g_normal_db_cache->size = 0;
+ g_normal_db_cache->count = 0;
+}
+
+void cache_remove(enum buxton_layer_type layer_type, const char *key)
+{
+ GHashTable *hash_table = NULL;
+
+ bxt_cache *cache = get_cache(layer_type);
+
+ if (!cache)
+ return;
+
+ hash_table = cache->hash_table;
+
+ if (!hash_table)
+ return;
+
+ if (g_hash_table_remove(hash_table, key)) {
+ bxt_dbg("[%s cache] removed (%s)/count(%d)/total size(%d)",
+ (layer_type == BUXTON_LAYER_NORMAL) ?
+ "NORMAL" : "BASE",
+ key, cache->count, cache->size);
+ }
+}
+
+void cache_update_data(enum buxton_layer_type layer_type,
+ const char *key, uint8_t *data, int len)
+{
+ GHashTable *hash_table = NULL;
+ gpointer raw_data;
+
+ cache_data *cdata;
+ bxt_cache *cache = get_cache(layer_type);
+
+ if (!cache)
+ return;
+
+ hash_table = cache->hash_table;
+
+ raw_data = g_hash_table_lookup(hash_table, key);
+
+ if (!raw_data) {
+ cache_insert(layer_type, key, data, len);
+ return;
+ }
+
+ cdata = (cache_data *)raw_data;
+
+ if (cdata->data)
+ free(cdata->data);
+
+ cdata->data = malloc(len);
+ if (!cdata->data)
+ return;
+
+ memcpy(cdata->data, data, len);
+
+ cdata->len = len;
+}
+
+static void cache_drop(enum buxton_layer_type layer_type, int size)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ int remain = size;
+ GHashTable *hash_table = NULL;
+
+ bxt_cache *cache = get_cache(layer_type);
+
+ if (!cache)
+ return;
+
+ hash_table = cache->hash_table;
+
+ g_hash_table_iter_init(&iter, hash_table);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (remain > 0) {
+ bxt_dbg("[%s cache][%d] removed (%s)",
+ (layer_type == BUXTON_LAYER_NORMAL) ?
+ "NORMAL" : "BASE", remain, (char *)key);
+ g_hash_table_iter_remove(&iter);
+ remain--;
+ }
+ }
+}
+
+void cache_insert(enum buxton_layer_type layer_type, const char *key,
+ uint8_t *data, int len)
+{
+ GHashTable *hash_table = NULL;
+ char *key_name;
+
+ bxt_cache *cache = get_cache(layer_type);
+ cache_data *raw_data;
+
+ if (!cache)
+ return;
+
+ hash_table = cache->hash_table;
+
+ if (g_hash_table_contains(hash_table, key))
+ return;
+
+ if ((g_hash_table_size(hash_table) >= CACHE_COUNT_MAX) ||
+ (cache->size >= CACHE_SIZE_MAX))
+ cache_drop(layer_type, DEFAULT_DROP_CACHE_SIZE);
+
+ key_name = (char *)strdup(key);
+ if (!key_name)
+ return;
+
+ raw_data = (cache_data *)malloc(sizeof(cache_data));
+ if (!raw_data) {
+ free(key_name);
+ return;
+ }
+
+ raw_data->data = malloc(len);
+ if (!raw_data->data) {
+ free(key_name);
+ free(raw_data);
+ return;
+ }
+
+ memcpy(raw_data->data, data, len);
+
+ raw_data->len = len;
+ raw_data->layer_type = layer_type;
+
+ g_hash_table_insert(hash_table, key_name, (gpointer) raw_data);
+
+ cache->count++;
+ cache->size += len;
+
+ bxt_dbg("[%s cache] inserted (%s)/size(%d)/count(%d)/total size(%d)",
+ (layer_type == BUXTON_LAYER_NORMAL) ?
+ "NORMAL" : "BASE", key, len, cache->count, cache->size);
+
+}
+
+int cache_get(enum buxton_layer_type layer_type, const char *key,
+ void **data, int *data_len)
+{
+ GHashTable *hash_table = NULL;
+ gpointer raw_data;
+
+ cache_data *cdata;
+ bxt_cache *cache = get_cache(layer_type);
+
+ if (!cache)
+ return -1;
+
+ hash_table = cache->hash_table;
+
+ raw_data = g_hash_table_lookup(hash_table, key);
+
+ if (!raw_data)
+ return -1;
+
+ cdata = (cache_data *)raw_data;
+
+ *data = malloc(cdata->len);
+ if (!*data)
+ return -1;
+
+ memcpy(*data, cdata->data, cdata->len);
+ *data_len = cdata->len;
+
+ bxt_dbg("[%s cache] get (%s)/size(%d)",
+ (layer_type == BUXTON_LAYER_NORMAL) ?
+ "NORMAL" : "BASE", key, cdata->len);
+
+ return 0;
+}
+
+void cache_clear(enum buxton_layer_type layer_type)
+{
+ bxt_cache *cache = get_cache(layer_type);
+
+ if (!cache)
+ return;
+
+ g_hash_table_remove_all(cache->hash_table);
+}
+
--- /dev/null
+/*
+ * Buxton
+ *
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+void cache_init(void);
+void cache_insert(enum buxton_layer_type layer_type, const char *key,
+ uint8_t *data, int len);
+void cache_remove(enum buxton_layer_type layer_type, const char *key);
+void cache_update_data(enum buxton_layer_type layer_type, const char *key,
+ uint8_t *data, int len);
+int cache_get(enum buxton_layer_type layer_type, const char *key,
+ void **data, int *data_len);
+
+void cache_clear(enum buxton_layer_type layer_type);
#include "config.h"
#include "backends.h"
#include "serialize.h"
+#include "cache.h"
static int get_path(uid_t uid, enum buxton_layer_type type,
const struct layer *ly, char *path, int sz)
return -1;
}
+ if (!cache_get(type, key, (void **)data, len))
+ return 0;
+
r = get_path(uid, type, ly, path, sizeof(path));
if (r == -1)
return -1;
return -1;
}
+ cache_insert(type, key, *data, *len);
+
return 0;
}
return 0;
}
+static int is_updated_data(enum buxton_layer_type type, const char *key,
+ uint8_t *data, int len)
+{
+ uint8_t *cur_data;
+ int cur_data_len;
+
+ if (cache_get(type, key, (void **)&cur_data, &cur_data_len))
+ return -1;
+
+ if (cur_data_len != len) {
+ if (cur_data)
+ free(cur_data);
+
+ return -1;
+ }
+
+ if (memcmp(cur_data, data, len)) {
+ if (cur_data)
+ free(cur_data);
+ return -1;
+ }
+
+ if (cur_data)
+ free(cur_data);
+
+ return 0;
+
+}
+
static int set_raw(const struct layer *ly, uid_t uid,
enum buxton_layer_type type, const char *key,
uint8_t *data, int len)
return -1;
}
+ if (!is_updated_data(type, key, data, len)) {
+ bxt_dbg("skip setting (same data) - (%s)", key);
+ return 0;
+ }
+
r = get_path(uid, type, ly, path, sizeof(path));
if (r == -1)
return -1;
if (r == -1)
return -1;
+ cache_update_data(type, key, data, len);
+
return 0;
}
return -1;
}
+ cache_remove(layer->type, key);
+
return 0;
}
#define LOG_TAG "VCONF"
+#define HASH_SIZE 10
+
static void _restore_noti_cb(gpointer key, gpointer value, gpointer user_data);
static pthread_mutex_t vconf_lock = PTHREAD_MUTEX_INITIALIZER;
static struct buxton_layer *system_layer;
static struct buxton_layer *memory_layer;
static GHashTable *noti_tbl;
+static GHashTable *cache_tbl;
+static GQueue *victims;
struct noti {
char *key;
g_hash_table_destroy(noti_tbl);
noti_tbl = NULL;
+ g_hash_table_destroy(cache_tbl);
+ cache_tbl = NULL;
+
+ g_queue_free_full(victims, (GDestroyNotify)free);
+ victims = NULL;
+
buxton_close(client);
client = NULL;
}
NULL, (GDestroyNotify)free_noti);
}
+ if (!cache_tbl) {
+ cache_tbl = g_hash_table_new_full(g_str_hash, g_str_equal,
+ (GDestroyNotify)free,
+ (GDestroyNotify)buxton_value_free);
+ }
+
+ if (!victims) {
+ victims = g_queue_new();
+ g_queue_init(victims);
+ }
+
if (!system_layer)
system_layer = buxton_create_layer("system");
if (!memory_layer)
}
r = buxton_set_value_sync(client, get_layer(key), key, val);
- if (r == -1)
+ if (r == -1) {
LOGE("set value: key '%s' errno %d", key, errno);
+ } else {
+ if (cache_tbl) {
+ if (g_hash_table_contains(cache_tbl, key)) {
+ g_hash_table_replace(cache_tbl,
+ strdup(key),
+ buxton_value_duplicate(val));
+ }
+ }
+ }
_close();
pthread_mutex_unlock(&vconf_lock);
return r;
}
+static void cache_cb(const struct buxton_layer *layer, const char *key,
+ const struct buxton_value *val, void *user_data)
+{
+ if (g_hash_table_contains(cache_tbl, key)) {
+ g_hash_table_replace(cache_tbl,
+ strdup(key), buxton_value_duplicate(val));
+ }
+}
+
+
+static void _reduce_cache()
+{
+ char *key;
+ int r;
+
+ key = (char *)g_queue_pop_tail(victims);
+ if (key == NULL)
+ return;
+
+ r = g_hash_table_remove(cache_tbl, key);
+ if (r == false)
+ return;
+
+ r = buxton_unregister_notification_sync(client, get_layer(key),
+ key, cache_cb);
+ if (r == -1)
+ return;
+
+ _close();
+
+ free(key);
+}
+
+static void _insert_cache(const char *key, struct buxton_value *val)
+{
+ int r;
+
+ r = _open();
+ if (r == -1)
+ return;
+
+ if (g_hash_table_size(cache_tbl) >= HASH_SIZE)
+ _reduce_cache();
+
+ r = buxton_register_notification_sync(client, get_layer(key), key,
+ cache_cb, NULL);
+
+ if (r == -1) {
+ _close();
+ return;
+ }
+
+ g_queue_push_head(victims, (char *)strdup(key));
+ r = g_hash_table_insert(cache_tbl, strdup(key),
+ buxton_value_duplicate(val));
+}
+
static int _vconf_get(const char *key, enum buxton_key_type type,
struct buxton_value **val)
{
assert(val);
pthread_mutex_lock(&vconf_lock);
+
r = _open();
if (r == -1) {
pthread_mutex_unlock(&vconf_lock);
return -1;
}
+ v = g_hash_table_lookup(cache_tbl, key);
+ if (v) {
+ *val = buxton_value_duplicate(v);
+ _close();
+ pthread_mutex_unlock(&vconf_lock);
+ return 0;
+ }
+
r = buxton_get_value_sync(client, get_layer(key), key, &v);
if (r == -1) {
LOGE("get value: key '%s' errno %d", key, errno);
}
}
+ _insert_cache(key, v);
_close();
+
pthread_mutex_unlock(&vconf_lock);
return r;