1

We're writing a routine which either returns an editable object, or a status object that says the underlying record is locked.

We're using C# and .NET Framework 4.8 with the Progress OpenEdge ODBC driver against an OpenEdge database. The record might be locked by legacy ABL code, which is why we want to check with a ReadCommitted transaction to see if it's safe for us to start editing it.

Functionally, the code works fine, doing exactly what we expect it to do. When the underlying record is not locked, it returns the object in a matter of milliseconds; when it's locked, it returns an object that describes the locked status of the record.

But when the underlying record is indeed locked it takes upwards of 15 seconds to return with the expected "ERROR [HY000] [DataDirect][ODBC Progress OpenEdge Wire Protocol driver][OPENEDGE]Failure getting record lock on a record from table PUB.i-mst."

I have tried decreasing the CommandTimeout value, but that only (eventually, as I decrease it incrementally) ultimately changes the failure to a timeout error.

Is there some lower-level setting to control how long either ODBC or OpenEdge takes to wait for a lock to be released before failing?

Here's the code:

        public static dynamic ReadOdbcForEdit(OdbcConnection connection, string type, string criteria, string domain,
            string parentClass, string application)
        {
            connection.Open();
            var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
            Type objectType = Object.GetJohnstonType(parentClass + type, domain, application);
            var tempObj = Activator.CreateInstance(objectType);

            try
            {
                var odbcCommand = new OdbcCommand(criteria)
                {
                    Connection = connection,
                    Transaction = transaction,
                    CommandTimeout = 30
                };

                var reader = odbcCommand.ExecuteReader();

                while (reader.Read())
                {

                    foreach (var property in tempObj.GetType().GetProperties())
                    {

                        var propertyType = property.PropertyType;
                        var propertyName = property.Name;

                        if (propertyType.IsArray ||
                            propertyType.IsGenericType &&
                            propertyType.GetGenericTypeDefinition() == typeof(List<>))
                        {
                            continue;
                        }

                        try
                        {
                            if (reader[propertyName].GetType() != typeof(DBNull))
                            {
                                property.SetValue(tempObj, reader[propertyName]);
                            }
                        }
                        catch (Exception e)
                        {
                            Logging.Message($"Could not fill {propertyName} from database column");
                            Logging.Exception(e);
                        }
                    }

                } 

                return tempObj;
            }
            catch (Exception e)
            {
                var openRecordStatus = new OpenRecordStatus
                {
                    StatusCode = e.HResult,
                    StatusMessage = e.Message
                };
                return openRecordStatus;
            }
        }
Tom Bascom
  • 13,405
  • 2
  • 27
  • 33

1 Answers1

1

You probably want to adjust -SQLLockWaitTimeout

https://knowledgebase.progress.com/articles/Article/What-is-the-SQLLockWaitTimeout-Parameter

The -SQLLockWaitTimeout parameter is used to identify the number of seconds to wait when a lock conflict occurs. The default is 5 seconds.

This value applies to all lock conflicts experienced by SQL applications. So an installation that gets a lot of lock conflicts (does a lot of updating) would want to consider the impact of changing this parameter.

For older versions of Progress (prior to 11.4): https://knowledgebase.progress.com/articles/Article/P123923

The PROSQL_LOCKWAIT_TIMEOUT environment variable was introduced in 9.1D06 and is used to limit how long a client will wait for a record that has a share or exclusive lock against it. This setting does not effect and is not needed for an SQL Client with an isolation level of READ UNCOMMITTED, because it will read a record that has a share or exclusive lock against it.

The PROSQL_LOCKWAIT_TIMEOUT environment variable enables one to determine how long SQL clients will wait in a lock queue for a particular record. The environment variable must be present before a broker is started and is applied to every SQL connection of the broker.

The minimum time-out value is the default of five seconds (DFLT_LOCKWAIT-TIMEOUT). The maximum time-out value is limited to a 32-bit integer value of 4,294,967,295 seconds or 1,193,046.5 hours.

This environment variable can be set prior to starting the database broker or AdminServer. For example, to set it to 30 seconds:

UNIX: PROSQL_LOCKWAIT_TIMEOUT=30 ; export PROSQL_LOCKWAIT_TIMEOUT

Windows: Control Panel -> System -> Advanced tab -> Environment Variables -> System Variables. Add a new variable.

In OpenEdge 11.4 and later there is a -SQLLockWaitTimeout startup parameter that can be used to accomplish the same goal as the environment variable. See article: 000064602, What is the -SQLLockWaitTimeout Parameter? for additional information.

Tom Bascom
  • 13,405
  • 2
  • 27
  • 33
  • Unfortunately, this is probably not an option for our environment, but I'll consult with our OpenEdge DBA. Thanks for looking into it! – J. Hochberg Nov 05 '19 at 12:18
  • Just curious but why would it not be an option? It seems like exactly what you're asking for so I must not be understanding some part of your requirement. – Tom Bascom Nov 06 '19 at 15:20
  • We've re-read the response and background KB articles and realized that this pertains *only* to SQL, so it does indeed look like the right solution. My only concern is that the current response time is more on the order of 15 seconds, and so I'm not sure whether changing the parameter will actually be of benefit. It doesn't hurt to try. :) – J. Hochberg Nov 06 '19 at 16:43