[interfacekit] Re: MimeDatabase

  • From: Tyler Dauwalder <tyler@xxxxxxxxxxxxx>
  • To: interfacekit@xxxxxxxxxxxxx
  • Date: Thu, 22 Aug 2002 01:40:04 -0700

On 2002-08-21 at 14:52:50 [-0700], interfacekit@xxxxxxxxxxxxx wrote:
> > > Then there is
> > > =3D60__mime_table' which is certainly also held in memory to speed 
> > > up
> > > BMimeType::GetSupportingTypes().
> > 
> > I'm still a bit perplexed about __mime_table. I honestly think it's
> > left over from days gone past. It contains *some* supporting app
> > information, but not nearly all of it. You have to go through the
> > actual database and read through the META:FILE_TYPES attributes of
> > all
> > the application types and merge that information with the
> > __mime_table
> > information to get the full supporting apps list.
> 
> Not so on my machine. 
[...]
> Therefore my conclusion is, that __mime_table is not just legacy, but
> is useful to speed up the boot process -- when the registrar is
> started, it doesn't need to scan the database for applications'
> supported types and build the reverse mapping, but it can just read in
> __mime_table instead.

That would make sense. I'm still not sure why I've been unable to add 
entries to my copy (I've tried rebooting, I've tried BEOS:FILE_TYPES 
resources as in the keymap preflet...), but it's possible I'm just not 
getting the formula right.
 
> > I still don't know how information gets added to the __mime_table
> > file
> > though. As best I've been able to tell, create_app_meta_mime()
> > doesn't
> > do it.
> 
> I believe it does. Not directly though -- it sends a message to the
> registrar and the "mime updater" does the job, certainly using
> BAppFileInfo, which uses BMimeType::SetSupportedTypes(), which in turn
> does the change to the in-memory version of __mime_table. The file is
> only written on shutdown and probably now and then whilst running.

Like I mentioned, I've tried rebooting, and to no effect. The 
information shows up in the database, but not __mime_table... I think I 
have a lazy registrar.

