Start work on disk cache
This commit is contained in:
parent
e2d61ab5be
commit
3162d391cc
@ -25,8 +25,7 @@ from .config import (
|
||||
)
|
||||
from .config_data import MINIMUM_FONT_SIZE
|
||||
from .constants import (
|
||||
appname, cache_dir, config_dir, is_macos, kitty_exe,
|
||||
supports_primary_selection
|
||||
appname, config_dir, is_macos, kitty_exe, supports_primary_selection
|
||||
)
|
||||
from .fast_data_types import (
|
||||
CLOSE_BEING_CONFIRMED, IMPERATIVE_CLOSE_REQUESTED, NO_CLOSE_REQUESTED,
|
||||
@ -1380,10 +1379,6 @@ class Boss:
|
||||
with suppress(FileNotFoundError):
|
||||
os.remove(path)
|
||||
|
||||
def create_temp_dir_in_cache(self, prefix: Optional[str] = None, suffix: Optional[str] = None) -> str:
|
||||
from tempfile import mkdtemp
|
||||
return mkdtemp(prefix=prefix, suffix=suffix, dir=cache_dir())
|
||||
|
||||
def set_update_check_process(self, process: Optional[PopenType] = None) -> None:
|
||||
if self.update_check_process is not None:
|
||||
with suppress(Exception):
|
||||
|
||||
@ -128,6 +128,9 @@ defconf = os.path.join(config_dir, 'kitty.conf')
|
||||
|
||||
@lru_cache(maxsize=2)
|
||||
def cache_dir() -> str:
|
||||
override: Optional[str] = getattr(cache_dir, 'override_dir', None)
|
||||
if override:
|
||||
return override
|
||||
if 'KITTY_CACHE_DIRECTORY' in os.environ:
|
||||
candidate = os.path.abspath(os.environ['KITTY_CACHE_DIRECTORY'])
|
||||
elif is_macos:
|
||||
@ -139,6 +142,13 @@ def cache_dir() -> str:
|
||||
return candidate
|
||||
|
||||
|
||||
def dir_for_disk_cache() -> str:
|
||||
from tempfile import mkdtemp
|
||||
ans = os.path.join(cache_dir(), 'disk-cache')
|
||||
os.makedirs(ans, exist_ok=True)
|
||||
return mkdtemp(dir=ans)
|
||||
|
||||
|
||||
def wakeup() -> None:
|
||||
from .fast_data_types import get_boss
|
||||
b = get_boss()
|
||||
|
||||
@ -192,6 +192,7 @@ static struct PyModuleDef module = {
|
||||
extern int init_LineBuf(PyObject *);
|
||||
extern int init_HistoryBuf(PyObject *);
|
||||
extern int init_Cursor(PyObject *);
|
||||
extern int init_DiskCache(PyObject *);
|
||||
extern bool init_child_monitor(PyObject *);
|
||||
extern int init_Line(PyObject *);
|
||||
extern int init_ColorProfile(PyObject *);
|
||||
@ -231,6 +232,7 @@ PyInit_fast_data_types(void) {
|
||||
if (!init_HistoryBuf(m)) return NULL;
|
||||
if (!init_Line(m)) return NULL;
|
||||
if (!init_Cursor(m)) return NULL;
|
||||
if (!init_DiskCache(m)) return NULL;
|
||||
if (!init_child_monitor(m)) return NULL;
|
||||
if (!init_ColorProfile(m)) return NULL;
|
||||
if (!init_Screen(m)) return NULL;
|
||||
|
||||
146
kitty/disk-cache.c
Normal file
146
kitty/disk-cache.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* disk-cache.c
|
||||
* Copyright (C) 2020 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "disk-cache.h"
|
||||
#include "state.h"
|
||||
#include "loop-utils.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
char *path;
|
||||
pthread_mutex_t lock;
|
||||
pthread_t write_thread;
|
||||
bool thread_started, lock_inited, loop_data_inited, shutting_down, fully_initialized;
|
||||
LoopData loop_data;
|
||||
PyObject *rmtree;
|
||||
} DiskCache;
|
||||
|
||||
#define mutex(op) pthread_mutex_##op(&self->lock)
|
||||
|
||||
static PyObject*
|
||||
new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
||||
DiskCache *self;
|
||||
self = (DiskCache*)type->tp_alloc(type, 0);
|
||||
if (self) {
|
||||
PyObject *shutil = PyImport_ImportModule("shutil");
|
||||
if (!shutil) { Py_CLEAR(self); return NULL; }
|
||||
self->rmtree = PyObject_GetAttrString(shutil, "rmtree");
|
||||
Py_CLEAR(shutil);
|
||||
if (!self->rmtree) { Py_CLEAR(self); return NULL; }
|
||||
}
|
||||
return (PyObject*) self;
|
||||
}
|
||||
|
||||
static void*
|
||||
write_loop(void *data) {
|
||||
DiskCache *self = (DiskCache*)data;
|
||||
while (!self->shutting_down) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
ensure_state(DiskCache *self) {
|
||||
int ret;
|
||||
if (self->fully_initialized) return true;
|
||||
if (!self->loop_data_inited) {
|
||||
if (!init_loop_data(&self->loop_data)) { PyErr_SetFromErrno(PyExc_OSError); return false; }
|
||||
self->loop_data_inited = true;
|
||||
}
|
||||
|
||||
if (!self->lock_inited) {
|
||||
if ((ret = pthread_mutex_init(&self->lock, NULL)) != 0) {
|
||||
PyErr_Format(PyExc_OSError, "Failed to create disk cache lock mutex: %s", strerror(ret));
|
||||
return false;
|
||||
}
|
||||
self->lock_inited = true;
|
||||
}
|
||||
|
||||
if (!self->thread_started) {
|
||||
if ((ret = pthread_create(&self->write_thread, NULL, write_loop, self)) != 0) {
|
||||
PyErr_Format(PyExc_OSError, "Failed to start disk cache write thread with error: %s", strerror(ret));
|
||||
return false;
|
||||
}
|
||||
self->thread_started = true;
|
||||
}
|
||||
|
||||
if (!self->path) {
|
||||
PyObject *kc = NULL, *cache_dir = NULL;
|
||||
kc = PyImport_ImportModule("kitty.constants");
|
||||
if (kc) {
|
||||
cache_dir = PyObject_CallMethod(kc, "dir_for_disk_cache", NULL);
|
||||
if (cache_dir) {
|
||||
self->path = strdup(PyUnicode_AsUTF8(cache_dir));
|
||||
if (!self->path) PyErr_NoMemory();
|
||||
}
|
||||
}
|
||||
Py_CLEAR(kc); Py_CLEAR(cache_dir);
|
||||
if (PyErr_Occurred()) return false;
|
||||
}
|
||||
|
||||
self->fully_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
wakeup_write_loop(DiskCache *self) {
|
||||
if (self->thread_started) wakeup_loop(&self->loop_data, false, "disk_cache_write_loop");
|
||||
}
|
||||
|
||||
static void
|
||||
dealloc(DiskCache* self) {
|
||||
self->shutting_down = true;
|
||||
if (self->thread_started) {
|
||||
wakeup_write_loop(self);
|
||||
pthread_join(self->write_thread, NULL);
|
||||
self->thread_started = false;
|
||||
}
|
||||
if (self->lock_inited) {
|
||||
pthread_mutex_destroy(&self->lock);
|
||||
self->lock_inited = false;
|
||||
}
|
||||
if (self->loop_data_inited) {
|
||||
free_loop_data(&self->loop_data);
|
||||
self->loop_data_inited = false;
|
||||
}
|
||||
|
||||
if (self->path) {
|
||||
PyObject_CallFunction(self->rmtree, "sO", self->path, Py_True);
|
||||
free(self->path); self->path = NULL;
|
||||
}
|
||||
Py_CLEAR(self->rmtree);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
#define PYWRAP0(name) static PyObject* py##name(DiskCache *self, PyObject *args UNUSED)
|
||||
PYWRAP0(ensure_state) {
|
||||
ensure_state(self);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#define MW(name, arg_type) {#name, (PyCFunction)py##name, arg_type, NULL}
|
||||
static PyMethodDef methods[] = {
|
||||
MW(ensure_state, METH_NOARGS),
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject DiskCache_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.DiskCache",
|
||||
.tp_basicsize = sizeof(DiskCache),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "A disk based secure cache",
|
||||
.tp_methods = methods,
|
||||
.tp_new = new,
|
||||
};
|
||||
|
||||
|
||||
INIT_TYPE(DiskCache)
|
||||
PyObject* create_disk_cache(void) { return new(&DiskCache_Type, NULL, NULL); }
|
||||
11
kitty/disk-cache.h
Normal file
11
kitty/disk-cache.h
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
PyObject* create_disk_cache(void);
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "graphics.h"
|
||||
#include "state.h"
|
||||
#include "disk-cache.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@ -36,6 +37,8 @@ grman_alloc() {
|
||||
PyErr_NoMemory();
|
||||
Py_CLEAR(self); return NULL;
|
||||
}
|
||||
self->disk_cache = create_disk_cache();
|
||||
if (!self->disk_cache) { Py_CLEAR(self); return NULL; }
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -71,6 +74,7 @@ dealloc(GraphicsManager* self) {
|
||||
free(self->images);
|
||||
}
|
||||
free(self->render_data);
|
||||
Py_CLEAR(self->disk_cache);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
|
||||
@ -84,6 +84,7 @@ typedef struct {
|
||||
size_t num_of_below_refs, num_of_negative_refs, num_of_positive_refs;
|
||||
unsigned int last_scrolled_by;
|
||||
size_t used_storage;
|
||||
PyObject *disk_cache;
|
||||
} GraphicsManager;
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user