Roxen.git / server / base_server / roxen.pike

version» Context lines:

Roxen.git/server/base_server/roxen.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2001, Roxen IS.   //   // The Roxen WebServer main program.   //   // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.   // ABS and suicide systems contributed freely by Francesco Chemolli    - constant cvs_version="$Id: roxen.pike,v 1.829 2003/04/04 14:25:01 grubba Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.830 2003/04/05 22:15:36 anders Exp $";      //! @appears roxen   //!   //! The Roxen WebServer main program.      // The argument cache. Used by the image cache.   ArgCache argcache;      // Some headerfiles   #define IN_ROXEN
Roxen.git/server/base_server/roxen.pike:2302:   class ImageCache   //! The image cache handles the behind-the-scenes caching and   //! regeneration features of graphics generated on the fly. Besides   //! being a cache, however, it serves a wide variety of other   //! interesting image conversion/manipulation functions as well.   {   #define QUERY(X,Y...) get_db()->query(X,Y)    string name;    string dir;    function draw_function; -  mapping meta_cache = ([]); +  mapping(string:array(mapping|int)) meta_cache = ([]);       string documentation(void|string tag_n_args)    {    string doc = Stdio.read_file("base_server/image_cache.xml");    if(!doc) return "";    if(!tag_n_args)    return Parser.HTML()->add_container("ex", "")->    add_quote_tag("!--","","--")->finish(doc)->read();    return replace(doc, "###", tag_n_args);    }       static mapping meta_cache_insert( string i, mapping what )    {   #ifdef ARG_CACHE_DEBUG    werror("MD insert for %O: %O\n", i, what );   #endif    if( sizeof( meta_cache ) > 1000 ) -  meta_cache = ([ ]); -  if( what ) -  return meta_cache[i] = what; +  sync_meta(); +  if( what ) { +  meta_cache[i] = ({ what, 0 }); +  return what; +  }    else    m_delete( meta_cache, i );    return 0;    }       static mixed frommapp( mapping what )    {    if( !what )    error( "Got invalid argcache-entry\n" );    if( !zero_type(what[""]) ) return what[""];
Roxen.git/server/base_server/roxen.pike:2871:   #endif    QUERY("INSERT INTO "+name+    " (id,size,atime,meta,data) VALUES (%s,%d,%d,%s,%s)",    id, strlen(data)+strlen(meta_data), time(1), meta_data, data );    }    }       static mapping restore_meta( string id, RequestID rid )    {    if( meta_cache[ id ] ) -  return meta_cache[ id ]; +  { +  meta_cache[ id ][ 1 ] = time(1); // Update cached atime. +  return meta_cache[ id ][ 0 ]; +  }      #ifdef ARG_CACHE_DEBUG    werror("restore meta %O\n", id );   #endif    array(mapping(string:string)) q =    QUERY("SELECT meta FROM "+name+" WHERE id=%s", id );       string s;    if(!sizeof(q) || !strlen(s = q[0]->meta))    return 0;
Roxen.git/server/base_server/roxen.pike:2895:    {    report_error( "Corrupt data in cache-entry "+id+".\n" );    QUERY( "DELETE FROM "+name+" WHERE id=%s", id);    return 0;    }       QUERY("UPDATE "+name+" SET atime=UNIX_TIMESTAMP() WHERE id=%s",id );    return meta_cache_insert( id, m );    }    +  static void sync_meta() +  { +  // Sync cached atimes. +  foreach(indices(meta_cache), string id) { +  if (meta_cache[id][1]) +  QUERY("UPDATE "+name+" SET atime=%d WHERE id=%s", +  meta_cache[id][1], id); +  } +  meta_cache = ([]); +  } +     void flush(int|void age)    //! Flush the cache. If an age (an integer as returned by    //! @[time()]) is provided, only images with their latest access before    //! that time are flushed.    {    int num;   #ifdef DEBUG    int t = gethrtime();    report_debug("Cleaning "+name+" image cache ... ");   #endif -  meta_cache = ([]); +  sync_meta();    uid_cache = ([]);    rst_cache = ([]);    if( !age )    { -  + #ifdef DEBUG +  report_debug("cleared\n"); + #endif    QUERY( "DELETE FROM "+name );    num = -1;    return;    }       array(string) ids =    QUERY( "SELECT id FROM "+name+" WHERE atime < "+age)->id;       num = sizeof( ids );   
Roxen.git/server/base_server/roxen.pike:2936:       if( num )    catch    {    // Old versions of Mysql lacks OPTIMIZE. Not that we support    // them, really, but it might be nice not to throw an error, at    // least.    QUERY( "OPTIMIZE TABLE "+name );    };    -  meta_cache = ([]); +    #ifdef DEBUG    report_debug("%s removed, %dms\n",    (num==-1?"all":num?(string)num:"none"),    (gethrtime()-t)/1000);   #endif    }       array(int) status(int|void age)    //! Return the total number of images in the cache, their cumulative    //! sizes in bytes and, if an age time_t was supplied, the number of
Roxen.git/server/base_server/roxen.pike:3229:    }    }       Sql.Sql get_db()    {    return dbm_cached_get("local");    }       static void init_db( )    { -  meta_cache = ([]); +  catch(sync_meta());    setup_tables();    }       void do_cleanup( )    { -  call_out( do_cleanup, 3600*10+random(4711) ); +  background_run( 3600*10+random(4711), do_cleanup );    flush(time()-7*3600*24);    }       void create( string id, function draw_func )    //! Instantiate an image cache of your own, whose image files will    //! be stored in a table `id' in the cache mysql database,    //!    //! The `draw_func' callback passed will be responsible for    //! (re)generation of the images in the cache. Your draw callback    //! may take any arguments you want, depending on the first argument    //! you give the <ref>store()</ref> method, but its final argument    //! will be the RequestID object.    {    name = id;    draw_function = draw_func;    init_db();    // Support that the 'local' database moves.    master()->resolv( "DBManager.add_dblist_changed_callback" )( init_db );       // Always remove entries that are older than one week. -  call_out( do_cleanup, 10 ); +  background_run( 10, do_cleanup );    } -  +  +  void destroy() +  { +  if (mixed err = catch(sync_meta())) +  report_warning("Failed to sync cached atimes for "+name+"\n");    } -  + }         class ArgCache   //! Generic cache for storing away a persistent mapping of data to be   //! refetched later by a short string key. This being a cache, your   //! data may be thrown away at random when the cache is full.   {   #undef QUERY   #define QUERY(X,Y...) db->query(X,Y)    Sql.Sql db;