Subject: | ErrFile handle not release on environment close |
Hi,
What I do is have a FastCGI process that opens and closes database environments on each request. Doing this showed me a problem with code of the following nature:
open ( ERRFILE, "> $dbEnvPath/db_error.log" );
$dbEnv = BerkeleyDB::Env->new (
...
-ErrFile => *ERRFILE,
...
);
...
$dbEnv->close ( );
close ( ERRFILE );
unlink ( "$dbEnvPath/db_error.log" );
What I see is that the unlink fails because Windows says another process has it open. (The problem only exhibits itself on Win32 perhaps because in Linux you can delete a file that still has open file handles.) By adding the following code to BerekeleyDB.xs, I was able to fix this though a lot of this is magik to me and so I'm hardly confident in what I did. (Sorry I don't have this in patch format - my BerekelyDB.xs files is in a rather customized form and so I can't isolate the specific changes in a patch.)
First, I added a definition for ReleaseFILEptr. I think this is necessary if USE_PERLIO is defined which it is not for me and so I'm guessing.
#ifdef USE_PERLIO
# define GetFILEptr(sv) PerlIO_findFILE(IoIFP(sv_2io(sv)))
# define ReleaseFILEptr(p,sv) PerlIO_releaseFILE(p,IoIFP(sv_2io(sv)))
#else
# define GetFILEptr(sv) IoIFP(sv_2io(sv))
# define ReleaseFILEptr(p,sv)
#endif
and then in db_appexit(env) I changed this:
#if DB_VERSION_MAJOR == 2
RETVAL = db_appexit(env->Env) ;
#else
RETVAL = (env->Env->close)(env->Env, 0) ;
#endif
to this (I wasn't sure if the code applied to version 2 or not):
#if DB_VERSION_MAJOR == 2
RETVAL = db_appexit(env->Env) ;
#else
RETVAL = (env->Env->close)(env->Env, 0) ;
if (env->ErrHandle)
{
ReleaseFILEptr(env->Env->db_errfile,env->ErrHandle);
SvREFCNT_dec(env->ErrHandle) ;
}
#endif
Thanks again for a great module,
Mike