NSURL Bookmarks: A Faster Alternative?

Viewed 404

Context

My app's model is a tree of objects where each object represents a filesystem item (a folder or file) on disk beneath a given starting folder.

Periodically, I recursively walk this tree from top-down in order to "sync" it to the actual state of the filesystem. That is, I visit each object in the model and verify that the file/folder it represents still exists in the same location on disk.

If the file/folder has moved, I use an NSURL bookmark to ascertain the new location of the file/folder so that I can update my model's state. (I create an NSURL bookmark when I first create the model object and then store the bookmark data as a property of the object so that I can resolve it later.)


The Problem

NSURL bookmarks simply aren't performant enough. It's not uncommon for my model graph to have 20,000 nested objects. Each one has a bookmark. Here's what I'm seeing when I profile performance:

enter image description here

The recursivelyValidateExistingChildItemsOfParentItem:... method is what walks my model tree. 90% of the time involved is just resolving bookmarks (and, if they are stale, re-creating them as described in Apple's documentation).

The app takes almost 2 minutes to complete the walk thanks to this. So, I need a faster alternative to NSURL bookmarks.


What I've Considered

  1. Extended File Attributes. I could add a UUID attribute to each file on disk. Instead of walking my model graph, I could walk the actual filesystem underneath the starting folder. When I find a new file, I could see if it has a UUID extended attribute. If so, I could then search my model graph for the object with that UUID to handle moved/relocated files. The trouble here is that many things clobber extended file attributes—they aren't guaranteed to stick around.

  2. BDAlias or NDAlias. I used to use BDAlias before I migrated to NSURL bookmarks, but that wasn't exceptionally more performant.


Bottom Line

I need a faster alternative to NSURL's bookmarks. But I still need to be able to track files across launches of my app, so simply keeping file descriptors open or using file id's won't work.

I don't care how low-level I have to get; I just need performance. Thanks!

1 Answers

I know the question is old. But this is my answer:

I only use resolving bookmark as a fallback. I save both file path and URL bookmark data in my model. When I want to open file, first I check if the file still exists in the previously known location. If not, I would try to resolve url's bookmark data. This would narrow calling to URL.init(resolvingBookmarkData) only to a limited subset of items. I would then update model with new path after resolving bookmark to keep performance reasonable.

If you need to assure you are working with exactly the same file, you can check file's date, size or a specific EA as an extra measurement.

Related