.NET Connection Pooling

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

.NET Connection Pooling

Kyle Fransham

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Greg Boone

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Greg Boone
In reply to this post by Kyle Fransham

Oh… one more point….

 

The call I mention needs to be done before any FDO connections/objects are created.

 

Greg

 

From: Greg Boone
Sent: Thursday, February 16, 2012 1:50 PM
To: [hidden email]
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Kyle Fransham
In reply to this post by Greg Boone

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Greg Boone

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Romica Dascalescu

I think we should expose this static method in C# in FDO 3.8 release J

 

Romy

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Greg Boone
Sent: Thursday, February 16, 2012 2:41 PM
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Greg Boone

Yes. Fine by me.

 

Greg

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Romica Dascalescu
Sent: Thursday, February 16, 2012 2:44 PM
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

I think we should expose this static method in C# in FDO 3.8 release J

 

Romy

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: Thursday, February 16, 2012 2:41 PM
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Kyle Fransham
In reply to this post by Greg Boone

Turns out that I had to explicitly specify the entry point:

 

        [DllImport("FDOCommon.dll", EntryPoint = "?EnableGlobalThreadLocking@FdoIDisposable@@SAX_N@Z", CallingConvention = CallingConvention.ThisCall)]

        public static extern void EnableGlobalThreadLocking(bool enabled);

 

 

And this is now working.  Case closed!

 

Thanks again for all your help.

 

Kyle

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Greg Boone
Sent: February-16-12 14:41
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Romica Dascalescu

Be aware that the name is different on x64 platform, so you would need something like:

 

