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 - 2004, 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.948 2006/11/14 21:27:06 mast Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.949 2006/11/16 14:19:43 mast 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:3676:    uid_cache[ci] = user;    if( catch(QUERY("INSERT INTO "+name+" "    "(id,uid,atime) VALUES (%s,%s,UNIX_TIMESTAMP())",    ci, user||"")) )    QUERY( "UPDATE "+name+" SET uid=%s WHERE id=%s",    user||"", ci );    }      #ifndef NO_ARG_CACHE_SB_REPLICATE    if(id->misc->persistent_cache_crawler) { -  // Force an update of atime for the requested arg cache id. +  // Force an update of rep_time for the requested arg cache id.    foreach(ci/"$", string key) {   #if ARGCACHE_DEBUG    werror("Request for id %O from prefetch crawler.\n", key);   #endif /* ARGCACHE_DEBUG */    argcache->refresh_arg(key);    }    }   #endif /* NO_ARG_CACHE_SB_REPLICATE */    return ci;    }
Roxen.git/server/base_server/roxen.pike:3823:    {    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, "    "ctime DATETIME NOT NULL, "    "atime DATETIME NOT NULL, " +  "rep_time DATETIME NOT NULL, "    "contents BLOB NOT NULL)");    } -  +  +  if (catch (QUERY ("SELECT rep_time FROM " + name + "2 WHERE id = 0"))) +  { +  // Upgrade a table without rep_time. +  QUERY ("ALTER TABLE " + name + "2" +  " ADD rep_time DATETIME NOT NULL" +  " AFTER atime");    } -  +  }       static void init_db()    {    // Delay DBManager resolving to before the 'roxen' object is    // compiled.    cache = ([]);    db = dbm_cached_get("local");    setup_table( );    }       static 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();    }    -  string read_encoded_args( string id ) +  static string read_encoded_args( string id, int dont_update_atime )    {    LOCK();    array res = QUERY("SELECT contents FROM "+name+"2 "    " WHERE id = %s", id);    if(!sizeof(res))    return 0; -  +  if (!dont_update_atime)    QUERY("UPDATE "+name+"2 "    " SET atime = NOW() "    " WHERE id = %s", id);    return res[0]->contents;    }    -  void create_key( string id, string encoded_args ) +  static void create_key( string id, string encoded_args )    {    LOCK();    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");    }    -  if(sizeof(rows)) +  if(sizeof(rows)) { +  QUERY("UPDATE "+name+"2 " +  " SET atime = NOW() " +  " WHERE id = %s", id);    return; -  +  }       QUERY( "INSERT INTO "+name+"2 "    "(id, contents, ctime, atime) VALUES "    "(%s, " MYSQL__BINARY "%s, NOW(), NOW())", id, encoded_args );       dwerror("ArgCache: Create new key %O\n", id);       (plugins->create_key-({0}))( id, encoded_args );    }   
Roxen.git/server/base_server/roxen.pike:3899:    foreach( ({ "../local/arg_cache_plugins", "arg_cache_plugins" }), string d)    if( file_stat( d ) )    foreach( glob("*.pike", get_dir( d )), string f )    {    object plug = ((program)(d+"/"+f))(this_object());    if( !plug->disabled )    plugins += ({ plug });    }    }    -  mapping plugins_read_encoded_args( string id ) +  static mapping plugins_read_encoded_args( string id )    {    mapping args;    foreach( (plugins->read_encoded_args - ({0})), function(string:mapping) f )    if( args = f( id ) )    return args;    return 0;    }       string store( mapping args )    //! Store a mapping (of purely encode_value:able data) in the
Roxen.git/server/base_server/roxen.pike:3931:    cache = ([]);    return id;    }          mapping lookup( string id )    //! Recall a mapping stored in the cache.    {    if( cache[id] )    return cache[id] + ([]); -  string encoded_args = read_encoded_args(id) || plugins_read_encoded_args(id); +  string encoded_args = (read_encoded_args(id, 0) || +  plugins_read_encoded_args(id));    if(!encoded_args) {    error("Requesting unknown key (not found in db)\n");    }    mapping args = decode_value(encoded_args);    cache[id] = args + ([]);    if( sizeof( cache ) >= CACHE_SIZE ) -  +  // Yowza! Garbing bulldoze style. /mast    cache = ([]);    return args;    }       void delete( string id )    //! Remove the data element stored under the key 'id'.    {    LOCK();    (plugins->delete-({0}))( id );    m_delete( cache, id );       QUERY( "DELETE FROM "+name+"2 WHERE id = %s", id );    }      #define SECRET_TAG "££"    -  int write_dump(Stdio.File file, int|void from_time) -  // Write a mapping from id to encoded arg string for all local arg -  // entries created after from_time to a file. Returns 0 if faled, 1 -  // otherwise. +  int write_dump(Stdio.File file, int from_time) +  //! Dumps all entries that have been @[refresh_arg]'ed at or after +  //! @[from_time] to @[file]. All existing entries are dumped if +  //! @[from_time] is zero. +  //! +  //! @returns +  //! Returns 0 if writing failed, -1 if there was no new entries, 1 +  //! otherwise. +  //! +  //! @note +  //! Entries added during the execution of this function might or +  //! 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) )    {    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. +     if(from_time)    // Only replicate entries accessed during the prefetch crawling.    ids =    (array(string))    QUERY( "SELECT id from "+name+"2 " -  " WHERE atime >= FROM_UNIXTIME(%d) " +  " WHERE rep_time >= FROM_UNIXTIME(%d) "    " LIMIT %d, %d", from_time, cursor, FETCH_ROWS)->id;    else    // Make sure _every_ entry is replicated when a dump is created.    ids =    (array(string))    QUERY( "SELECT id from "+name+"2 "    " LIMIT %d, %d", cursor, FETCH_ROWS)->id;       cursor += FETCH_ROWS;       foreach(ids, string id) {    dwerror("ArgCache.write_dump(): %O\n", id);    -  +  string encoded_args; +  if (mapping args = cache[id]) +  encoded_args = encode_value_canonic (args); +  else { +  encoded_args = read_encoded_args (id, 1); +  if (!encoded_args) error ("ArgCache entry %O disappeared.\n", id); +  } +     string s = -  MIME.encode_base64(encode_value(({ id, read_encoded_args(id) })), +  MIME.encode_base64(encode_value(({ id, encoded_args })),    1)+"\n";    if(sizeof(s) != file->write(s))    return 0; -  +  entry_count++;    }    } while(sizeof(ids) == FETCH_ROWS);    } -  return file->write("EOF\n") == 4; +  if (file->write("EOF\n") != 4) +  return 0; +  return entry_count ? 1 : -1;    }       string read_dump (Stdio.FILE file)    // Returns an error message if there was a parse error, 0 otherwise.    {    string secret = file->gets();    // Check if no secret is present -> newstyle package.    if(!secret || !has_prefix(secret, SECRET_TAG))    // New pakage found, restore input stream.    file->ungets(secret);
Roxen.git/server/base_server/roxen.pike:4035:    create_key(a[0], a[1]);    } else    return "Decode failed for argcache record (wrong size on key array)\n";    }    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.    { -  QUERY("UPDATE "+name+"2 SET atime=NOW() WHERE id = %s", id); +  QUERY("UPDATE "+name+"2 SET rep_time=NOW() WHERE id = %s", id);    }   }      #else // ENABLE_NEW_ARGCACHE      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.   {