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 - 2009, 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.1086 2011/08/30 12:28:23 grubba Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.1087 2011/08/31 11:23:35 grubba 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:4442:    }    }   }         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.   { + #define GET_DB() \ +  Sql.Sql db = dbm_cached_get("local")   #undef QUERY   #define QUERY(X,Y...) db->query(X,Y) -  Sql.Sql db; +     string name;      #define CACHE_SIZE 900       Thread.Mutex mutex = Thread.Mutex();    // Allow recursive locks, since it's normal here.   # define LOCK() mixed __ = mutex->lock (2)      #ifdef ARGCACHE_DEBUG   #define dwerror(ARGS...) werror(ARGS)
Roxen.git/server/base_server/roxen.pike:4471:    protected mapping(string|int:mixed) cache = ([ ]);       //! Cache of cache-ids that have no expiration time.    //! This cache is maintained in sync with @[cache].    //! Note that entries not in this cache may still have    //! unlimited expiration time.    protected mapping(string|int:int) no_expiry = ([ ]);       protected void setup_table()    { +  GET_DB(); +     // New style argument2 table.    if(catch(QUERY("SELECT id FROM "+name+"2 LIMIT 0")))    {    master()->resolv("DBManager.is_module_table")    ( 0, "local", name+"2",    "The argument cache, used to map between "    "a unique string and an argument mapping" );    catch(QUERY("DROP TABLE "+name+"2" ));    QUERY("CREATE TABLE "+name+"2 ("    "id CHAR(32) PRIMARY KEY, "
Roxen.git/server/base_server/roxen.pike:4533:       if(res[0]->Type == "blob") {    QUERY("ALTER TABLE "+name+"2 MODIFY contents MEDIUMBLOB NOT NULL");    werror("ArgCache: Extending \"contents\" field in table \"%s2\" from BLOB to MEDIUMBLOB.\n", name);    }    };    }       protected void do_cleanup()    { +  GET_DB();    QUERY("DELETE LOW_PRIORITY FROM " + name + "2 "    " WHERE timeout IS NOT NULL "    " AND timeout < %d", time());    }       protected void cleanup_process( )    {    // Flushes may be costly in large sites (since there's no index    // on the timeout field) so schedule next run sometime after    // 04:30 the day after tomorrow.
Roxen.git/server/base_server/roxen.pike:4557:       do_cleanup();    }       protected void init_db()    {    // Delay DBManager resolving to before the 'roxen' object is    // compiled.    cache = ([]);    no_expiry = ([]); -  db = dbm_cached_get("local"); +     setup_table( );       // Cleanup exprired entries on start.    background_run( 10, cleanup_process );    }       protected void create( string _name )    {    name = _name;    init_db();    // Support that the 'local' database moves (not really nessesary,    // but it won't hurt either)    master()->resolv( "DBManager.add_dblist_changed_callback" )( init_db );    get_plugins();    }       protected string read_encoded_args( string id, int dont_update_atime )    {    LOCK(); -  +  GET_DB();    array res = QUERY("SELECT contents FROM "+name+"2 "    " WHERE id = %s", id);    if(!sizeof(res))    return 0;    if (!dont_update_atime)    QUERY("UPDATE LOW_PRIORITY "+name+"2 "    " SET atime = NOW() "    " WHERE id = %s", id);    return res[0]->contents;    }       // Callback used in replicate.pike    void create_key( string id, string encoded_args, int|void timeout )    {    if (!zero_type(timeout) && (timeout < time(1))) return; // Expired.    LOCK(); -  +  GET_DB();    array(mapping) rows =    QUERY("SELECT id, contents FROM "+name+"2 WHERE id = %s", id );    foreach( rows, mapping row )    if( row->contents != encoded_args ) {    report_error("ArgCache.create_key(): "    "Duplicate key found! Please report this to support@roxen.com: "    "id: %O, old data: %O, new data: %O\n",    id, row->contents, encoded_args);    error("ArgCache.create_key() Duplicate key found!\n");    }
Roxen.git/server/base_server/roxen.pike:4677:    //! @param timeout    //! Timeout for the entry in seconds from now. If @expr{UNDEFINED@},    //! the entry will not expire.    {    if (!zero_type(timeout)) timeout += time(1);    string encoded_args = encode_value_canonic( args );    string id = Gmp.mpz(Crypto.SHA1.hash(encoded_args), 256)->digits(36);    if( cache[ id ] ) {    if (!no_expiry[id]) {    // The cache id may have a timeout. +  GET_DB();    if (zero_type(timeout)) {    // No timeout now, but there may have been one earlier.    QUERY("UPDATE LOW_PRIORITY "+name+"2 "    " SET timeout = NULL "    " WHERE id = %s "    " AND timeout IS NOT NULL", id);    no_expiry[id] = 1;    } else {    // Attempt to bump the timeout.    QUERY("UPDATE LOW_PRIORITY "+name+"2 "
Roxen.git/server/base_server/roxen.pike:4735:    no_expiry = ([]);    }    cache[id] = args + ([]);    return args;    }       void delete( string id )    //! Remove the data element stored under the key @[id].    {    LOCK(); +  GET_DB();    (plugins->delete-({0}))( id );    m_delete( cache, id );       QUERY( "DELETE FROM "+name+"2 WHERE id = %s", id );    }       int key_exists( string id )    //! Does the key @[id] exist in the cache? Returns 1 if it does, 0    //! if it was not present.    {
Roxen.git/server/base_server/roxen.pike:4773:    //! might not be included in the dump.    {    constant FETCH_ROWS = 10000;    int entry_count = 0;       // The server does only need to use file based argcache    // replication if the server don't participate in a replicate    // setup with a shared database.    if( !has_value((plugins->is_functional-({0}))(), 1) )    { +  GET_DB();    int cursor;    array(string) ids;    do {    // Note: No lock is held, so rows might be added between the    // SELECTs here. That can however only cause a slight overlap    // between the LIMIT windows since rows are only added and    // never removed, and read_dump doesn't mind the occasional    // duplicate entry.    //    // A lock will be necessary here if a garb is added, though.
Roxen.git/server/base_server/roxen.pike:4889:    }    if(s != "EOF")    return "Missing data in argcache file\n";    return 0;    }       void refresh_arg(string id)    //! Indicate that the entry @[id] needs to be included in the next    //! @[write_dump]. @[id] must be an existing entry.    { +  GET_DB();    QUERY("UPDATE "+name+"2 SET rep_time=NOW() WHERE id = %s", id);    }   }      mapping cached_decoders = ([]);   string decode_charset( string charset, string data )   {    // FIXME: This code is probably not thread-safe!    if( charset == "iso-8859-1" ) return data;    if( !cached_decoders[ charset ] )