> > Aside from being sure to check the __mime_table file for supporting
> > apps info, I don't know that I see much point in trying to support 
> > it
> > any further.
> 
> As written above, I think, __mime_table shortens the time for booting.
> We might test, if it is much -- my certainly small MIME DB has 257
> application/* entries, which all had to be checked for 
> META:FILE_TYPES,
> perhaps taking one or two seconds, I reckon -- but I don't see the
> reason for abandoning it.

No, using it the way you're suggesting makes a lot of sense. It'd 
definitely be worth trying.

> What we should do, is to remove entries from __mime_table, that are 
> not
> longer installed in the MIME DB. At least I don't see any reason not 
> to
> do it. There seems to be no way to get hold of the not installed types
> contained in __mime_table anyway.

I agree. This we should definitely do.

> > > (watch out
> > > the private BMimeType::{Set,Get}SupportedTypes(), that we may or
> > > may
> > > not want to implement as well).
> > 
> > We may as well. I don't really see any reason why they should be
> > private anyway.
> 
> The explanation that immediately comes to my mind is, that it should
> not be allowed to manipulate the types an app supports 
> algorithmically.
> In fact this doesn't make much sense, as an app either supports a type
> or it does not. One may be able to construct counter examples though.
> E.g. when an application supports types through add-ons (a web browser
> for instance). I don't know, if BMimeType::SetSupportedTypes() was the
> best means in this case, as the type support is a static feature
> whereas loading add-ons is done at run time. I think, a better 
> solution
> would be to make the add-on an executable, itself supporting the type.
> When a file of the type is requested to be opened, the add-on gets
> executed and it simply passes the entry_ref to the main application
> (e.g. using BRoster::Launch() and quitting thereafter).
> 
> To sum it up, I vote for leaving the methods private for the time
> being, and, if we find a good reason to make it public, we can do that
> at any time.

I just don't see that supported types are all that different from the 
other attributes BMimeType gives access to. And certainly, why would we 
want to keep someone from being able to at least lookup the types 
supported by a given app? It seems highly inconsistent to me to give 
unlimited access to the rest of the database through BMimeType but then 
exclude supported types. And code-wise, they're essentially no 
different from Get/SetFileExtensions() or Get/SetAttrInfo(). A little 
more code will be needed to update the supported apps table, but not so 
much that it justifies making those methods private (plus, assuming 
BAppFileInfo implements SetSupportedTypes() functionality, we'll have 
to do it anyway... :-). 

So any way, my vote's for making them public. Like you said though, 
it's not like it'll be a lot of work to change them one way or the 
other :-). Incidentally, I have Get/SetSupportedTypes() implemented but 
not yet checked in, in case you might find them useful for BAppFileInfo.

> > In that case, here's what I'm thinking I'll do:
> > 
> > // For GetInstalledTypes(BMessage*)
> > std::set<char*> fAllInstalledTypes;
> > BMessage *fAllTypesMessage;
> > 
> > // For GetInstalledTypes(const char*, BMessage*)
> > // and GetInstalledSupertypes(BMessage*)
> > struct InstalledSubtypesInfo {
> > =3D09std::set<char*> fInstalledSubtypes;
> > =3D09BMessage *fCachedMessage;
> > };
> > std::map<char*, InstalledSubtypesInfo> fSupertypesMap;
> > 
> > // For GetSupportingApps(BMessage*)
> > struct SupportingAppsInfo {
> > =3D09std::set<char*> fSupportingApps;
> > =3D09BMessage *fCachedMessage;
> > };
> > std::map<char*, SupportingAppsInfo> fSupportingAppsMap;
> 
> First for sake of formal correctness (feel free to call it pettiness):
> string should be used instead of char* (as it wouldn't work, unless
> there is a specialization for it) and the struct members should be
> named x_y_z instead of fXYZ.

Thanks. I tend to forget the rules when it comes to structs. :-)

> > Initially, just the maps and sets would be filled with data. When a
> > function is called, first the appropriate cached BMessage would be
> > checked. If it existed, it'd be returned. If not, a new BMessage
> > would
> > be constructed from the data in the maps and sets and then returned
> > and
> > cached. If, by a Set() or Delete() call, the data in the maps and
> > sets
> > would need to be updated, any corresponding cached BMessage(s) would
> > be
> > deleted.
> 
> I'm not sure, if this invalidation+lazy-reinitialization strategy is
> advantageous in all cases. E.g. the set of (all) installed types is
> large, but seldomly changed. A single Install() or Delete() would
> require to rebuild the whole message instead of just adding/deleting
> one item. There may be issues with finding the index of the type to be
> added/removed though. Don't know...

Well, after looking BMessage over and thinking about it, I believe it 
*would* be faster to maintain everything in BMessages. You'd need to 
keep a mapping of mimetypes to indices in the BMessage. Adding would be 
easy, but deleting would require an update of the indices in the map 
for all the mimetypes following the type removed. Overall it's still 
O(n), but decrementing O(n) integers in memory should be considerably 
faster than walking through the entire database again on disk. It'll be 
a bit more complicated, too, but I bet it would be worth it.

I have GetInstalledTypes(BMessage*) done using the method I originally 
mentioned, so perhaps I'll reimplement it using this BMessage method 
and see which is really faster before finishing everything else.

> I'd like to propose to encapsulate all this functionality into a
> separate class. If its interface is designed cleverly, we are free to
> play with its guts afterwards.

Done. :-) The interface I'm currently using is essentially identical to 
that from BMimeType:

status_t GetInstalledTypes(BMessage *types);
status_t GetInstalledTypes(const char *supertype, BMessage *subtypes);
status_t GetInstalledSupertypes(BMessage *supertypes);
status_t GetSupportingApps(const char *type, BMessage *signatures);

Who knows what's going on inside? :-)=05

-Tyler

Other related posts: