I'm using Postmodern to query and update a table in a database. The
application is networked and threaded, and in the past we've had
issues where we get compilation style warnings at run time, and even
errors which pop up the debugger. These issues arose when we began
flowing client traffic to our application, and I thought that they
might be because of some race condition in Postmodern's internals when
it starts doing MOP operations on our class which has had
(:metaclass dao-class) added to its class definition.
Because I suspected a race condition--that multiple threads might be
trying to instantiate the MOP stuff around our database accessor class
at once--I worked around it by having our startup procedure do a
single database access before allowing any client traffic in. That
seemed to help things for a while, but this morning I was using the
profiler to instrument our code. When I ran the program, and at a
point where only that one retrieval should've been running, it popped
up with an error in the debugger.
I'm using postmodern-20120520-git as loaded through Quicklisp, on SBCL
1.0.57. The issues have arisen on a variety of x86 hardware, both 32-
and 64-bits.
Here's the defclass for the table in question:
(defclass device ()
((device-uid :col-type integer :initarg :device-uid :accessor device-uid)
(macaddress :col-type string :accessor device-macaddress)
(status :col-type string :accessor device-status)
(state :col-type string :initarg :state :accessor device-state)
(nature :col-type string :accessor device-nature)
(client-uid :col-type integer :accessor device-client-uid)
(user-uid :col-type integer :accessor device-user-uid))
(:metaclass dao-class)
(:keys device-uid))
and here's the function which we call to prime the pump at the start
of program execution:
(defun get-device-object-by-device-uid (device-uid)
(with-connection *db-parameters*
(log-message :device-dao-bug "In get-device-object-by-device-uid,
device-uid = ~A" device-uid)
(let ((result (query (:select '* :from 'device :where (:= 'device-uid
device-uid)) (:dao device))))
(log-message :device-dao-bug "Finished query in
get-device-object-by-device-uid.")
(if result
(car result)
nil))))
The error I got this morning was:
POSTMODERN:DAO-EXISTS-P already names an ordinary function or a macro.
[Condition of type SB-INT:SIMPLE-PROGRAM-ERROR]
Restarts:
0: [CONTINUE] Replace the function binding
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] Abort thread (#<THREAD "repl-thread" RUNNING {1003E48113}>)
Backtrace:
0: (ENSURE-GENERIC-FUNCTION POSTMODERN:DAO-EXISTS-P)
1: (SB-PCL::REAL-ADD-NAMED-METHOD POSTMODERN:DAO-EXISTS-P NIL
(#<POSTMODERN:DAO-CLASS PROJECT-PACKAGENAME:DEVICE>) (POSTMODERN::OBJECT)
#<unavailable &REST argument>)
2: (SB-PCL::LOAD-DEFMETHOD-INTERNAL ..)
3: ((LAMBDA ()))
4: ((LAMBDA (SB-INT:&MORE SB-PROFILE::ARG-CONTEXT SB-PROFILE::ARG-COUNT) :IN
SB-PROFILE::PROFILE-ENCAPSULATION-LAMBDAS) #<unavailable &MORE argument>)
5: ((LAMBDA (SB-INT:&MORE SB-PROFILE::ARG-CONTEXT SB-PROFILE::ARG-COUNT) :IN
SB-PROFILE::PROFILE-ENCAPSULATION-LAMBDAS) #<unavailable &MORE argument>)
6: ((SB-PCL::EMF SB-MOP:FINALIZE-INHERITANCE) #<unavailable argument>
#<unavailable argument> #<POSTMODERN:DAO-CLASS PROJECT-PACKAGENAME:DEVICE>)
7: (PROJECT-PACKAGENAME::GET-DEVICE-OBJECT-BY-DEVICE-UID 1)
Earlier, when we were allowing multiple threads to access this object
at the same time, we got output like this (all of the following is output from
one session):
debugger invoked on a UNBOUND-SLOT in thread
#<THREAD "message handler2" RUNNING {1004843BE3}>:
The slot POSTMODERN::COLUMN-MAP is unbound in the object
#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>.
STYLE-WARNING:
redefining POSTMODERN:DAO-EXISTS-P (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:UPDATE-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:DELETE-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:GET-DAO (#<SB-MOP:EQL-SPECIALIZER
{100C80AFB3}>) in DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:INSERT-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN::FETCH-DEFAULTS (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining SHARED-INITIALIZE :AFTER (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>
#<BUILT-IN-CLASS T>) in DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:DAO-EXISTS-P (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:UPDATE-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:DELETE-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:GET-DAO (#<SB-MOP:EQL-SPECIALIZER
{100C80AFB3}>) in DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:INSERT-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN::FETCH-DEFAULTS (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining SHARED-INITIALIZE :AFTER (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>
#<BUILT-IN-CLASS T>) in DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:DAO-EXISTS-P (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:UPDATE-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:DELETE-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:GET-DAO (#<SB-MOP:EQL-SPECIALIZER
{100C80AFB3}>) in DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN:INSERT-DAO (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining POSTMODERN::FETCH-DEFAULTS (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>) in
DEFMETHOD
STYLE-WARNING:
redefining SHARED-INITIALIZE :AFTER (#<POSTMODERN:DAO-CLASS
PROJECT-PACKAGENAME:DEVICE>
#<BUILT-IN-CLASS T>) in DEFMETHOD
For the time being, we're planning to work around this by avoiding the
use of the dao-class metaclass; we'll write our database queries to
return lists or alists, and we'll write update operations directly as
SQL or S-SQL queries instead of using update-dao. If there's a way to
address this problem and continue using the dao-class metaclass,
though, we'd rather do that.
Any advice would be most welcome.
Keith Browne