Perfect! Applied. Many thanks Dave. Tim.
On Wed, Apr 18, 2012 at 11:48:31AM +0100, Dave Mitchell wrote: > On Fri, Mar 02, 2012 at 05:04:29PM +0000, Dave Mitchell wrote: > > On Fri, Mar 02, 2012 at 03:23:30PM +0000, Dave Mitchell wrote: > > > I'd be happy in principle, although some guidance would be welcome > > > > Also in particular, what needs to continue happening across an API > > change? Is it just that a driver, compiled and installed against an old > > DBI, must continue to work if the DBI is upgraded? > > I've now attached a revised DBIS patch. The only difference is that > the new DBI continues to store a pointer to the dbi_state struct in > $DBI::_dbistate, so that DBD modules compiled against the old DBI can > continue to retrieve the struct the old way. Once recompiled, they'll > start to use the new method. > > IIUC, this means that there are no binary or backwards compatibility > issues, and no API version numbers need bumping. > > -- > The optimist believes that he lives in the best of all possible worlds. > As does the pessimist. > From 0fb5fd6a7099c5fc40bd0b9d40b8b34d748533b5 Mon Sep 17 00:00:00 2001 > From: David Mitchell <da...@iabyn.com> > Date: Fri, 10 Feb 2012 13:11:13 +0000 > Subject: [PATCH] under ithreads, make DBIS efficient for DBD::* > > rather than the slow looking up of $DBI::_dbistate on every use of DBIS, > convert DBIS into a call to a C-level function that returns the address of > the dbi_state struct. > > Since the C-level function is only directly callable from DBI, store its > address in an XSUB, so that the DBD:* modules can retrieve the function's > address and cache it in a static var. > > We continue to store the dbi_state struct address within $DBI::_dbistate > too, so that DBD modules compiled against an older DBI will continue to > work if the DBI is upgraded but the DBD not recompiled. > --- > DBI.pm | 4 +--- > DBI.xs | 39 +++++++++++++++++++-------------------- > DBIXS.h | 39 +++++++++++++++++++++++++++------------ > 3 files changed, 47 insertions(+), 35 deletions(-) > > diff --git a/DBI.pm b/DBI.pm > index 4e02e8c..614ffae 100644 > --- a/DBI.pm > +++ b/DBI.pm > @@ -519,10 +519,8 @@ END { > > > sub CLONE { > - my $olddbis = $DBI::_dbistate; > _clone_dbis() unless $DBI::PurePerl; # clone the DBIS structure > - DBI->trace_msg(sprintf "CLONE DBI for new thread %s\n", > - $DBI::PurePerl ? "" : sprintf("(dbis %x -> %x)",$olddbis, > $DBI::_dbistate)); > + DBI->trace_msg("CLONE DBI for new thread\n"); > while ( my ($driver, $drh) = each %DBI::installed_drh) { > no strict 'refs'; > next if defined &{"DBD::${driver}::CLONE"}; > diff --git a/DBI.xs b/DBI.xs > index 64dc5b1..a9e9000 100644 > --- a/DBI.xs > +++ b/DBI.xs > @@ -127,8 +127,6 @@ char *neatsvpv _((SV *sv, STRLEN maxlen)); > SV * preparse(SV *dbh, const char *statement, IV ps_return, IV ps_accept, > void *foo); > static meth_types get_meth_type(const char * const name); > > -DBISTATE_DECLARE; > - > struct imp_drh_st { dbih_drc_t com; }; > struct imp_dbh_st { dbih_dbc_t com; }; > struct imp_sth_st { dbih_stc_t com; }; > @@ -310,13 +308,20 @@ typedef struct { > > START_MY_CXT > > -#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || defined(PERL_CAPI) > -# undef DBIS > -# define DBIS (MY_CXT.dbi_state) > -#endif > +#undef DBIS > +#define DBIS (MY_CXT.dbi_state) > > #define g_dbi_last_h (MY_CXT.dbi_last_h) > > +/* allow the 'static' dbi_state struct to be accessed from other files */ > +dbistate_t** > +_dbi_state_lval(pTHX) > +{ > + dMY_CXT; > + return &(MY_CXT.dbi_state); > +} > + > + > /* --- */ > > static void * > @@ -521,15 +526,12 @@ dbi_bootinit(dbistate_t * parent_dbis) > dbistate_t* DBISx; > > DBISx = (struct dbistate_st*)malloc_using_sv(sizeof(struct dbistate_st)); > - > - /* publish address of dbistate so dynaloaded DBD's can find it, > - * taking care to store the value in the same way it'll be used > - * to avoid problems on some architectures, for example see > - * http://rt.cpan.org/Public/Bug/Display.html?id=32309 > - */ > - sv_setiv(get_sv(DBISTATE_PERLNAME, GV_ADDMULTI), 0); /* force SvIOK */ > DBIS = DBISx; > - DBIS_PUBLISHED_LVALUE = DBISx; > + > + /* make DBIS available to DBD modules the "old" (<= 1.618) way, > + * so that unrecompiled DBD's will still work against a newer DBI */ > + sv_setiv(get_sv("DBI::_dbistate", GV_ADDMULTI), > + PTR2IV(MY_CXT.dbi_state)); > > /* store version and size so we can spot DBI/DBD version mismatch */ > DBIS->check_version = check_version; > @@ -547,12 +549,6 @@ dbi_bootinit(dbistate_t * parent_dbis) > DBIS->thr_owner = PERL_GET_THX; > #endif > > - DBISTATE_INIT; /* check DBD code to set DBIS from DBISTATE_PERLNAME */ > - > - if (DBIS_TRACE_LEVEL > 9) { > - sv_dump(DBISTATE_ADDRSV); > - } > - > /* store some function pointers so DBD's can call our functions */ > DBIS->getcom = dbih_getcom; > DBIS->clearcom = dbih_clearcom; > @@ -4346,6 +4342,9 @@ BOOT: > (void)cv; > (void)items; /* avoid 'unused variable' warning */ > dbi_bootinit(NULL); > + /* make this sub into a fake XS so it can bee seen by DBD::* modules; > + * never actually call it as an XS sub, or it will crash and burn! */ > + (void) newXS("DBI::_dbi_state_lval", (XSUBADDR_t)_dbi_state_lval, > __FILE__); > > > I32 > diff --git a/DBIXS.h b/DBIXS.h > index 7502af8..22a18de 100644 > --- a/DBIXS.h > +++ b/DBIXS.h > @@ -467,8 +467,6 @@ struct dbistate_st { > #define set_attr(h, k, v) set_attr_k(h, k, 0, v) > #define get_attr(h, k) get_attr_k(h, k, 0) > > -#define DBISTATE_PERLNAME "DBI::_dbistate" > -#define DBISTATE_ADDRSV (get_sv(DBISTATE_PERLNAME, 0x05)) > #define DBILOGFP (DBIS->logfp) > #ifdef IN_DBI_XS > #define DBILOGMSG (dbih_logmsg) > @@ -476,28 +474,45 @@ struct dbistate_st { > #define DBILOGMSG (DBIS->logmsg) > #endif > > - > /* --- perl object (ActiveState) / multiplicity hooks and hoops --- */ > /* note that USE_ITHREADS implies MULTIPLICITY */ > -#define DBIS_PUBLISHED_LVALUE (*(INT2PTR(dbistate_t**, > &SvIVX(DBISTATE_ADDRSV)))) > + > +typedef dbistate_t** (*_dbi_state_lval_t)(pTHX); > + > +# define _DBISTATE_DECLARE_COMMON \ > + static _dbi_state_lval_t dbi_state_lval_p = 0; \ > + static dbistate_t** dbi_get_state(pTHX) { \ > + if (!dbi_state_lval_p) { \ > + CV *cv = get_cv("DBI::_dbi_state_lval", 0); \ > + if (!cv) \ > + croak("Unable to get DBI state function. DBI not loaded."); \ > + dbi_state_lval_p = (_dbi_state_lval_t)CvXSUB(cv); \ > + } \ > + return dbi_state_lval_p(aTHX); \ > + } \ > + typedef int dummy_dbistate /* keep semicolon from feeling lonely */ > + > #if defined(MULTIPLICITY) || defined(PERL_OBJECT) || defined(PERL_CAPI) > > -# define DBISTATE_DECLARE typedef int dummy_dbistate /* keep semicolon > from feeling lonely */ > -# define DBISTATE_INIT_DBIS typedef int dummy_dbistate2; /* keep semicolon > from feeling lonely */ > +# define DBISTATE_DECLARE _DBISTATE_DECLARE_COMMON > +# define _DBISTATE_INIT_DBIS > # undef DBIS > -# define DBIS DBIS_PUBLISHED_LVALUE > -# define dbis DBIS_PUBLISHED_LVALUE /* temp for old drivers using 'dbis' > instead of 'DBIS' */ > +# define DBIS (*dbi_get_state(aTHX)) > +# define dbis DBIS /* temp for old drivers using 'dbis' instead of 'DBIS' */ > > #else /* plain and simple non perl object / multiplicity case */ > > -# define DBISTATE_DECLARE static dbistate_t *DBIS > -# define DBISTATE_INIT_DBIS (DBIS = DBIS_PUBLISHED_LVALUE) > +# define DBISTATE_DECLARE \ > + static dbistate_t *DBIS; \ > + _DBISTATE_DECLARE_COMMON > + > +# define _DBISTATE_INIT_DBIS DBIS = *dbi_get_state(aTHX); > #endif > > # define DBISTATE_INIT { /* typically use in BOOT: of XS file */ > \ > - DBISTATE_INIT_DBIS; \ > + _DBISTATE_INIT_DBIS \ > if (DBIS == NULL) \ > - croak("Unable to get DBI state from %s at %p. DBI not loaded.", > DBISTATE_PERLNAME, (void*)DBISTATE_ADDRSV); \ > + croak("Unable to get DBI state. DBI not loaded."); \ > DBIS->check_version(__FILE__, DBISTATE_VERSION, sizeof(*DBIS), > NEED_DBIXS_VERSION, \ > sizeof(dbih_drc_t), sizeof(dbih_dbc_t), sizeof(dbih_stc_t), > sizeof(dbih_fdc_t) \ > ); \ > -- > 1.7.4.4 >