Thursday, March 22, 2012
Asynchronous ActiveX Replication Problems
I have a VB.NET service that has a timer. On certain timer ticks, a
merge replication is called.
I have a wrapper class that asynchronously starts the merge replication
process (using the .BeginInvoke() method). I did this so that my
service could continue to do other things while the merge replication
took place.
Through logging, I know that a separate thread is indeed handling the
replication process.
The problem is that the merge replication appears to block the calling
thread as soon as replication begins. I can see this happening because
I have logging statements inside the merge status event. I see the
calling thread continue to do work until the merge thread begins to
initialize. As soon as the merge is complete, the calling thread once
again continues.
At first I thought that maybe the entire process was blocked by the
merge replication ActiveX object, but the timer event continues to fire.
So it appears that only the calling thread is blocked.
Any ideas?
Thanks,
Jeff
are you using an MSDE database? MSDE is throttled at 8 simultaneous
workloads.
Perhaps this is the problem you are running into.
Hilary Cotter
Looking for a SQL Server replication book?
http://www.nwsu.com/0974973602.html
"Jeff Hedlund" <jeff.hedlund_NOSPAM_@._NOSPAM_elsym.com> wrote in message
news:Nu02d.286$DY.238@.chiapp18.algx.net...
> Hello,
> I have a VB.NET service that has a timer. On certain timer ticks, a
> merge replication is called.
> I have a wrapper class that asynchronously starts the merge replication
> process (using the .BeginInvoke() method). I did this so that my
> service could continue to do other things while the merge replication
> took place.
> Through logging, I know that a separate thread is indeed handling the
> replication process.
> The problem is that the merge replication appears to block the calling
> thread as soon as replication begins. I can see this happening because
> I have logging statements inside the merge status event. I see the
> calling thread continue to do work until the merge thread begins to
> initialize. As soon as the merge is complete, the calling thread once
> again continues.
> At first I thought that maybe the entire process was blocked by the
> merge replication ActiveX object, but the timer event continues to fire.
> So it appears that only the calling thread is blocked.
> Any ideas?
> Thanks,
> Jeff
|||Xref: TK2MSFTNGP08.phx.gbl microsoft.public.sqlserver.replication:56175
Hilary Cotter wrote:
> are you using an MSDE database? MSDE is throttled at 8 simultaneous
> workloads.
No, SQL Server 2000 on both publisher/distributor and subscriber.
But besides that, even if it were being throttled - it shouldn't block
the other thread from continue to process non-SQL Server instructions.
Thanks,
Jeff
|||Can you find out what the merge replication process is doing when it blocks
the other process?
If it is applying a snapshot you can expect blocking. For the type of
singleton transactions that merge replication uses you should not
experieince this level of locking, unless perhaps you are updating columns
which have indexes on them.
You might want to run sp_lock on the client to get an idea of what sort of
locks the replication process is applying.
You might also want to see if perhaps the locking is occuring due to your
code. For instance, I do not experience any locking when using databases
which are part of a merge publication or subscription when the merge
replication agents are running and when I am running the replication process
via tsql or em. This will rule out replication and give you a better window
into what is occuring.
Hilary Cotter
Looking for a SQL Server replication book?
http://www.nwsu.com/0974973602.html
"Jeff Hedlund" <jeff.hedlund_NOSPAM_@._NOSPAM_elsym.com> wrote in message
news:7b12d.297$DY.106@.chiapp18.algx.net...
> Hilary Cotter wrote:
> No, SQL Server 2000 on both publisher/distributor and subscriber.
> But besides that, even if it were being throttled - it shouldn't block
> the other thread from continue to process non-SQL Server instructions.
> Thanks,
> Jeff
|||Hilary Cotter wrote:
> Can you find out what the merge replication process is doing when it blocks
> the other process?
Yes: It blocks the calling thread as soon as I get the "Initializing"
status until I get the "Complete" status.
> If it is applying a snapshot you can expect blocking. For the type of
> singleton transactions that merge replication uses you should not
> experieince this level of locking, unless perhaps you are updating columns
> which have indexes on them.
> You might want to run sp_lock on the client to get an idea of what sort of
> locks the replication process is applying.
It sounds like you are describing a possible lock on the database. This
is not what is happening. What I am describing is my main thread in my
application is getting blocked until the merge thread (separate from the
main thread) is complete. The main thread is not doing any database
work at all when it gets blocked by the merge thread.
> You might also want to see if perhaps the locking is occuring due to your
> code. For instance, I do not experience any locking when using databases
> which are part of a merge publication or subscription when the merge
> replication agents are running and when I am running the replication process
> via tsql or em. This will rule out replication and give you a better window
> into what is occuring.
I am sure that if I were to run the replication from tsql or em it would
not block - because of my above paragraph. It's the actual ActiveX COM
replication object that is blocking my main thread for some reason. And
like I said in my original post, I am positive that the main thread is
properly spawning a new thread for the merge.
Thanks for the ideas!
Jeff
|||If you want to send the code to me, offline I'll try to repro it.
Otherwise I suggest you open a support incident with PSS.
Hilary Cotter
Looking for a SQL Server replication book?
http://www.nwsu.com/0974973602.html
"Jeff Hedlund" <jeff.hedlund_NOSPAM_@._NOSPAM_elsym.com> wrote in message
news:K%g2d.520$DY.90@.chiapp18.algx.net...[vbcol=seagreen]
> Hilary Cotter wrote:
blocks[vbcol=seagreen]
> Yes: It blocks the calling thread as soon as I get the "Initializing"
> status until I get the "Complete" status.
columns[vbcol=seagreen]
of[vbcol=seagreen]
> It sounds like you are describing a possible lock on the database. This
> is not what is happening. What I am describing is my main thread in my
> application is getting blocked until the merge thread (separate from the
> main thread) is complete. The main thread is not doing any database
> work at all when it gets blocked by the merge thread.
your[vbcol=seagreen]
process[vbcol=seagreen]
window
> I am sure that if I were to run the replication from tsql or em it would
> not block - because of my above paragraph. It's the actual ActiveX COM
> replication object that is blocking my main thread for some reason. And
> like I said in my original post, I am positive that the main thread is
> properly spawning a new thread for the merge.
> Thanks for the ideas!
> Jeff
|||Jeff Hedlund wrote:
> The problem is that the merge replication appears to block the calling
> thread as soon as replication begins.
FYI - I have found the source of my problem. When using BeginInvoke()
to create a separate thread for the replication object, VB.NET uses a
thread from the thread pool.
The thread pool operates with the MTA apartment state. The SQL
replication ActiveX object apparently uses STA, so it was blocking the
MTA apartment while it ran. Make sure I used an STA thread to run the
SQL replication object on solved the blocking problem.
Thanks,
Jeff
sql
Wednesday, March 7, 2012
Assertion failed error while resizing a vector in a plug-in algorithm
I got an Assertion failed error while resizing a vector in a plug-in algorithm.
In order to isolate the problem I created a simple model class in Navigator.h file as shown below:
//========================= begin code =======================
class CStateStats
{
public:
DOUBLE m_dblSum;
DOUBLE m_dblSqrSum;
public:
CStateStats()
{
m_dblSum = 0.0;
m_dblSqrSum = 0.0;
}
};
class CAttStats : public DMHALLOC
{
public:
dmh_vector<CStateStats> vstatestats;
public:
CAttStats() : vstatestats (*this)
{
}
};
//========================= end code =======================
The access to DMHALLOC is provided in that class and in Navigator class as shown below:
//========================= begin code =======================
class ATL_NO_VTABLE NAVIGATOR :
public DMHALLOC,
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<NAVIGATOR, &CLSID_NAVIGATOR>,
public ISupportErrorInfo,
public IDMAlgorithmNavigation
{
public:
NAVIGATOR() : _viAttributeOutput(*this), _vCAttStats(*this)
//========================= end code =======================
I succeded making room for _vCAttStats vector, but when I tried providing room for the vectors of the vector I got an Assertion failed error (file dmhallocator.h Line:56 Expression assert(_dmhalloc._spidmmemoryallocator != NULL)). Please, see the code below, included in NAVIGATOR::GetNodeArrayProperty function:
//========================= begin code =======================
_vCAttStats.resize (2); // <<<<< succeeded here!
// make space for the states
_vCAttStats[0].vstatestats.resize(ulStates); // <<<<<<< assertion failed here!
//========================= end code =======================
I tried using a vector-of-vector approach and I also succeeded.
But I have to use that kind of structure: a vector of class with a vector inside.
I think I must provide a similar approach of vector-of-vector existing in DmhVector.h but I don't know how to do it.
I would apreciate any help.
hello,Claudio
It looks like:
- the original DMHALLOC (containing the allocator pointer), NAVIGATOR is passed properly to the vector of CAttStats, _vCAttStats and used correctly in resizing it
- during resize, STL calls the default constructor for CAttStats , which does not take any argument. Consequently, the CAttStats DMHALLOC instance does not contain an allocator pointer
- _vCAttStats[0].vstatestats.resize(ulStates); attempts to resize the vstatestats vector, which does not have a properly initialized DMHALLOC , hence the assertion that fails
To confirm my hypothesis in your code, try to use _vCAttStats[0].vstatestats.get_allocator() right before calling resize. It is likely NULL or uninitialized (well, not the actual object which is a reference, but the IDMMemoryAllocator pointer it contains).
The simplest and most reliable solution is:
- do not derive CAttStats from DMHALLOC
- use, instead, an IDMMemoryAllocator member inside the CAttStats
- explicitly set that member to the current allocator before using vstatestats
- use IDMMemoryAllocator->Alloc( n*sizeof(CStateStats) ) to get a C-style buffer of state stats which can be freed in the destructor of CAttStats with IDMMemoryAllocator->Free
Hope this helps
|||Hi Bogdan,
Thanks for you help.
I suceeded using your suggestions.
The drawbacks of this approach are that I have to explicitly initialize vstatestats because the class constructor is not called anymore when I provide room for the buffer and I don't have anymore the vector facilities. Am I correct?