From 4bf8b0a2e9db842283e9e3849e8d23573ba3b181 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 29 Jul 2023 15:57:44 +0800 Subject: [PATCH] Update Android port * java/org/gnu/emacs/EmacsSafThread.java (postInvalidateCache): New argument cacheName. Remove that file from the cache. (accessDocument1): Consult the storage cache as well. * java/org/gnu/emacs/EmacsService.java (deleteDocument): New argument NAME. * src/android.c (android_init_emacs_service): Add new argument. * src/androidvfs.c (android_saf_delete_document) (android_saf_tree_rmdir, android_saf_file_unlink): Pass name of file being deleted to `deleteDocument'. --- java/org/gnu/emacs/EmacsSafThread.java | 71 +++++++++++++++++++++++--- java/org/gnu/emacs/EmacsService.java | 9 ++-- src/android.c | 3 +- src/androidvfs.c | 31 ++++++++--- 4 files changed, 96 insertions(+), 18 deletions(-) diff --git a/java/org/gnu/emacs/EmacsSafThread.java b/java/org/gnu/emacs/EmacsSafThread.java index cf067adc87b..cb69df01bfb 100644 --- a/java/org/gnu/emacs/EmacsSafThread.java +++ b/java/org/gnu/emacs/EmacsSafThread.java @@ -478,14 +478,12 @@ public final class EmacsSafThread extends HandlerThread document tree URI. Call this after deleting a document or directory. - Caveat emptor: this does not remove the component name cache - entries linked to the name(s) of the directory being removed, the - assumption being that the next time `documentIdFromName1' is - called, it will notice that the document is missing and remove - the outdated cache entry. */ + At the same time, remove the final component within the file name + CACHENAME from the cache if it exists. */ public void - postInvalidateCache (final Uri uri, final String documentId) + postInvalidateCache (final Uri uri, final String documentId, + final String cacheName) { handler.post (new Runnable () { @Override @@ -493,9 +491,55 @@ public final class EmacsSafThread extends HandlerThread run () { CacheToplevel toplevel; + HashMap children; + String[] components; + CacheEntry entry; + DocIdEntry idEntry; toplevel = getCache (uri); toplevel.idCache.remove (documentId); + + /* If the parent of CACHENAME is cached, remove it. */ + + children = toplevel.children; + components = cacheName.split ("/"); + + for (String component : components) + { + /* Java `split' removes trailing empty matches but not + leading or intermediary ones. */ + if (component.isEmpty ()) + continue; + + if (component == components[components.length - 1]) + { + /* This is the last component, so remove it from + children. */ + children.remove (component); + return; + } + else + { + /* Search for this component within the last level + of the cache. */ + + idEntry = children.get (component); + + if (idEntry == null) + /* Not cached, so return. */ + return; + + entry = toplevel.idCache.get (idEntry.documentId); + + if (entry == null) + /* Not cached, so return. */ + return; + + /* Locate the next component within this + directory. */ + children = entry.children; + } + } } }); } @@ -1109,12 +1153,27 @@ public final class EmacsSafThread extends HandlerThread int tem, index; String tem1; Cursor cursor; + CacheToplevel toplevel; + CacheEntry entry; uriObject = Uri.parse (uri); if (documentId == null) documentId = DocumentsContract.getTreeDocumentId (uriObject); + /* If WRITABLE is false and the document ID is cached, use its + cached value instead. This speeds up + `directory-files-with-attributes' a little. */ + + if (!writable) + { + toplevel = getCache (uriObject); + entry = toplevel.idCache.get (documentId); + + if (entry != null) + return 0; + } + /* Create a document URI representing DOCUMENTID within URI's authority. */ diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index e2abd6c96ef..5186dec974a 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java @@ -1674,10 +1674,13 @@ public final class EmacsService extends Service /* Delete the document identified by ID from the document tree identified by URI. Return 0 upon success and -1 upon - failure. */ + failure. + + NAME should be the name of the document being deleted, and is + used to invalidate the cache. */ public int - deleteDocument (String uri, String id) + deleteDocument (String uri, String id, String name) throws FileNotFoundException { Uri uriObject, tree; @@ -1688,7 +1691,7 @@ public final class EmacsService extends Service if (DocumentsContract.deleteDocument (resolver, uriObject)) { if (storageThread != null) - storageThread.postInvalidateCache (tree, id); + storageThread.postInvalidateCache (tree, id, name); return 0; } diff --git a/src/android.c b/src/android.c index 687c0b48a2a..a75193e5edd 100644 --- a/src/android.c +++ b/src/android.c @@ -1581,7 +1581,8 @@ android_init_emacs_service (void) "(Ljava/lang/String;Ljava/lang/String;" "Ljava/lang/String;)Ljava/lang/String;"); FIND_METHOD (delete_document, "deleteDocument", - "(Ljava/lang/String;Ljava/lang/String;)I"); + "(Ljava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;)I"); #undef FIND_METHOD } diff --git a/src/androidvfs.c b/src/androidvfs.c index b175f7746f3..6c34aac9e3e 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -3969,34 +3969,45 @@ android_saf_access (const char *uri_name, const char *id_name, /* Delete the document designated by DOC_ID within the tree identified through the URI TREE. Return 0 if the document has been deleted, - set errno and return -1 upon failure. */ + set errno and return -1 upon failure. + + DOC_NAME should be the name of the file itself, as a file name + whose constituent components lead to a document named DOC_ID. It + isn't used to search for a document ID, but is used to invalidate + the file cache. */ static int -android_saf_delete_document (const char *tree, const char *doc_id) +android_saf_delete_document (const char *tree, const char *doc_id, + const char *doc_name) { - jobject id, uri; + jobject id, uri, name; jmethodID method; jint rc; - /* Build the strings holding the ID and URI. */ + /* Build the strings holding the ID, URI and NAME. */ id = (*android_java_env)->NewStringUTF (android_java_env, doc_id); android_exception_check (); uri = (*android_java_env)->NewStringUTF (android_java_env, tree); android_exception_check_1 (id); + name = (*android_java_env)->NewStringUTF (android_java_env, + doc_name); + android_exception_check_2 (id, name); /* Now, try to delete the document. */ method = service_class.delete_document; rc = (*android_java_env)->CallIntMethod (android_java_env, emacs_service, - method, uri, id); + method, uri, id, + name); - if (android_saf_exception_check (2, id, uri)) + if (android_saf_exception_check (3, id, uri, name)) return -1; ANDROID_DELETE_LOCAL_REF (id); ANDROID_DELETE_LOCAL_REF (uri); + ANDROID_DELETE_LOCAL_REF (name); if (rc) { @@ -4553,7 +4564,9 @@ android_saf_tree_rmdir (struct android_vnode *vnode) return -1; } - return android_saf_delete_document (vp->tree_uri, vp->document_id); + return android_saf_delete_document (vp->tree_uri, + vp->document_id, + vp->name); } static int @@ -5173,7 +5186,9 @@ android_saf_file_unlink (struct android_vnode *vnode) struct android_saf_file_vnode *vp; vp = (struct android_saf_file_vnode *) vnode; - return android_saf_delete_document (vp->tree_uri, vp->document_id); + return android_saf_delete_document (vp->tree_uri, + vp->document_id, + vp->name); } static int -- 2.39.2