Print this page
3166 feed generation needs performance improvement
3306 feed returns invalid last-modified header

Split Close
Expand all
Collapse all
          --- old/src/modules/server/feed.py
          +++ new/src/modules/server/feed.py
↓ open down ↓ 27 lines elided ↑ open up ↑
  28   28     a catalog, allow the construction of a feed representing the activity within
  29   29     a given time period."""
  30   30  
  31   31  import cherrypy
  32   32  from cherrypy.lib.static import serve_file
  33   33  import cStringIO
  34   34  import datetime
  35   35  import httplib
  36   36  import os
  37   37  import rfc822
       38 +import sys
  38   39  import time
  39   40  import urllib
  40   41  import xml.dom.minidom as xmini
  41   42  
  42   43  from pkg.misc import get_rel_path, get_res_path
  43      -import pkg.catalog as catalog
       44 +import pkg.server.catalog as catalog
  44   45  import pkg.fmri as fmri
  45   46  import pkg.Uuid25 as uuid
  46   47  
  47   48  MIME_TYPE = 'application/atom+xml'
  48   49  CACHE_FILENAME = "feed.xml"
  49   50  RFC3339_FMT = "%Y-%m-%dT%H:%M:%SZ"
  50   51  
  51   52  def dt_to_rfc3339_str(ts):
  52   53          """Returns a string representing a datetime object formatted according
  53   54          to RFC 3339.
↓ open down ↓ 140 lines elided ↑ open up ↑
 194  195                  # Done with the author.
 195  196                  feed.appendChild(a)
 196  197  
 197  198  operations = {
 198  199          "+": ["Added", "%s was added to the repository."],
 199  200          "-": ["Removed", "%s was removed from the repository."],
 200  201          "U": ["Updated", "%s, an update to an existing package, was added to "
 201  202              "the repository."]
 202  203  }
 203  204  
 204      -def add_transaction(request, scfg, rcfg, doc, feed, txn):
      205 +def add_transaction(request, scfg, rcfg, doc, feed, txn, fmris):
 205  206          """Each transaction is an entry.  We have non-trivial content, so we
 206  207          can omit summary elements.
 207  208          """
 208  209  
 209  210          e = doc.createElement("entry")
 210  211  
 211  212          tag, fmri_str = txn["catalog"].split()
 212  213          f = fmri.PkgFmri(fmri_str)
 213  214   
 214  215          # Generate a 'tag' uri, to uniquely identify the entry, using the fmri.
↓ open down ↓ 7 lines elided ↑ open up ↑
 222  223          # the entry title and content.
 223  224          if txn["operation"] in operations:
 224  225                  op_title, op_content = operations[txn["operation"]]
 225  226          else:
 226  227                  # XXX Better way to reflect an error?  (Aborting will make a
 227  228                  # non-well-formed document.)
 228  229                  op_title = "Unknown Operation"
 229  230                  op_content = "%s was changed in the repository."
 230  231  
 231  232          if txn["operation"] == "+":
 232      -                c = scfg.updatelog.catalog
 233  233                  # Get all FMRIs matching the current FMRI's package name.
 234      -                matches = catalog.extract_matching_fmris(c.fmris(),
 235      -                    f.get_name(), matcher=fmri.exact_name_match)
 236      -
 237      -                if len(matches) > 1:
 238      -                        # Get the oldest fmri (it's the last entry).
 239      -                        of = matches[-1]
      234 +                matches = fmris[f.pkg_name]
      235 +                if len(matches["versions"]) > 1:
      236 +                        # Get the oldest fmri.
      237 +                        of = matches[str(matches["versions"][0])][0]
 240  238  
 241  239                          # If the current fmri isn't the oldest one, then this
 242  240                          # is an update to the package.
 243  241                          if f != of:
 244  242                                  # If there is more than one matching FMRI, and
 245  243                                  # it isn't the same version as the oldest one,
 246  244                                  # we can assume that this is an update to an
 247  245                                  # existing package.
 248  246                                  op_title, op_content = operations["U"]
 249  247  
↓ open down ↓ 50 lines elided ↑ open up ↑
 300  298  
 301  299          set_title(request, rcfg, d, feed, scfg.updatelog.last_update)
 302  300  
 303  301          d.appendChild(feed)
 304  302  
 305  303          # The feed should be presented in reverse chronological order.
 306  304          def compare_ul_entries(a, b):
 307  305                  return cmp(ults_to_ts(a["timestamp"]),
 308  306                      ults_to_ts(b["timestamp"]))
 309  307  
      308 +        # Get the entire catalog in the format returned by catalog.cache_fmri,
      309 +        # so that we don't have to keep looking for possible matches.
      310 +        fmris = {}
      311 +        catalog.ServerCatalog.read_catalog(fmris,
      312 +            scfg.updatelog.catalog.catalog_root)
      313 +
 310  314          for txn in sorted(scfg.updatelog.gen_updates_as_dictionaries(feed_ts),
 311  315              cmp=compare_ul_entries, reverse=True):
 312      -                add_transaction(request, scfg, rcfg, d, feed, txn)
      316 +                add_transaction(request, scfg, rcfg, d, feed, txn, fmris)
 313  317  
 314  318          d.writexml(cf)
 315  319  
 316  320  def __get_cache_pathname(scfg):
 317  321          return os.path.join(scfg.repo_root, CACHE_FILENAME)
 318  322  
 319  323  def __clear_cache(scfg):
 320  324          if scfg.is_read_only():
 321  325                  # Ignore the request due to server configuration.
 322  326                  return
↓ open down ↓ 84 lines elided ↑ open up ↑
 407  411                          # feed will have to be generated every time.
 408  412                          cf = cStringIO.StringIO()
 409  413                          update(request, scfg, rcfg, last, cf)
 410  414                          cf.seek(0)
 411  415                          buf = cf.read()
 412  416                          cf.close()
 413  417  
 414  418                          # Now that the feed has been generated, set the headers
 415  419                          # correctly and return it.
 416  420                          response.headers['Content-type'] = MIME_TYPE
 417      -                        response.headers['Last-Modified'] = \
 418      -                            datetime.datetime.now().isoformat()
      421 +
      422 +                        # Return the current time and date in GMT.
      423 +                        response.headers['Last-Modified'] = rfc822.formatdate()
      424 +
 419  425                          response.headers['Content-length'] = len(buf)
 420  426                          return buf
 421  427                  else:
 422  428                          # If the server isn't operating in readonly mode, the
 423  429                          # feed can be generated and cached in inst_dir.
 424  430                          cf = file(cfpath, "w")
 425  431                          update(request, scfg, rcfg, last, cf)
 426  432                          cf.close()
 427  433  
 428  434          return serve_file(cfpath, MIME_TYPE)
 429  435  
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX