Up to Main Index Up to Journal for July, 2017 JOURNAL FOR WEDNESDAY 26TH JULY, 2017 ______________________________________________________________________________ SUBJECT: Data race fixes delayed, New debug tooling DATE: Wed 26 Jul 22:50:45 BST 2017 Some people have noticed that I haven’t made the changes available as detailed in my last journal entry. The reason was simple, the WolfMUD server was being a real pain and dropped a data race trace five minutes after I published. *sigh* I spent time pouting, grumbling and throwing away all of the changes I’d made. I then spent a lot of time thinking about how to improve the current situation with respect to solving the data races. In theory the locking rules in WolfMUD are very simple: 1. Locking is only done on the outermost Inventory of an Inventory hierarchy 2. When handling the attributes of a Thing, you need to lock the outermost Inventory the Thing is in 3. Using a Locate Attribute is concurrently safe 4. Using a Thing itself (not its Attributes) is concurrently safe When executing any player or scripted command there is some standard setup that is performed. First we need to know where the ‘actor’[1] is. We find out where they are via the Locate.Where method — rule 3 means this is safe. To find out where the actor is we need to find the actor’s Locate Attribute via the FindLocate function — rule 4 means this is safe. We can then lock the outermost Inventory of where the player is by calling the Inventory.Outermost method — rule 1. After this setup is completed we are free to access anything within the outermost Inventory including nested Inventories like containers, other players, items, items in containers etc. If we need multiple locations, for example when moving from one location to another, we do the setup as above. This locks the location where we are. We then find out the Inventory we want to move to via the Exit attribute from the current (locked) Inventory parent Thing. We then add the lock for the destination and reacquire our locks. Rule 1 says we can now access anything within the current and destination Inventories. In this case we can remove the player from the current location, add them to the destination, notify players at the current location that we left, notify players at the destination we arrived and finally access the items at the destination to describe the new location. For the most part this all works beautifully :) Where things tend to go wonky is where something is ‘out of play’ — that is not in an Inventory we can lock on. For example there is a race when first adding a player, or removing them from the game world. Items can also go ‘out of play’ during a reset. After throwing away all of my pending changes I did something crazy, really crazy. I realised I needed to validate rules 1 and 2 above. I spent ages adding a locks parameter as the first parameter of nearly every function or method for every Attribute. The locks were a simple []has.Inventory containing a copy of the state locks being held. That way I could verify at every step that any Thing or Attribute that was touched was under a lock and log when it wasn’t. Only one problem, there were a huge number of lock verifying changes and it was difficult to tell them apart from actual bug fixes. So I threw all of those changes away as well :( The time spent on that failed exercise wasn’t wasted. I realised I only needed to check the locks in a few places — most of the other changes were to transport the lock data and propagate it through the different calls to where it was needed. As a result I modified the thing.Attrs method to make sure the Thing is in the hierarchy of a locked Inventory — to access an Attribute you have to use a finder function and they all call the thing.Attrs method. I’ve also added checks to the Inventory methods to make sure Inventory are always in the hierarchy of a locked Inventory. I’ve also overridden the BRL Lock and Unlock methods exposed in the Inventory type to record the locks and unlocks. Last of all I’ve added some DebugXXX functions to a separate attr/debugging.go file. With these few, simple changes I can now monitor all of the locks and report when an improper Inventory or Thing access is detected. The difference between my tracing and the standard data race trace is that I can now follow the flow of locking, unlocking and accesses as opposed to the simple snapshot displayed by the standard data race trace. So apologies for the delay and to everyone waiting for the data race fixes. With my new debugging ‘tool’ I hope to nail the remaining data races I know about and I’ve already started fixing some I didn’t know about. On a side note, Go 1.9 RC1 was announced today :) -- Diddymus [1] The actor is whatever is performing the command, usually a player but can actually be any Thing. Up to Main Index Up to Journal for July, 2017