• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

Fixed xf_deferred: Data too long for column 'unique_key'

Chris D

XenForo developer
Staff member
#1
The unique_key column in xf_deferred is VARBINARY(50)

My deferred class name happens to be 47 characters long and actionTriggerDeferred simply passes Rebuild + Class_Name to the defer method as the unique key:

PHP:
XenForo_Application::defer($input['cache'], $input['options'], 'Rebuild' . $input['cache'], true);
It would be nice to see:

PHP:
        $input = $this->_input->filter(array(
            'cache' => XenForo_Input::STRING,
            'options' => XenForo_Input::ARRAY_SIMPLE,
            'unique_key' => XenForo_Input::STRING
        ));

        if ($input['cache'])
        {
            if (!$input['unique_key'])
            {
                $input['unique_key'] = 'Rebuild_' . $input['cache'];
            }

            $obj = XenForo_Deferred_Abstract::create($input['cache']);
            if ($obj)
            {
                XenForo_Application::defer($input['cache'], $input['options'], $input['unique_key'], true);
            }
        }
So we can specify our own unique_key via a hidden input or, quite simply a change of the column definition to be, at least, VARBINARY(100) :)
 

Chris D

XenForo developer
Staff member
#2
Strictly speaking, of course, specifying a custom unique key and the current method, produces something that isn't a unique key.

And, unfortunately, doesn't this potentially result in another error?

What if two Admins were to rebuild the same cache at the same time. The unique_key column has a unique index on the table, and in that scenario the unique_key would not be unique.

I nearly suggested it last night. But I think I will now, anyway.

What if the unique_key was:

PHP:
        $input = $this->_input->filter(array(
            'cache' => XenForo_Input::STRING,
            'options' => XenForo_Input::ARRAY_SIMPLE
        ));

        if ($input['cache'])
        {
            $uniqueKey = uniqid('Rebuild_');
            $uniqueKey = substr($uniqueKey . $input['cache'], 0, 50);

            $obj = XenForo_Deferred_Abstract::create($input['cache']);
            if ($obj)
            {
                XenForo_Application::defer($input['cache'], $input['options'], $uniqueKey, true);
            }
        }
So we generate a unique ID in PHP with a prefix of Rebuild_ then add the cache name (or class name) to it and substr it down to the first 50 characters.

You wouldn't need to change the database column definition, and unique_id would ultimately become actually unique.
 

Mike

XenForo developer
Staff member
#3
It does an INSERT ON DUPLICATE KEY UPDATE. The second request would override the first (if I remember the code correctly). This is used in situations where running the same thing twice (back to back) doesn't have a benefit.
 

Chris D

XenForo developer
Staff member
#4
Actually, yes, I can confirm that.

So it wouldn't trigger an error.

Still might be a good solution, though, to resolve the data too long error. Unless you prefer to just increase the column limit... Or I could just use shorter class names (which I have done in this case :p)