Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I'm working on a DBus service that needs to export objects on demand when requested by 3rd party applications. That part seems fairly strait-forward.

But I also need to "garbage collect" these objects when it has zero consumers. I could have API that requires the 3rd party applications to explicitly release the objects, but the downside is if the consumer application crashes without releases the references, unused objects would accumulate.

For what it's worth, I'm using DBus from Python via python3-dbus. So I have 2 questions I guess:

  1. What sort of mechanisms does DBus provide for reference counting on exported objects, is there a way to know when zero processes are currently "observing" an object?

  2. What is considered the best-practice for designing such a DBus API, and what do people think is a good example to follow? (The only thing like this I can think of is the Avahi Browser objects.)

My question will probably make more sense if I describe the exact problem: Dmedia is a specialized distributed file-system aimed at media files. Files are given a globally unique ID based on their content-hash. When an application needs to use a file (say for playback or display), it will use the Dmedia DBus API to resolve the file ID into a regular file path. For example, this ID:

5PULSAF3PFR4VPNJMLSAJ362HG475NDKKISDYXW7WUJCFUJN

Could for example resolve into the file:

/media/MyDrive/.dmedia/files/5P/ULSAF3PFR4VPNJMLSAJ362HG475NDKKISDYXW7WUJCFUJN

But things are more complicated than that. The file might not be available locally, in which case Dmedia can download the file from one of the user's other devices or from the cloud. So we need signals for say download progress, and to signal what that regular file path is once a file is downloaded.

The resolution also might change over time when removable drives are connected or disconnected. A user might remove a drive, at which point the file isn't available locally and Dmedia would try to download it. Or the user might plug in an additional drive, and the resolution of a given file could change as Dmedia re-load-balances across the drives.

It seems that having a DBus object exported per current file-of-interest is a reasonable approach, but perhaps that's making things too complicated. I suppose it's the difference between needing more filtering and smarts on the consumer vs the service side. A flat collection of signals and methods on a single object would make things easier for the service, but put more burden on the consumer.

If we export a DBus object per-file-of-interest, I'm rather certain we need the garbage collection as a very large number of files can be of interest at some point during the DBus service lifecycle.

I'd much appreciate any advice on this!

share|improve this question
add comment

2 Answers

up vote 3 down vote accepted

First, it's probably worth unpacking what “observing” means in:

What sort of mechanisms does DBus provide for reference counting on exported objects, is there a way to know when zero processes are currently "observing" an object?

The only sense in which it makes sense to ask whether something is ‘observing’ a DBus object is whether a client will receive any signals that object raises; there's otherwise no concept of observation, just message passing. Clients do this by calling AddMatch/RemoveMatch on the bus, so you could theoretically reference count on matches. That seems like a method prone to error, though - you'll basically need to reimplement the daemon's match handler in order to be sure you've caught all the ways a client can listen to your signals.

However, if all you're after is cleanup after crashing clients, there is a way - each DBus client gets a unique bus-id (for example, :1.693) allocated it by the daemon. When a client requests a file over your DBus API you can record their bus-id, and then watch the NameOwnerChanged signal of org.freedesktop.DBus. This signal has 3 parts - the bus name (which, in the cases we're interested in, will be the unique bus-id), the the new owner's bus-id, and the old owner's bus-id.

So if you get a NameOwnerChanged signal with name=":1.693", new_owner="", and old_owner=":1.693" you know that the client with bus-id :1.693 has disconnected from the bus, and can remove any objects that client was using.

You'd want to do this in addition to having clients explicitly telling your service when they're done with a file, of course.

Edit:

As for your global question - what should the API be - I'd suggest that this seems complex enough that your DBus objects should not be the primary API. Wrap this up in a python-dmedia-client (and possibly a C libdmedia-client), and handle the ref-counting and complexity there.

share|improve this answer
add comment

I hit a similar issue and came up with a mechanism for doing reference counting across DBus. It turned out to be quite tricky so I created DBus bug #38784 to propose incorporation into the DBus spec as a standard interface/mechanism so others wouldn't have to repeat the work.

You can read the proposal in docbook format here.

I don't believe it has been implemented in the Python DBus bindings or any other publicly available DBus bindings though.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.