static PyObject * range_item(rangeobject *r, Py_ssize_t i) { Py_ssize_t len = range_length(r); PyObject *rem, *incr, *result; /* XXX(nnorwitz): should negative indices be supported? */ /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */ if (i < 0 || i >= len) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_IndexError, "range object index out of range"); return NULL; } /* XXX(nnorwitz): optimize for short ints. */ rem = PyLong_FromSsize_t(i); if (!rem) return NULL; incr = PyNumber_Multiply(rem, r->step); Py_DECREF(rem); if (!incr) return NULL; result = PyNumber_Add(r->start, incr); Py_DECREF(incr); return result; }
static void clean_cpu_cache(struct cach_buf *buf, struct cach_range *range) { struct cach_range intersection; intersect_range(&buf->range_dirty_in_cpu_cache, range, &intersection); if (is_non_empty_range(&intersection)) { bool cleaned_everything; expand_range_2_edge(&intersection, &buf->range_dirty_in_cpu_cache); clean_cpu_dcache( offset_2_vaddr(buf, intersection.start), offset_2_paddr(buf, intersection.start), range_length(&intersection), buf->cache_settings & HWMEM_ALLOC_HINT_INNER_CACHE_ONLY, &cleaned_everything); if (cleaned_everything) null_range(&buf->range_dirty_in_cpu_cache); else shrink_range(&buf->range_dirty_in_cpu_cache, &intersection); } }
static void flush_cpu_cache(struct cach_buf *buf, struct cach_range *range) { struct cach_range intersection; intersect_range(&buf->range_in_cpu_cache, range, &intersection); if (is_non_empty_range(&intersection)) { bool flushed_everything; expand_range_2_edge(&intersection, &buf->range_in_cpu_cache); flush_cpu_dcache( offset_2_vaddr(buf, intersection.start), offset_2_paddr(buf, intersection.start), range_length(&intersection), buf->cache_settings & HWMEM_ALLOC_HINT_INNER_CACHE_ONLY, &flushed_everything); if (flushed_everything) { if (!speculative_data_prefetch()) null_range(&buf->range_in_cpu_cache); null_range(&buf->range_dirty_in_cpu_cache); null_range(&buf->range_invalid_in_cpu_cache); } else { if (!speculative_data_prefetch()) shrink_range(&buf->range_in_cpu_cache, &intersection); shrink_range(&buf->range_dirty_in_cpu_cache, &intersection); shrink_range(&buf->range_invalid_in_cpu_cache, &intersection); } } }
guint64 cache_mng_get_file_length (CacheMng *cmng, fuse_ino_t ino) { struct _CacheEntry *entry; entry = g_hash_table_lookup (cmng->h_entries, GUINT_TO_POINTER (ino)); if (!entry) return 0; return range_length (entry->avail_range); }
// removes file from local storage void cache_mng_remove_file (CacheMng *cmng, fuse_ino_t ino) { struct _CacheEntry *entry; char path[PATH_MAX]; entry = g_hash_table_lookup (cmng->h_entries, GUINT_TO_POINTER (ino)); if (entry) { cmng->size -= range_length (entry->avail_range); g_queue_delete_link (cmng->q_lru, entry->ll_lru); g_hash_table_remove (cmng->h_entries, GUINT_TO_POINTER (ino)); cache_mng_file_name (cmng, path, sizeof (path), ino); unlink (path); LOG_debug (CMNG_LOG, INO_H"Entry is removed", INO_T (ino)); } else { LOG_debug (CMNG_LOG, INO_H"Entry not found", INO_T (ino)); } }
/*{{{ get_stats*/ void cache_mng_get_stats (CacheMng *cmng, guint32 *entries_num, guint64 *total_size, guint64 *cache_hits, guint64 *cache_miss) { GHashTableIter iter; struct _CacheEntry *entry; gpointer value; *entries_num = g_hash_table_size (cmng->h_entries); *cache_hits = cmng->cache_hits; *cache_miss = cmng->cache_miss; *total_size = 0; g_hash_table_iter_init (&iter, cmng->h_entries); while (g_hash_table_iter_next (&iter, NULL, &value)) { entry = (struct _CacheEntry *) value; *total_size = *total_size + range_length (entry->avail_range); } }/*}}}*/
static void invalidate_cpu_cache(struct cach_buf *buf, struct cach_range *range) { struct cach_range intersection; intersect_range(&buf->range_invalid_in_cpu_cache, range, &intersection); if (is_non_empty_range(&intersection)) { bool flushed_everything; expand_range_2_edge(&intersection, &buf->range_invalid_in_cpu_cache); /* * Cache handler never uses invalidate to discard data in the * cache so we can use flush instead which is considerably * faster for large buffers. */ flush_cpu_dcache( offset_2_vaddr(buf, intersection.start), offset_2_paddr(buf, intersection.start), range_length(&intersection), buf->cache_settings & HWMEM_ALLOC_HINT_INNER_CACHE_ONLY, &flushed_everything); if (flushed_everything) { null_range(&buf->range_invalid_in_cpu_cache); null_range(&buf->range_dirty_in_cpu_cache); } else { /* * No need to shrink range_in_cpu_cache as invalidate * is only used when we can't keep track of what's in * the CPU cache. */ shrink_range(&buf->range_invalid_in_cpu_cache, &intersection); } } }
// store file buffer into local storage // if success == TRUE then "buf" successfuly stored on disc void cache_mng_store_file_buf (CacheMng *cmng, fuse_ino_t ino, size_t size, off_t off, unsigned char *buf, cache_mng_on_store_file_buf_cb on_store_file_buf_cb, void *ctx) { struct _CacheContext *context; struct _CacheEntry *entry; ssize_t res; int fd; char path[PATH_MAX]; guint64 old_length, new_length; guint64 range_size; time_t now; range_size = (guint64)(off + size); // limit the number of cache checks now = time (NULL); if (cmng->check_time < now && now - cmng->check_time >= 10) { // remove data until we have at least size bytes of max_size left while (cmng->max_size < cmng->size + size && g_queue_peek_tail (cmng->q_lru)) { entry = (struct _CacheEntry *) g_queue_peek_tail (cmng->q_lru); cache_mng_remove_file (cmng, entry->ino); } cmng->check_time = now; } context = cache_context_create (size, ctx); context->cb.store_cb = on_store_file_buf_cb; cache_mng_file_name (cmng, path, sizeof (path), ino); fd = open (path, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { LOG_err (CMNG_LOG, INO_H"Failed to create / open file for writing! Path: %s", INO_T (ino), path); if (context->cb.store_cb) context->cb.store_cb (FALSE, context->user_ctx); cache_context_destroy (context); return; } res = pwrite(fd, buf, size, off); close (fd); entry = g_hash_table_lookup (cmng->h_entries, GUINT_TO_POINTER (ino)); if (!entry) { entry = cache_entry_create (ino); g_queue_push_head (cmng->q_lru, entry); entry->ll_lru = g_queue_peek_head_link (cmng->q_lru); g_hash_table_insert (cmng->h_entries, GUINT_TO_POINTER (ino), entry); } old_length = range_length (entry->avail_range); range_add (entry->avail_range, off, range_size); new_length = range_length (entry->avail_range); if (new_length >= old_length) cmng->size += new_length - old_length; else { LOG_err (CMNG_LOG, INO_H"New length is less than the old length !: %"G_GUINT64_FORMAT" <= %"G_GUINT64_FORMAT, INO_T (ino), new_length, old_length); } // update modification time entry->modification_time = time (NULL); context->success = (res == (ssize_t) size); LOG_debug (CMNG_LOG, INO_H"Written [%"OFF_FMT":%zu] bytes, result: %s", INO_T (ino), off, size, context->success ? "OK" : "Failed"); context->ev = event_new (application_get_evbase (cmng->app), -1, 0, cache_write_cb, context); // fire this event at once event_active (context->ev, 0, 0); event_add (context->ev, NULL); }