mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-01-16 23:59:19 +03:00
change the persistant data store to owning the allocations
This commit is contained in:
parent
335ba082fd
commit
8b810ee4a1
@ -31,8 +31,6 @@ enum backing_store_flags {
|
||||
BACKING_STORE_NONE = 0,
|
||||
/** data is metadata */
|
||||
BACKING_STORE_META = 1,
|
||||
/** backing store will handle allocation. */
|
||||
BACKING_STORE_ALLOC = 2
|
||||
};
|
||||
|
||||
/** low level cache backing store operation table
|
||||
@ -61,12 +59,13 @@ struct gui_llcache_table {
|
||||
* Place an object in the backing store.
|
||||
*
|
||||
* The object is placed in the persistent store and may be
|
||||
* retrieved. If the BACKING_STORE_ALLOC flag is used the
|
||||
* backing store will take a reference to the passed data,
|
||||
* subsequently the caller should explicitly release the
|
||||
* allocation using the release method and not free the data
|
||||
* itself. An additional effect of this is that the persistent
|
||||
* storage may not have been completely written on return.
|
||||
* retrieved with the fetch method.
|
||||
* The backing store will take a reference to the
|
||||
* passed data, subsequently the caller should explicitly
|
||||
* release the allocation using the release method and not
|
||||
* free the data itself.
|
||||
* The caller may not assume that the persistent storage has
|
||||
* been completely written on return.
|
||||
*
|
||||
* @param[in] url The url is used as the unique primary key for the data.
|
||||
* @param[in] flags The flags to control how the obejct is stored.
|
||||
@ -80,9 +79,13 @@ struct gui_llcache_table {
|
||||
/**
|
||||
* Retrive an object from the backing store.
|
||||
*
|
||||
* If the BACKING_STORE_ALLOC flag is set the returned memory
|
||||
* is managed by the backing store and should be freed by
|
||||
* calling the release method.
|
||||
* The caller may provide a buffer in \a data and a buffer
|
||||
* length in \a datalen. Alternatively the backing store will
|
||||
* allocate its own buffer if \a data is NULL, this memory is
|
||||
* managed by the backing store.
|
||||
* The caller must assume nothing about the backing store
|
||||
* allocated buffers and the storage and *must* be freed by
|
||||
* calling the release method.
|
||||
*
|
||||
* @param[in] url The url is used as the unique primary key for the data.
|
||||
* @param[in] flags The flags to control how the object is retrived.
|
||||
@ -90,9 +93,18 @@ struct gui_llcache_table {
|
||||
* @param[in,out] datalen The length of the \a data retrieved.
|
||||
* @return NSERROR_OK on success or error code on faliure.
|
||||
*/
|
||||
nserror (*fetch)(struct nsurl *url, enum backing_store_flags *flags,
|
||||
nserror (*fetch)(struct nsurl *url, enum backing_store_flags flags,
|
||||
uint8_t **data, size_t *datalen);
|
||||
|
||||
/**
|
||||
* release a previously fetched or stored memory object.
|
||||
*
|
||||
* @param url The url is used as the unique primary key to invalidate.
|
||||
* @param[in] flags The flags to control how the object data is released.
|
||||
* @return NSERROR_OK on success or error code on faliure.
|
||||
*/
|
||||
nserror (*release)(struct nsurl *url, enum backing_store_flags flags);
|
||||
|
||||
/**
|
||||
* Invalidate a source object from the backing store.
|
||||
*
|
||||
@ -106,19 +118,6 @@ struct gui_llcache_table {
|
||||
*/
|
||||
nserror (*invalidate)(struct nsurl *url);
|
||||
|
||||
/**
|
||||
* release a previously fetched or stored memory object.
|
||||
*
|
||||
* if the BACKING_STORE_ALLOC flag was used with the fetch or
|
||||
* store operation for this url the returned storage is
|
||||
* unreferenced. When the reference count drops to zero the
|
||||
* storage is released.
|
||||
*
|
||||
* @param url The url is used as the unique primary key to invalidate.
|
||||
* @param[in] flags The flags to control how the object data is released.
|
||||
* @return NSERROR_OK on success or error code on faliure.
|
||||
*/
|
||||
nserror (*release)(struct nsurl *url, enum backing_store_flags flags);
|
||||
};
|
||||
|
||||
extern struct gui_llcache_table* null_llcache_table;
|
||||
|
@ -56,7 +56,7 @@
|
||||
#define DEFAULT_ENTRY_SIZE 16
|
||||
|
||||
/** Backing store file format version */
|
||||
#define CONTROL_VERSION 110
|
||||
#define CONTROL_VERSION 120
|
||||
|
||||
/** Number of milliseconds after a update before control data maintinance is performed */
|
||||
#define CONTROL_MAINT_TIME 10000
|
||||
@ -73,21 +73,6 @@
|
||||
/** Filename of serialised entries */
|
||||
#define ENTRIES_FNAME "entries"
|
||||
|
||||
/**
|
||||
* flags that indicate what additional information is contained within
|
||||
* an entry.
|
||||
*/
|
||||
enum store_entry_flags {
|
||||
/** entry is not managing the allocation */
|
||||
STORE_ENTRY_FLAG_NONE = 0,
|
||||
/** entry allocation is on heap */
|
||||
STORE_ENTRY_FLAG_HEAP = 1,
|
||||
/** entry allocation is mmaped */
|
||||
STORE_ENTRY_FLAG_MMAP = 2,
|
||||
/** entry allocation is in small object pool */
|
||||
STORE_ENTRY_FLAG_SMALL = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store index values refering to store entries. Care
|
||||
* must be taken with this type as it is used to build address to
|
||||
@ -103,20 +88,70 @@ typedef uint16_t entry_index_t;
|
||||
*/
|
||||
typedef uint32_t entry_ident_t;
|
||||
|
||||
/**
|
||||
* Entry extension index values.
|
||||
*/
|
||||
enum store_entry_elem_idx {
|
||||
ENTRY_ELEM_DATA = 0, /**< entry element is data */
|
||||
ENTRY_ELEM_META = 1, /**< entry element is metadata */
|
||||
ENTRY_ELEM_COUNT = 2, /**< count of elements on an entry */
|
||||
};
|
||||
|
||||
/**
|
||||
* flags that indicate what additional information is contained within
|
||||
* an entry element.
|
||||
*/
|
||||
enum store_entry_elem_flags {
|
||||
/** store not managing any allocation on entry */
|
||||
ENTRY_ELEM_FLAG_NONE = 0,
|
||||
/** entry data allocation is on heap */
|
||||
ENTRY_ELEM_FLAG_HEAP = 0x1,
|
||||
/** entry data allocation is mmaped */
|
||||
ENTRY_ELEM_FLAG_MMAP = 0x2,
|
||||
/** entry data allocation is in small object pool */
|
||||
ENTRY_ELEM_FLAG_SMALL = 0x4,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Backing store entry element.
|
||||
*
|
||||
* @note Order is important to avoid excessive structure packing overhead.
|
||||
*/
|
||||
struct store_entry_element {
|
||||
uint32_t size; /**< size of entry element on disc */
|
||||
union {
|
||||
struct {
|
||||
uint8_t* data; /**< data allocated on heap */
|
||||
uint8_t ref; /**< reference count */
|
||||
} heap;
|
||||
struct {
|
||||
uint8_t* data; /**< data is from an mmapping */
|
||||
uint8_t ref; /**< reference count */
|
||||
} map;
|
||||
struct {
|
||||
uint16_t block; /**< small object data block */
|
||||
} small;
|
||||
};
|
||||
uint8_t flags; /* extension flags */
|
||||
};
|
||||
|
||||
/**
|
||||
* Backing store object index entry.
|
||||
*
|
||||
* @note Order is important to avoid structure packing overhead.
|
||||
* An entry in the backing store contains two elements for the actual
|
||||
* data and the metadata. The two elements are treated identically for
|
||||
* storage lifetime but as a collective whole for expiration and
|
||||
* indexing.
|
||||
*
|
||||
* @note Order is important to avoid excessive structure packing overhead.
|
||||
*/
|
||||
struct store_entry {
|
||||
int64_t last_used; /**< unix time the entry was last used */
|
||||
entry_ident_t ident; /**< entry identifier */
|
||||
uint32_t data_alloc; /**< currently allocated size of data on disc */
|
||||
uint32_t meta_alloc; /**< currently allocated size of metadata on disc */
|
||||
uint16_t use_count; /**< number of times this entry has been accessed */
|
||||
uint16_t flags; /**< entry flags (unused) */
|
||||
uint16_t data_block; /**< small object data block entry (unused) */
|
||||
uint16_t meta_block; /**< small object meta block entry (unused) */
|
||||
/** Entry element (data or meta) specific information */
|
||||
struct store_entry_element elem[ENTRY_ELEM_COUNT];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -195,6 +230,18 @@ remove_store_entry(struct store_state *state,
|
||||
return NSERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* check if the entry has storage already allocated */
|
||||
if (((state->entries[sei].elem[ENTRY_ELEM_DATA].flags &
|
||||
(ENTRY_ELEM_FLAG_HEAP | ENTRY_ELEM_FLAG_MMAP)) != 0) ||
|
||||
((state->entries[sei].elem[ENTRY_ELEM_META].flags &
|
||||
(ENTRY_ELEM_FLAG_HEAP | ENTRY_ELEM_FLAG_MMAP)) != 0)) {
|
||||
/* this entry cannot be removed as it has associated
|
||||
* allocation.
|
||||
*/
|
||||
LOG(("attempt to remove entry with in use data"));
|
||||
return NSERROR_PERMISSION;
|
||||
}
|
||||
|
||||
/* sei is entry to be removed, we swap it to the end of the
|
||||
* table so there are no gaps and the returned entry is held
|
||||
* in storage with reasonable lifetime.
|
||||
@ -204,8 +251,8 @@ remove_store_entry(struct store_state *state,
|
||||
BS_ENTRY_INDEX(ident, state) = 0;
|
||||
|
||||
/* global allocation accounting */
|
||||
state->total_alloc -= state->entries[sei].data_alloc;
|
||||
state->total_alloc -= state->entries[sei].meta_alloc;
|
||||
state->total_alloc -= state->entries[sei].elem[ENTRY_ELEM_DATA].size;
|
||||
state->total_alloc -= state->entries[sei].elem[ENTRY_ELEM_META].size;
|
||||
|
||||
state->last_entry--;
|
||||
|
||||
@ -396,6 +443,26 @@ static int compar(const void *va, const void *vb)
|
||||
const struct store_entry *a = &BS_ENTRY(*(entry_ident_t *)va, storestate);
|
||||
const struct store_entry *b = &BS_ENTRY(*(entry_ident_t *)vb, storestate);
|
||||
|
||||
/* consider the allocation flags - if an entry has an
|
||||
* allocation it is considered more valuble as it cannot be
|
||||
* freed.
|
||||
*/
|
||||
if ((a->elem[ENTRY_ELEM_DATA].flags == ENTRY_ELEM_FLAG_NONE) &&
|
||||
(b->elem[ENTRY_ELEM_DATA].flags != ENTRY_ELEM_FLAG_NONE)) {
|
||||
return -1;
|
||||
} else if ((a->elem[ENTRY_ELEM_DATA].flags != ENTRY_ELEM_FLAG_NONE) &&
|
||||
(b->elem[ENTRY_ELEM_DATA].flags == ENTRY_ELEM_FLAG_NONE)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((a->elem[ENTRY_ELEM_META].flags == ENTRY_ELEM_FLAG_NONE) &&
|
||||
(b->elem[ENTRY_ELEM_META].flags != ENTRY_ELEM_FLAG_NONE)) {
|
||||
return -1;
|
||||
} else if ((a->elem[ENTRY_ELEM_META].flags != ENTRY_ELEM_FLAG_NONE) &&
|
||||
(b->elem[ENTRY_ELEM_META].flags == ENTRY_ELEM_FLAG_NONE)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a->use_count < b->use_count) {
|
||||
return -1;
|
||||
} else if (a->use_count > b->use_count) {
|
||||
@ -463,8 +530,8 @@ static nserror store_evict(struct store_state *state)
|
||||
removed = 0;
|
||||
for (ent = 0; ent < ent_count; ent++) {
|
||||
|
||||
removed += BS_ENTRY(elist[ent], state).data_alloc;
|
||||
removed += BS_ENTRY(elist[ent], state).meta_alloc;
|
||||
removed += BS_ENTRY(elist[ent], state).elem[ENTRY_ELEM_DATA].size;
|
||||
removed += BS_ENTRY(elist[ent], state).elem[ENTRY_ELEM_META].size;
|
||||
|
||||
ret = unlink_ident(state, elist[ent]);
|
||||
if (ret != NSERROR_OK) {
|
||||
@ -591,6 +658,7 @@ get_store_entry(struct store_state *state, nsurl *url, struct store_entry **bse)
|
||||
sei = BS_ENTRY_INDEX(ident, state);
|
||||
|
||||
if (sei == 0) {
|
||||
LOG(("Failed to find ident 0x%x in index", ident));
|
||||
return NSERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
@ -639,7 +707,7 @@ set_store_entry(struct store_state *state,
|
||||
entry_index_t sei; /* store entry index */
|
||||
struct store_entry *se;
|
||||
nserror ret;
|
||||
bool isrep; /* is the store repalcing an existing entry or not */
|
||||
struct store_entry_element *elem;
|
||||
|
||||
LOG(("url:%s", nsurl_access(url)));
|
||||
|
||||
@ -654,52 +722,59 @@ set_store_entry(struct store_state *state,
|
||||
/* use the url hash as the entry identifier */
|
||||
ident = nsurl_hash(url);
|
||||
|
||||
/* get the entry index from the ident */
|
||||
sei = BS_ENTRY_INDEX(ident, state);
|
||||
|
||||
/** @todo Should this deal with cache eviction? */
|
||||
|
||||
if (sei == 0) {
|
||||
/* allocating the next available entry */
|
||||
sei = state->last_entry;
|
||||
state->last_entry++;
|
||||
BS_ENTRY_INDEX(ident, state) = sei;
|
||||
isrep = false;
|
||||
} else {
|
||||
/* updating or replacing existing entry */
|
||||
/** @todo should we be checking the entry ident
|
||||
* matches the url. Thats a collision in the address
|
||||
* mapping right? and is it important?
|
||||
*/
|
||||
isrep = true;
|
||||
|
||||
/* clear the new entry */
|
||||
memset(&state->entries[sei], 0, sizeof(struct store_entry));
|
||||
}
|
||||
|
||||
/** @todo should we be checking the entry ident matches the
|
||||
* url. Thats a collision in the address mapping right? and is
|
||||
* it important?
|
||||
*/
|
||||
|
||||
/* the entry */
|
||||
se = &state->entries[sei];
|
||||
|
||||
/* the entry element */
|
||||
if ((flags & BACKING_STORE_META) != 0) {
|
||||
elem = &se->elem[ENTRY_ELEM_META];
|
||||
} else {
|
||||
elem = &se->elem[ENTRY_ELEM_DATA];
|
||||
}
|
||||
|
||||
/* check if the element has storage already allocated */
|
||||
if ((elem->flags & (ENTRY_ELEM_FLAG_HEAP | ENTRY_ELEM_FLAG_MMAP)) != 0) {
|
||||
/* this entry cannot be removed as it has associated
|
||||
* allocation.
|
||||
*/
|
||||
LOG(("attempt to remove entry with in use data"));
|
||||
return NSERROR_PERMISSION;
|
||||
}
|
||||
|
||||
/* set the common entry data */
|
||||
se->ident = ident;
|
||||
se->flags = STORE_ENTRY_FLAG_NONE;
|
||||
se->use_count = 1;
|
||||
se->last_used = time(NULL);
|
||||
|
||||
/* account for allocation */
|
||||
if ((flags & BACKING_STORE_META) != 0) {
|
||||
if (isrep) {
|
||||
state->total_alloc -= se->meta_alloc;
|
||||
} else {
|
||||
se->data_alloc = 0;
|
||||
}
|
||||
se->meta_alloc = datalen;
|
||||
} else {
|
||||
if (isrep) {
|
||||
state->total_alloc -= se->data_alloc;
|
||||
} else {
|
||||
se->meta_alloc = 0;
|
||||
}
|
||||
se->data_alloc = datalen;
|
||||
}
|
||||
state->total_alloc += datalen;
|
||||
/* store the data in the element */
|
||||
elem->flags |= ENTRY_ELEM_FLAG_HEAP;
|
||||
elem->heap.data = data;
|
||||
elem->heap.ref = 1;
|
||||
|
||||
/* account for size of entry element */
|
||||
state->total_alloc -= elem->size;
|
||||
elem->size = datalen;
|
||||
state->total_alloc += elem->size;
|
||||
|
||||
/* ensure control maintinance scheduled. */
|
||||
state->entries_dirty = true;
|
||||
|
||||
guit->browser->schedule(CONTROL_MAINT_TIME, control_maintinance, state);
|
||||
|
||||
*bse = se;
|
||||
@ -793,8 +868,8 @@ build_entrymap(struct store_state *state)
|
||||
BS_ENTRY_INDEX(state->entries[eloop].ident, state) = eloop;
|
||||
|
||||
/* account for the storage space */
|
||||
state->total_alloc += state->entries[eloop].data_alloc +
|
||||
state->entries[eloop].meta_alloc;
|
||||
state->total_alloc += state->entries[eloop].elem[ENTRY_ELEM_DATA].size;
|
||||
state->total_alloc += state->entries[eloop].elem[ENTRY_ELEM_META].size;
|
||||
}
|
||||
|
||||
return NSERROR_OK;
|
||||
@ -1113,7 +1188,7 @@ initialise(const struct llcache_store_parameters *parameters)
|
||||
LOG(("FS backing store init successful"));
|
||||
|
||||
LOG(("path:%s limit:%d hyst:%d addr:%d entries:%d", newstate->path, newstate->limit, newstate->hysteresis, newstate->ident_bits, newstate->entry_bits));
|
||||
LOG(("Using %d/%d", newstate->total_alloc, newstate->limit));
|
||||
LOG(("Using %lld/%lld", newstate->total_alloc, newstate->limit));
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
@ -1151,6 +1226,8 @@ finalise(void)
|
||||
/**
|
||||
* Place an object in the backing store.
|
||||
*
|
||||
* takes ownership of the heap block passed in.
|
||||
*
|
||||
* @param url The url is used as the unique primary key for the data.
|
||||
* @param flags The flags to control how the object is stored.
|
||||
* @param data The objects source data.
|
||||
@ -1200,6 +1277,22 @@ store(nsurl *url,
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* release any allocation for an entry
|
||||
*/
|
||||
static nserror entry_release_alloc(struct store_entry_element *elem)
|
||||
{
|
||||
if ((elem->flags & ENTRY_ELEM_FLAG_HEAP) != 0) {
|
||||
elem->heap.ref--;
|
||||
if (elem->heap.ref == 0) {
|
||||
LOG(("freeing %p", elem->heap.data));
|
||||
free(elem->heap.data);
|
||||
elem->flags &= ~ENTRY_ELEM_FLAG_HEAP;
|
||||
}
|
||||
}
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive an object from the backing store.
|
||||
*
|
||||
@ -1211,12 +1304,13 @@ store(nsurl *url,
|
||||
*/
|
||||
static nserror
|
||||
fetch(nsurl *url,
|
||||
enum backing_store_flags *flags,
|
||||
enum backing_store_flags bsflags,
|
||||
uint8_t **data_out,
|
||||
size_t *datalen_out)
|
||||
{
|
||||
nserror ret;
|
||||
struct store_entry *bse;
|
||||
struct store_entry_element *elem;
|
||||
uint8_t *data;
|
||||
size_t datalen;
|
||||
int fd;
|
||||
@ -1237,36 +1331,53 @@ fetch(nsurl *url,
|
||||
|
||||
LOG(("retriving cache file for url:%s", nsurl_access(url)));
|
||||
|
||||
fd = store_open(storestate, bse->ident, *flags, O_RDONLY);
|
||||
fd = store_open(storestate, bse->ident, bsflags, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
LOG(("Open failed"));
|
||||
/** @todo should this invalidate the entry? */
|
||||
return NSERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* the entry element */
|
||||
if ((bsflags & BACKING_STORE_META) != 0) {
|
||||
elem = &bse->elem[ENTRY_ELEM_META];
|
||||
} else {
|
||||
elem = &bse->elem[ENTRY_ELEM_DATA];
|
||||
}
|
||||
|
||||
data = *data_out;
|
||||
datalen = *datalen_out;
|
||||
/** @todo should this check datalen is sufficient? */
|
||||
|
||||
/* need to deal with buffers */
|
||||
if (data == NULL) {
|
||||
if (datalen == 0) {
|
||||
/* caller did not know the files length */
|
||||
if (((*flags) & BACKING_STORE_META) != 0) {
|
||||
datalen = bse->meta_alloc;
|
||||
} else {
|
||||
datalen = bse->data_alloc;
|
||||
if ((elem->flags & ENTRY_ELEM_FLAG_HEAP) != 0) {
|
||||
/* a heap allocation already exists. Return
|
||||
* that allocation and bump our ref count.
|
||||
*/
|
||||
data = elem->heap.data;
|
||||
elem->heap.ref++;
|
||||
datalen = elem->size;
|
||||
LOG(("Using existing heap allocation %p", elem->heap.data));
|
||||
} else {
|
||||
datalen = elem->size;
|
||||
data = malloc(elem->size);
|
||||
if (data == NULL) {
|
||||
close(fd);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
data = malloc(datalen);
|
||||
if (data == NULL) {
|
||||
close(fd);
|
||||
return NSERROR_NOMEM;
|
||||
/* store allocated buffer so track ownership */
|
||||
elem->flags |= ENTRY_ELEM_FLAG_HEAP;
|
||||
elem->heap.data = data;
|
||||
elem->heap.ref = 1;
|
||||
LOG(("Creating new heap allocation %p", elem->heap.data));
|
||||
}
|
||||
} else if (datalen == 0) {
|
||||
/* caller provided a buffer but no length bad parameter */
|
||||
return NSERROR_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
/** @todo should this check datalen is sufficient */
|
||||
|
||||
LOG(("Reading %d bytes into %p from file", datalen, data));
|
||||
|
||||
/** @todo this read should be an a loop */
|
||||
@ -1275,7 +1386,7 @@ fetch(nsurl *url,
|
||||
LOG(("read returned %d", rd));
|
||||
close(fd);
|
||||
if ((*data_out) == NULL) {
|
||||
free(data);
|
||||
entry_release_alloc(elem);
|
||||
}
|
||||
return NSERROR_NOT_FOUND;
|
||||
}
|
||||
@ -1291,6 +1402,41 @@ fetch(nsurl *url,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* release a previously fetched or stored memory object.
|
||||
*
|
||||
* @param url The url is used as the unique primary key to invalidate.
|
||||
* @param[in] flags The flags to control how the object data is released.
|
||||
* @return NSERROR_OK on success or error code on faliure.
|
||||
*/
|
||||
static nserror release(nsurl *url, enum backing_store_flags bsflags)
|
||||
{
|
||||
nserror ret;
|
||||
struct store_entry *bse;
|
||||
struct store_entry_element *elem;
|
||||
|
||||
/* check backing store is initialised */
|
||||
if (storestate == NULL) {
|
||||
return NSERROR_INIT_FAILED;
|
||||
}
|
||||
|
||||
ret = get_store_entry(storestate, url, &bse);
|
||||
if (ret != NSERROR_OK) {
|
||||
LOG(("entry not found"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* the entry element */
|
||||
if ((bsflags & BACKING_STORE_META) != 0) {
|
||||
elem = &bse->elem[ENTRY_ELEM_META];
|
||||
} else {
|
||||
elem = &bse->elem[ENTRY_ELEM_DATA];
|
||||
}
|
||||
|
||||
return entry_release_alloc(elem);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalidate a source object from the backing store.
|
||||
*
|
||||
@ -1314,23 +1460,6 @@ invalidate(nsurl *url)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* release a previously fetched or stored memory object.
|
||||
*
|
||||
* if the BACKING_STORE_ALLOC flag was used with the fetch or
|
||||
* store operation for this url the returned storage is
|
||||
* unreferenced. When the reference count drops to zero the
|
||||
* storage is released.
|
||||
*
|
||||
* @param url The url is used as the unique primary key to invalidate.
|
||||
* @param[in] flags The flags to control how the object data is released.
|
||||
* @return NSERROR_OK on success or error code on faliure.
|
||||
*/
|
||||
static nserror release(nsurl *url, enum backing_store_flags flags)
|
||||
{
|
||||
return NSERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static struct gui_llcache_table llcache_table = {
|
||||
.initialise = initialise,
|
||||
.finalise = finalise,
|
||||
|
@ -150,7 +150,6 @@ typedef struct {
|
||||
/** Current status of objects data */
|
||||
typedef enum {
|
||||
LLCACHE_STATE_RAM = 0, /**< source data is stored in RAM only */
|
||||
LLCACHE_STATE_MMAP, /**< source data is mmaped (implies on disc too) */
|
||||
LLCACHE_STATE_DISC, /**< source data is stored on disc */
|
||||
} llcache_store_state;
|
||||
|
||||
@ -1076,8 +1075,6 @@ llcache_object_remove_from_list(llcache_object *object, llcache_object **list)
|
||||
*/
|
||||
static nserror llcache_persist_retrieve(llcache_object *object)
|
||||
{
|
||||
enum backing_store_flags flags = BACKING_STORE_NONE;
|
||||
|
||||
/* ensure the source data is present if necessary */
|
||||
if ((object->source_data != NULL) ||
|
||||
(object->store_state != LLCACHE_STATE_DISC)) {
|
||||
@ -1089,7 +1086,7 @@ static nserror llcache_persist_retrieve(llcache_object *object)
|
||||
|
||||
/* Source data for the object may be in the persiatant store */
|
||||
return guit->llcache->fetch(object->url,
|
||||
&flags,
|
||||
BACKING_STORE_NONE,
|
||||
&object->source_data,
|
||||
&object->source_len);
|
||||
}
|
||||
@ -1246,13 +1243,12 @@ llcache_process_metadata(llcache_object *object)
|
||||
int lnsize;
|
||||
size_t num_headers;
|
||||
size_t hloop;
|
||||
enum backing_store_flags flags = BACKING_STORE_META;
|
||||
|
||||
LOG(("Retriving metadata"));
|
||||
|
||||
/* attempt to retrieve object metadata from the backing store */
|
||||
res = guit->llcache->fetch(object->url,
|
||||
&flags,
|
||||
BACKING_STORE_META,
|
||||
&metadata,
|
||||
&metadatalen);
|
||||
if (res != NSERROR_OK) {
|
||||
@ -1273,14 +1269,14 @@ llcache_process_metadata(llcache_object *object)
|
||||
|
||||
res = nsurl_create(ln, &metadataurl);
|
||||
if (res != NSERROR_OK) {
|
||||
free(metadata);
|
||||
guit->llcache->release(object->url, BACKING_STORE_META);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (nsurl_compare(object->url, metadataurl, NSURL_COMPLETE) != true) {
|
||||
/* backing store returned the wrong object for the
|
||||
* request. This may occour if the backing store had
|
||||
* a collision in its stoage method. We cope with this
|
||||
* a collision in its storage method. We cope with this
|
||||
* by simply skipping caching of this object.
|
||||
*/
|
||||
|
||||
@ -1290,7 +1286,7 @@ llcache_process_metadata(llcache_object *object)
|
||||
|
||||
nsurl_unref(metadataurl);
|
||||
|
||||
free(metadata);
|
||||
guit->llcache->release(object->url, BACKING_STORE_META);
|
||||
|
||||
return NSERROR_BAD_URL;
|
||||
}
|
||||
@ -1349,12 +1345,12 @@ llcache_process_metadata(llcache_object *object)
|
||||
|
||||
res = llcache_fetch_process_header(object, (uint8_t *)ln, lnsize);
|
||||
if (res != NSERROR_OK) {
|
||||
free(metadata);
|
||||
guit->llcache->release(object->url, BACKING_STORE_META);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
free(metadata);
|
||||
guit->llcache->release(object->url, BACKING_STORE_META);
|
||||
|
||||
/* object stored in backing store */
|
||||
object->store_state = LLCACHE_STATE_DISC;
|
||||
@ -1363,7 +1359,8 @@ llcache_process_metadata(llcache_object *object)
|
||||
|
||||
format_error:
|
||||
LOG(("metadata error on line %d\n", line));
|
||||
free(metadata);
|
||||
guit->llcache->release(object->url, BACKING_STORE_META);
|
||||
|
||||
return NSERROR_INVALID;
|
||||
|
||||
}
|
||||
@ -1454,7 +1451,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
|
||||
* pull from persistant store.
|
||||
*/
|
||||
if (newest == NULL) {
|
||||
LLCACHE_LOG(("No viable object found in cache"));
|
||||
LLCACHE_LOG(("No viable object found in llcache"));
|
||||
|
||||
error = llcache_object_new(url, &obj);
|
||||
if (error != NSERROR_OK)
|
||||
@ -1498,7 +1495,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
|
||||
|
||||
/* retrival of source data from persistant store
|
||||
* failed, destroy cache object and fall though to
|
||||
* cache miss to re-retch
|
||||
* cache miss to re-fetch
|
||||
*/
|
||||
LLCACHE_LOG(("Persistant retrival failed for %p", newest));
|
||||
|
||||
@ -2255,7 +2252,7 @@ write_backing_store(struct llcache_object *object, size_t *written_out)
|
||||
BACKING_STORE_META,
|
||||
metadata,
|
||||
metadatasize);
|
||||
free(metadata);
|
||||
guit->llcache->release(object->url, BACKING_STORE_META);
|
||||
if (ret != NSERROR_OK) {
|
||||
/* There has been an error putting the metadata in the
|
||||
* backing store. Ensure the data object is invalidated.
|
||||
@ -2903,7 +2900,7 @@ void llcache_clean(bool purge)
|
||||
(object->fetch.fetch == NULL) &&
|
||||
(object->fetch.outstanding_query == false) &&
|
||||
(remaining_lifetime <= 0)) {
|
||||
/* object is stale */
|
||||
/* object is stale */
|
||||
LLCACHE_LOG(("discarding stale cacheable object with no users or pending fetches (%p) %s", object, nsurl_access(object->url)));
|
||||
|
||||
llcache_object_remove_from_list(object,
|
||||
@ -2942,7 +2939,8 @@ void llcache_clean(bool purge)
|
||||
(object->fetch.fetch == NULL) &&
|
||||
(object->fetch.outstanding_query == false) &&
|
||||
(object->store_state == LLCACHE_STATE_DISC)) {
|
||||
free(object->source_data);
|
||||
guit->llcache->release(object->url, BACKING_STORE_NONE);
|
||||
|
||||
object->source_data = NULL;
|
||||
|
||||
llcache_size -= object->source_len;
|
||||
@ -2955,7 +2953,7 @@ void llcache_clean(bool purge)
|
||||
|
||||
/* Fresh cacheable objects with no users, no pending fetches
|
||||
* and pushed to persistant store while the cache exceeds
|
||||
* the configured size. Efectively just the object metadata.
|
||||
* the configured size. Efectively just the llcache object metadata.
|
||||
*/
|
||||
for (object = llcache->cached_objects;
|
||||
((limit < llcache_size) && (object != NULL));
|
||||
@ -2983,7 +2981,7 @@ void llcache_clean(bool purge)
|
||||
}
|
||||
|
||||
/* Fresh cacheable objects with no users or pending fetches
|
||||
* while the cache exceeds the configured size. These are the
|
||||
* while the cache exceeds the configured size. These are the
|
||||
* most valuble objects as replacing them is a full network
|
||||
* fetch
|
||||
*/
|
||||
|
@ -45,7 +45,7 @@ static nserror store(nsurl *url,
|
||||
}
|
||||
|
||||
static nserror fetch(nsurl *url,
|
||||
enum backing_store_flags *flags,
|
||||
enum backing_store_flags flags,
|
||||
uint8_t **data_out,
|
||||
size_t *datalen_out)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user