From 219a87dccd55fcdc716e2fd69791214e2ceb1eb6 Mon Sep 17 00:00:00 2001 From: Francesco Chemolli <li@kinkie.it> Date: Mon, 7 Aug 2000 19:59:57 +0200 Subject: [PATCH] MySQL-based storage manager. Rev: lib/modules/Cache.pmod/Storage.pmod/MySQL.pike:1.1 --- .gitattributes | 1 + .../Cache.pmod/Storage.pmod/MySQL.pike | 156 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 lib/modules/Cache.pmod/Storage.pmod/MySQL.pike diff --git a/.gitattributes b/.gitattributes index 3092fe5026..347f07ef93 100644 --- a/.gitattributes +++ b/.gitattributes @@ -44,6 +44,7 @@ testfont binary /lib/modules/Cache.pmod/Storage.pmod/Base.pike foreign_ident /lib/modules/Cache.pmod/Storage.pmod/Gdbm.pike foreign_ident /lib/modules/Cache.pmod/Storage.pmod/Memory.pike foreign_ident +/lib/modules/Cache.pmod/Storage.pmod/MySQL.pike foreign_ident /lib/modules/Cache.pmod/Storage.pmod/Yabu.pike foreign_ident /lib/modules/Cache.pmod/cache.pike foreign_ident /lib/modules/Calendar.pmod/mkrules.pike foreign_ident diff --git a/lib/modules/Cache.pmod/Storage.pmod/MySQL.pike b/lib/modules/Cache.pmod/Storage.pmod/MySQL.pike new file mode 100644 index 0000000000..d9495e12e4 --- /dev/null +++ b/lib/modules/Cache.pmod/Storage.pmod/MySQL.pike @@ -0,0 +1,156 @@ +/* + * An SQL-based storage manager + * by Francesco Chemolli <kinkie@roxen.com> + * (C) 2000 Roxen IS + * + * $Id: MySQL.pike,v 1.1 2000/08/07 17:59:57 kinkie Exp $ + * + * This storage manager provides the means to save data to an SQL-based + * backend. + * + * For now it's mysql only, dialectization will be added at a later time. + * Serialization should be taken care of by the low-level SQL drivers. + * + * Notice: the administrator is supposed to create the database and give + * the roxen user enough privileges to write to it. It will be care + * of this driver to create the database itself. + * + */ + +#define MAX_KEY_SIZE "255" +#define CREATION_QUERY "create table cache ( \ +cachekey varchar(" MAX_KEY_SIZE ") not null primary key, \ +atime timestamp, \ +ctime timestamp, \ +etime timestamp default '20361231235959', \ +cost float unsigned DEFAULT 1.0 NOT NULL, \ +data longblob NOT NULL \ +)" + +Sql.sql db; + +#if 0 // set to 1 to enable debugging +#ifdef debug +#undef debug +#endif // ifdef debug +#define debug(X...) werror("Cache.Storage.mysql: "+X);werror("\n") +#else // 1 +#ifndef debug // if there's a clash, let's let it show +#define debug(X...) /**/ +#endif // ifndef debug +#endif // 1 + + +//database manipulation is done externally. This class only returns +//values, with some lazy decoding. +class Data { + inherit Cache.Data; + private int _size; + private string db_data; + private mixed _data; + + void create (mapping q) { + debug("instantiating data object from %O",q); + db_data=q->data; + _size=sizeof(db_data); + atime=(int)q->atime; + ctime=(int)q->ctime; + etime=(int)q->etime; + cost=(float)q->cost; + } + + int size() { + debug("object size requested"); + return _size; + } + + mixed data() { + debug("data requested"); + if (_data) + return _data; + debug("lazy-decoding data"); + _data=decode_value(db_data); + db_data=0; + return _data; + } +} +//does MySQL support multiple outstanding resultsets? +//we'll know now. +//Notice: this will fail miserably with Sybase, for instance. +//Notice: can and will throw exceptions if anything fails. +private object(Sql.sql_result) enum_result; +int(0..0)|string first() { + debug("first()"); + array res; + if (enum_result) + destruct(enum_result); + enum_result=db->big_query("select cachekey from cache"); + return next(); +} + +int(0..0)|string next() { + debug("next()"); + array res; + if (!enum_result) + return 0; + if (res=enum_result->fetch_row()) + return res[0]; + enum_result=0; // enumeration finished + return 0; +} + +void delete(string key, void|int(0..1) hard) { + debug("deleting value for key %s",key); + //what happens if there's no such key? Nothing should happen... + db->query("delete from cache where cachekey='%s'",key); +} + +void set(string key, mixed value, + void|int expire_time, void|float preciousness) { + debug("setting value for key %s (e: %d, v: %f",key,expire_time, + preciousness?preciousness:1.0); + mixed err; + db->query("delete from cache where cachekey='%s'",key); + db->query("insert into cache (cachekey,atime,ctime,etime,cost,data) " + "values('%s',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,%s,%s,'%s')", + db->quote(key), + (expire_time?"FROM_UNIXTIME("+expire_time+")":"NULL"), + (preciousness?(string)preciousness:"1"), + db->quote(encode_value(value))); +} + +int(0..0)|Cache.Data get(string key,void|int notouch) { + debug("getting value for key %s (nt: %d)",key,notouch); + array(mapping) result=0; + mixed err=0; + catch (result=db->query("select unix_timestamp(atime) as atime," + "unix_timestamp(ctime) as ctime," + "unix_timestamp(etime) as etime,cost,data " + "from cache where cachekey='%s'",key)); + if (!result || !sizeof(result)) + return 0; + if (!notouch) + catch(db->query("update cache set atime=CURRENT_TIMESTAMP " + "where cachekey='%s'",key)); + return Data(result[0]); +} + +void aget(string key, + function(string,int(0..0)|Cache.Data:void) callback) { + callback(key,get(key)); +} + + + +void create(string sql_url) { + array result=0; + mixed err=0; + db=Sql.sql(sql_url); + // used to determine whether there already is a DB here. + err=catch(result=db->query("select stamp from cache_admin")); + if (err || !sizeof(result)) { + db->query(CREATION_QUERY); + db->query("create table cache_admin (stamp integer primary key)"); + db->query("insert into cache_admin values ('1')"); + } +} -- GitLab