[DllImport("FDOCommon.dll", EntryPoint = "...x64 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking64(bool enabled);

 

[DllImport("FDOCommon.dll", EntryPoint = "...x86 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking32(bool enabled);

 

public static void EnableGlobalThreadLocking(bool enabled)

{

   if (IntPtr.Size == 8)

        EnableGlobalThreadLocking64(enabled);

   else

        EnableGlobalThreadLocking32(enabled);

}

 

Romy.

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:51 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Turns out that I had to explicitly specify the entry point:

 

        [DllImport("FDOCommon.dll", EntryPoint = "?EnableGlobalThreadLocking@FdoIDisposable@@SAX_N@Z", CallingConvention = CallingConvention.ThisCall)]

        public static extern void EnableGlobalThreadLocking(bool enabled);

 

 

And this is now working.  Case closed!

 

Thanks again for all your help.

 

Kyle

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Greg Boone
Sent: February-16-12 14:41
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Kyle Fransham

Hi Romy, Greg,

 

Thanks for the x64 tip.  Unfortunately, calling this method didn’t seem to solve my problem.  (The exception still occurs.)  I did ensure that this method was called on app startup, before any FDO objects were created.  Could it be that it needs to be compiled into the C# dll to be effective?  If so, is there any place I could download the C# api to roll my own libraries with this function included?  Or maybe you have other ideas?  Any suggestions you could give me would be greatly appreciated.

 

Thanks again for all your help so far.

 

Kyle

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Romica Dascalescu
Sent: February-16-12 15:37
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Be aware that the name is different on x64 platform, so you would need something like:

 

[DllImport("FDOCommon.dll", EntryPoint = "...x64 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking64(bool enabled);

 

[DllImport("FDOCommon.dll", EntryPoint = "...x86 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking32(bool enabled);

 

public static void EnableGlobalThreadLocking(bool enabled)

{

   if (IntPtr.Size == 8)

        EnableGlobalThreadLocking64(enabled);

   else

        EnableGlobalThreadLocking32(enabled);

}

 

Romy.

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:51 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Turns out that I had to explicitly specify the entry point:

 

        [DllImport("FDOCommon.dll", EntryPoint = "?EnableGlobalThreadLocking@FdoIDisposable@@SAX_N@Z", CallingConvention = CallingConvention.ThisCall)]

        public static extern void EnableGlobalThreadLocking(bool enabled);

 

 

And this is now working.  Case closed!

 

Thanks again for all your help.

 

Kyle

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 14:41
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users

image001.png (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Romica Dascalescu

I'm not sure this will fix your issue, however is nice to know.

I would avoid using FDO #C API like below (I'm not sure if you do use such code style):

int cnt = connection.ExpressionCapabilities.Functions.Count;

 

You should do it like:

IExpressionCapabilities expCap = connection.ExpressionCapabilities;

FunctionDefinitionCollection fcts = expCap.Functions;

int cnt = fcts.Count;

 

Even try adding using(){}

 

I got crashes in case I did not avoid this type of code...

 

Romy


From: [hidden email] [[hidden email]] on behalf of Kyle Fransham [[hidden email]]
Sent: Friday, February 17, 2012 8:12 AM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

Hi Romy, Greg,

 

Thanks for the x64 tip.  Unfortunately, calling this method didn’t seem to solve my problem.  (The exception still occurs.)  I did ensure that this method was called on app startup, before any FDO objects were created.  Could it be that it needs to be compiled into the C# dll to be effective?  If so, is there any place I could download the C# api to roll my own libraries with this function included?  Or maybe you have other ideas?  Any suggestions you could give me would be greatly appreciated.

 

Thanks again for all your help so far.

 

Kyle

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Romica Dascalescu
Sent: February-16-12 15:37
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Be aware that the name is different on x64 platform, so you would need something like:

 

[DllImport("FDOCommon.dll", EntryPoint = "...x64 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking64(bool enabled);

 

[DllImport("FDOCommon.dll", EntryPoint = "...x86 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking32(bool enabled);

 

public static void EnableGlobalThreadLocking(bool enabled)

{

   if (IntPtr.Size == 8)

        EnableGlobalThreadLocking64(enabled);

   else

        EnableGlobalThreadLocking32(enabled);

}

 

Romy.

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:51 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Turns out that I had to explicitly specify the entry point:

 

        [DllImport("FDOCommon.dll", EntryPoint = "?EnableGlobalThreadLocking@FdoIDisposable@@SAX_N@Z", CallingConvention = CallingConvention.ThisCall)]

        public static extern void EnableGlobalThreadLocking(bool enabled);

 

 

And this is now working.  Case closed!

 

Thanks again for all your help.

 

Kyle

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 14:41
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users
Reply | Threaded
Open this post in threaded view
|

RE: .NET Connection Pooling

Greg Boone

Both of Romy’s suggestions are very useful. 

 

Avoiding calling FDO using ‘a.b.c.function()’ is an important one.

 

Also note that MS recommends using the ‘using’ mechanism in cases such as this, where a managed object wraps a native object, specifically so that garbage collection is handled correctly.

 

Greg

 

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Romica Dascalescu
Sent: Friday, February 17, 2012 9:33 AM
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

I'm not sure this will fix your issue, however is nice to know.

I would avoid using FDO #C API like below (I'm not sure if you do use such code style):

int cnt = connection.ExpressionCapabilities.Functions.Count;

 

You should do it like:

IExpressionCapabilities expCap = connection.ExpressionCapabilities;

FunctionDefinitionCollection fcts = expCap.Functions;

int cnt = fcts.Count;

 

Even try adding using(){}

 

I got crashes in case I did not avoid this type of code...

 

Romy


From: [hidden email] [[hidden email]] on behalf of Kyle Fransham [[hidden email]]
Sent: Friday, February 17, 2012 8:12 AM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

Hi Romy, Greg,

 

Thanks for the x64 tip.  Unfortunately, calling this method didn’t seem to solve my problem.  (The exception still occurs.)  I did ensure that this method was called on app startup, before any FDO objects were created.  Could it be that it needs to be compiled into the C# dll to be effective?  If so, is there any place I could download the C# api to roll my own libraries with this function included?  Or maybe you have other ideas?  Any suggestions you could give me would be greatly appreciated.

 

Thanks again for all your help so far.

 

Kyle

 

From: [hidden email] [hidden email] On Behalf Of Romica Dascalescu
Sent: February-16-12 15:37
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Be aware that the name is different on x64 platform, so you would need something like:

 

[DllImport("FDOCommon.dll", EntryPoint = "...x64 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking64(bool enabled);

 

[DllImport("FDOCommon.dll", EntryPoint = "...x86 name", CallingConvention = CallingConvention.ThisCall)]

private static extern void EnableGlobalThreadLocking32(bool enabled);

 

public static void EnableGlobalThreadLocking(bool enabled)

{

   if (IntPtr.Size == 8)

        EnableGlobalThreadLocking64(enabled);

   else

        EnableGlobalThreadLocking32(enabled);

}

 

Romy.

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:51 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Turns out that I had to explicitly specify the entry point:

 

        [DllImport("FDOCommon.dll", EntryPoint = "?EnableGlobalThreadLocking@FdoIDisposable@@SAX_N@Z", CallingConvention = CallingConvention.ThisCall)]

        public static extern void EnableGlobalThreadLocking(bool enabled);

 

 

And this is now working.  Case closed!

 

Thanks again for all your help.

 

Kyle

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 14:41
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Your code segment looks ok, but I have not tried executing it in that manner.

 

It is not included in the C# API.

 

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 2:32 PM
To: 'FDO Users Mail List'
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Greg,

 

Great, thanks for the quick answer.  So, to call the function from C#, I would do something like:

 

[DllImport("FDOCommon.dll")]

public static extern void EnableGlobalThreadLocking(bool enabled);

 

Correct?   Or is it already included somewhere in the C# provider?

 

Thanks,

 

Kyle

 

 

From: [hidden email] [hidden email] On Behalf Of Greg Boone
Sent: February-16-12 13:50
To: FDO Users Mail List
Subject: RE: [fdo-users] .NET Connection Pooling

 

Hi Kyle,

 

Yes, this is a known issue. Using, and later disposing, FDO objects across multiple threads can lead to an exception.

 

When you application starts up, what you need to invoke is the following method (C++)

 

                    FdoIDisposable:EnableGlobalThreadLocking(true);

 

Located in:  ….\FDO\Fdo\Unmanaged\Inc\Common\IDisposable.h

 

Regards,

Greg

 

From: [hidden email] [hidden email] On Behalf Of Kyle Fransham
Sent: Thursday, February 16, 2012 1:09 PM
To: [hidden email]
Subject: [fdo-users] .NET Connection Pooling

 

Hello,

 

I’m trying to implement a connection pool for a C# .NET project that uses FDO backed by MySQL 5.5, and I’m running into a bit of trouble.  I have a static pool of OSGeo.FDO.Connection.IConnection objects that I pass off to threads as they request them.  When the thread is done with the connection, it returns it to the pool.

 

Before the pool gives out a connection, it does a simple check by issuing a “SELECT 1” and if all is well, the connection gets sent out.  If the command fails, the connection is closed, and the next connection in the pool is tested.  If there are no valid connections in the pool, a new one is leased out.   This all works fine, for a while.  After a period of time, though, my app pool throws an unhandled exception that I believe is coming from the finalize thread.  All of my statements are encased in try-catch blocks, so I think that there is some object that’s being disposed of by the garbage collector that’s causing the error to occur.  But I’m not sure. 

 

I’ve appended the exception and the code for the connection pool to this e-mail… Does anyone see if I’m doing something completely wrong?  Any suggestions on what to try next?

 

Thanks in advance,

 

Kyle Fransham

 

******************************************************************

Here is the exception that I see in the debugger:

 

Message: “Connection not established”

Stack Trace:  

   at OSGeo.FDO.Runtime.Disposable.ReleaseUnmanagedObject()

   at OSGeo.FDO.Runtime.Disposable.!Disposable()

   at OSGeo.FDO.Runtime.Disposable.Dispose(Boolean )

   at OSGeo.FDO.Runtime.Disposable.Finalize()

 

*******************************************************************

Here is the connection pool code:

 

using System;

using System.Collections.Concurrent;

using System.Linq;

using System.Web;

using OSGeo.FDO.Connections;

using System.Security.Permissions;

using System.Threading;

 

namespace GVFFDOProvider

{

    public sealed class ConnectionPool

    {

 

        #region Member Variables

 

        private static readonly int n_cached_connections =

            Convert.ToInt32(Properties.Settings.Default.number_of_cached_connections);

 

        private ConcurrentQueue<IConnection> pool;

 

        private GVFInterfaces m_gvfinterfaces =

            GVFInterfaces.CreateInstance(

                AppDomain.CurrentDomain.BaseDirectory + "GVFExceptionLog.txt");

 

        #endregion

 

        #region Constructors

        /// <summary>

        /// The following class implements a thread-safe singleton pattern.

        /// </summary>

        private static readonly ConnectionPool instance = new ConnectionPool();

 

        private ConnectionPool()

        {

            pool = new ConcurrentQueue<IConnection>();

            for (int i = 0; i < n_cached_connections; i++)

            {

                pool.Enqueue(GetNewConnection());

            }

 

        }

 

        public static ConnectionPool Instance

        {

            get

            {

                return instance;

            }

        }

        #endregion

 

        #region Private Functions

 

 

        private bool ConnectionIsAlive(IConnection connection)

        {

            try

            {

               if (m_gvfinterfaces.TestConnection(connection))

                        return true;

               connection.Close();

            }

            catch

            {

                // Connection is closed.  Return false;

            }

            return false;

        }

 

        private IConnection GetNewConnection()

        {

            return m_gvfinterfaces

                    .GetConnection(Properties.Settings.Default.fdo_user,

                                   Properties.Settings.Default.fdo_password,

                                   Properties.Settings.Default.fdo_service,

                                   Properties.Settings.Default.fdo_datastore,

                                   false);

        }

 

        #endregion

 

        #region Public Functions

 

        /// <summary>

        /// Gets a connection from the pool if one is available and alive,

        /// or returns a new connection.

        /// </summary>

        /// <returns></returns>

        public IConnection GetConnection()

        {

            IConnection connection;

            try

            {

                while (pool.Count() > 0)

                {

                    if (pool.TryDequeue(out connection) && ConnectionIsAlive(connection))

                    {

                        return connection;

                    }

                }

            }

            catch

            {

                // Do nothing, just return a new connection.  

            }

            return GetNewConnection();

        }

 

        /// <summary>

        /// Returns a connection to the pool.

        /// </summary>

        /// <param name="connection"></param>

        public void ReturnConnection(IConnection connection)

        {

 

            if (pool.Count < n_cached_connections && ConnectionIsAlive(connection))

            {

                pool.Enqueue(connection);

            }

        }  

 

        #endregion

    }

 

}

 

 

 

 

 

Description: Description: Description: Description: emailKYLE FRANSHAM  Software Developer

613-729-1100 ext. 330 (w) | www.superna.net

Superna  is located at 300 Terry Fox Drive, Unit 700, Kanata, Ontario K2K 0E3.


CONFIDENTIALITY NOTICE: The information contained in this email is privileged and confidential and intended only for the use of the individual or entity to whom it is addressed.  If you are not the intended recipient, you are hereby notified that any distribution, copying, or disclosure or taking of any action in reliance on the contents of this transmission is strictly prohibited and review by any individual other than the intended recipient shall not constitute waiver of privilege.  If you receive this message in error, please notify the sender immediately at 613-729-1100 and destroy the original message and all copies. Thank you.


 

 


_______________________________________________
fdo-users mailing list
[hidden email]
http://lists.osgeo.org/mailman/listinfo/fdo-users