
chris.keane at zzgi
Jul 21, 2012, 7:47 AM
Views: 152
Permalink
|
|
A brief discussion of UserTags and their presence in RPC server daemons
|
|
Imagine this case: * A single interchange instance with a comprehensive set of system-wide custom UserTags * Multiple catalogs within the interchange instance. Some of them have UserTags overriding some of the system-wide UserTags with catalog-level tags. All catalogs have at least a few tags named the same that implement catalog-specific logic. Problem: inconsistency in which version of a UserTag is actually called: In cases where the global UserTag is not overridden by any local tags, the global tag is properly called (good). In instances where a local UserTag in one catalog overrides a global UserTag, sometimes the tag is also overridden in all catalogs, sometimes not (bad) In instances where multiple catalogs have the same local UserTag, the actual UserTag called in any catalog is a random* selection of those UserTags from all catalogs, i.e. it's not necessarily the UserTag from the actual calling catalog, it might be one from a completely separate catalog. (bad) *random: it's not really random, its actually the version from the first catalog that was called in each server Child process. The reason: Within each server Child process global UserTags are loaded into the Parse space (into %Routines) They are then supplemented/overridden by local UserTags. However, if even a single catalog overrides the in-memory copy of a global UserTag in $Routines{tagname} it will be overridden for all subsequent requests served by that server Child. Even for catalogs which are not supposed to be overriding it. Once a server Child process starts and receives its first request, it loads all the local UserTags for that first catalog called, but does not do so again. Result: that first catalog's local UserTags being used by all subsequent calls to that Child regardless of which catalog they are for. Solutions: The most obvious and braindead solution is to update the RPC mode settings to have MaxRequestsPerChild equal 1. In this setting, each Child will handle one request, die, and spawn a new one, thereby freshly setting all UserTags for one specific catalog call. However, there is then little advantage to using RPC mode, and in our case where we send hundreds of tiny ajax requests through the interchange server, would require quite a high StartServers number. Alternately, fix the code. We gone through various iterations of this over the last few years. Right now we're sitting with: in Vend::Parse in new() replace add_tags($Vend::Cfg->{UserTag}) unless $Vend::Tags_added++; with add_tags($Global::UserTag); # CK added because later-loaded Usertags from different catalogs were overriding global tags if # some other catalog had a local version of the tag but this one relied on the global version add_tags($Vend::Cfg->{UserTag}); Note, the conditional Tags_added removed to force load of tags every time. Otherwise, stale versions from other catalogs will be used instead of the ones from our catalog. Note, added add_tags($Global::UserTag) to force a fresh copy of the global usertags in case a previous call within this Child to a different catalog had overridden the global tag with its own, but we don't override it in this catalog. The downside of performing these add_tags is performance. We don't have any benchmarks. sub add_tags is a memory-only operation so not as terrible as it could be. But basically it's additional stuff that needs to happen before we even start real processing which we're trying to optimize out wherever possible. The next step to making this better will be to rewrite Parse::do_tag to remove the use of the %Routine hash altogether. Basically, at time of execution try finding $Vend::Cfg->{UserTag}->{Routine} first, then try $Global::UserTag->{Routine} next if not found. Thoughts, suggestions? Chris. _______________________________________________ interchange-users mailing list interchange-users [at] icdevgroup http://www.icdevgroup.org/mailman/listinfo/interchange-users
|