[jira] [Commented] (OFBIZ-3557) Enforced sequence does not work with concurrent access

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[jira] [Commented] (OFBIZ-3557) Enforced sequence does not work with concurrent access

Nicolas Malin (Jira)

    [ https://issues.apache.org/jira/browse/OFBIZ-3557?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13040315#comment-13040315 ]

Bruno Brandmeier commented on OFBIZ-3557:
-----------------------------------------

Hi all,

why not using a lock table like this (example in c#):

c_Lock mylock = new c_Lock("rechnungs_nr");            
mylock.use_lock();
int nur_rechnungs_nr = mylock.increment_counter();
mylock.open_lock();

    class c_Lock
    {

        string name = "";                          
        string lock_closed_by = "";                
        int lock_counter = 0;                      
        bool can_use_lock_now = false;            
        string unique_id = "";                    
        MySqlConnection conn_shop = null;
        c_BB_Shop bb_shop = new c_BB_Shop();
        string sql_string = "";
        MySqlDataAdapter da = null;
        System.Data.DataTable dt_remote = null;
        DataRow row_remote = null;
        MySqlCommand cmd = null;
        BB_Gen.c_BB_Gen bb_gen = new BB_Gen.c_BB_Gen();

        public c_Lock(string feldname)
        {
            name = feldname;
            if (name == "")
            {
                MessageBox.Show("Feldname wurde nicht übergeben");
            }
            else
            {
                conn_shop = bb_gen.conn_open(bb_shop.g_connectionstring_shop);
                read_lock();
            }
            Random zufallszahlen = new Random();
            unique_id = zufallszahlen.NextDouble().ToString().Substring(2).PadRight(18, Convert.ToChar("0"));
        }


        public bool use_lock()
        {
            int start_zeit = 0;
            int schloss_geschlossen_seit = 0;
            int max_lock_lease = 10;      
            int aktuelle_zeit = 0;
            bool result = false;
            if (row_remote["lock_type"].ToString() != "undefined")
            {
                start_zeit = bb_gen.unix_timestamp();
                while ((result = close_lock()) == false)
                {
                    aktuelle_zeit = bb_gen.unix_timestamp();
                    schloss_geschlossen_seit = int.Parse(row_remote["lock_closed_since"].ToString());
                    if (((aktuelle_zeit - start_zeit) > max_lock_lease) && ((aktuelle_zeit - schloss_geschlossen_seit) > max_lock_lease))
                    {
                        crack_lock();
                        break;
                    }
                    else
                    {
                        Thread.Sleep(1000);
                        read_lock();
                    }
                }
            }
            else
            {
                result = false;
            }

            return result;
        }


        public void open_lock()
        {
            if (can_use_lock_now == true)
            {

                sql_string = "UPDATE locks SET lock_status='unlocked',lock_closed_by='',lock_closed_since='0' WHERE Lock_ID='" + row_remote["Lock_ID"].ToString() + "';";
                cmd = new MySqlCommand(sql_string, conn_shop);
                int ergebnis = cmd.ExecuteNonQuery();
                cmd.Dispose();
                if (ergebnis == 1)
                {
                    lock_closed_by = "";
                    can_use_lock_now = false;
                }
            }
            conn_shop.Close();
            conn_shop.Dispose();
        }


        private bool crack_lock()
        {
            bool result_var = false;
            sql_string = "UPDATE locks SET lock_status='locked',lock_closed_by='" + unique_id + "' WHERE Lock_ID='" + row_remote["Lock_ID"].ToString() + "';";
            cmd = new MySqlCommand(sql_string, conn_shop);
            int ergebnis = cmd.ExecuteNonQuery();
            cmd.Dispose();
            if (ergebnis == 1)
            {
                lock_closed_by = unique_id;
                can_use_lock_now = true;
                result_var = true;
            }
            else
            {
                result_var = false;
            }
            return result_var;
        }


        public int increment_counter()
        {
            int return_var = 0;
            if (can_use_lock_now == true && row_remote["lock_type"].ToString() == "counter")
            {
                sql_string = "SELECT lock_counter FROM locks WHERE Lock_ID='" + row_remote["Lock_ID"].ToString() + "';";
                cmd = new MySqlCommand(sql_string, conn_shop);
                int result = int.Parse(cmd.ExecuteScalar().ToString());
                cmd.Dispose();
                if (result == 0)
                {
                    return_var = 0;
                }
                else
                {
                    int lock_counter_incremented = result;
                    lock_counter_incremented++;
                    sql_string = "UPDATE locks SET lock_counter='" + lock_counter_incremented.ToString() + "' WHERE Lock_ID='" + row_remote["Lock_ID"].ToString() + "';";
                    cmd = new MySqlCommand(sql_string, conn_shop);
                    int ergebnis = cmd.ExecuteNonQuery();
                    cmd.Dispose();
                    if (ergebnis == 0)
                    {
                        return_var = 0;
                    }
                    else
                    {
                        lock_counter = lock_counter_incremented;
                        return_var = lock_counter_incremented;
                    }
                }
            }
            else
            {
                return_var = 0;
            }
            return return_var;
        }


        private bool close_lock()
        {
            bool result_var = false;
            string object_identifier = unique_id;
            sql_string = "UPDATE locks SET lock_status='locked',lock_closed_by='" + unique_id + "', lock_closed_since='" + bb_gen.unix_timestamp().ToString() + "' WHERE Lock_ID='" + row_remote["Lock_ID"].ToString() + "' AND lock_status='unlocked';";
            cmd = new MySqlCommand(sql_string, conn_shop);
            int ergebnis = cmd.ExecuteNonQuery();
            cmd.Dispose();
            if (ergebnis == 0)
            {
                result_var = false;
            }
            else
            {
                sql_string = "SELECT lock_closed_by FROM locks WHERE Lock_ID='" + row_remote["Lock_ID"].ToString() + "';";
                cmd = new MySqlCommand(sql_string, conn_shop);
                string object_identifier_aus_db = cmd.ExecuteScalar().ToString();
                cmd.Dispose();
                if (object_identifier_aus_db != object_identifier)
                {
                    read_lock();
                    result_var = false;
                }
                else
                {
                    lock_closed_by = object_identifier;
                    can_use_lock_now = true;
                    result_var = true;
                }
            }
            return result_var;
        }


        private bool read_lock()
        {
            bool return_val = false;
            sql_string = "SELECT * FROM locks where name='" + name + "';";
            da = new MySqlDataAdapter(sql_string, conn_shop);
            dt_remote = new System.Data.DataTable();
            da.Fill(dt_remote);
            if (dt_remote.Rows.Count == 1)
            {
                row_remote = dt_remote.Rows[0];
                return_val = true;
            }
            return return_val;
        }

    }

Bruno

> Enforced sequence does not work with concurrent access
> ------------------------------------------------------
>
>                 Key: OFBIZ-3557
>                 URL: https://issues.apache.org/jira/browse/OFBIZ-3557
>             Project: OFBiz
>          Issue Type: Bug
>          Components: framework
>    Affects Versions: Release Branch 09.04, SVN trunk
>            Reporter: Wickersheimer Jeremy
>         Attachments: OFBIZ-3557-1.patch, OFBIZ-3557-2.patch
>
>
> There is a fundamental issue with enforced sequences (for orders, invoices, etc ..) and concurrency.
> For example if two users are creating an order at the same time one of them will see the creation fail with a PK error. The problem is that the "getNextXXXId" rely on the party accounting preference entity, but there is absolutely no guarantee that the last number in the sequence gets updated before another service can read it.
> This is at best very annoying when used only internally but may be unpractical for e-commerce sites.

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira