Laravel Relationship Events
Laravel Packages
/
July 09, 2018
Laravel Relationship Events
Laravel Relationship Events is a package by Viacheslav Ostrovskiy that adds extra model relationship events. This package comes with the following traits that are used to register listeners on a model’s boot()
method:
- HasOneEvents
- HasBelongsToEvents
- HasManyEvents
- HasBelongsToManyEvents
- HasMorphOneEvents
- HasMorphToEvents
- HasMorphManyEvents
- HasMorphToManyEvents
- HasMorphedByManyEvents
And from the above traits, here’s an example of a few events on a Country
model that has many Users
using the HasManyEvents
trait:
namespace App\Models;
use App\User;
use Chelout\RelationshipEvents\Concerns\HasManyEvents;
use Illuminate\Database\Eloquent\Model;
class Country extends Model
{
use HasManyEvents;
protected $fillable = [
'name',
];
public function users()
{
return $this->hasMany(User::class);
}
public static function boot()
{
parent::boot();
static::hasManySaving(function ($parent, $related) {
Log::info("Saving user's country {$parent->name}.");
});
static::hasManySaved(function ($parent, $related) {
Log::info("User's country is now set to {$parent->name}.");
});
}
}
And the inverse of the relationship with this package might look like the following:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Chelout\RelationshipEvents\Concerns\HasBelongsToEvents;
class User extends Model
{
use HasBelongsToEvents;
/**
* Get the country associated with the user.
*/
public function country()
{
return $this->belongsTo(Country::class);
}
protected static function boot()
{
parent::boot();
static::belongsToAssociating(function ($relation, $related, $parent) {
Log::info("Associating country {$parent->name} with user.");
});
static::belongsToAssociated(function ($relation, $related, $parent) {
Log::info("User has been assosiated with country {$parent->name}.");
});
}
}
Using an overloaded associate()
method, you can fire two events belongsToAssociating
and belongsToAssociated
:
$country = App\Models\Country::first();
$user = factory(User::class)->create([
'name' => 'John Smith',
]);
// Assosiate user with country
// This will fire belongsToAssociating and belongsToAssociated events
$user->country()->associate($country);
Learn More
The package has documentation for each trait and association type. Check out the package on GitHub at chelout/laravel-relationship-events.
Why MySQL Stored Procedures, Functions and Triggers Are Bad For Performance
MySQL stored procedures, functions and triggers are tempting constructs for application developers. However, as I discovered, there can be an impact on database performance when using MySQL stored routines. Not being entirely sure of what I was seeing during a customer visit, I set out to create some simple tests to measure the impact of triggers on database performance. The outcome might surprise you.
Why stored routines are not optimal performance wise: short version
Recently, I worked with a customer to profile the performance of triggers and stored routines. What I’ve learned about stored routines: “dead” code (the code in a branch which will never run) can still significantly slow down the response time of a function/procedure/trigger. We will need to be careful to clean up what we do not need.
Profiling MySQL stored functions
Let’s compare these four simple stored functions (in MySQL 5.7):
Function 1:
CREATE DEFINER=`root`@`localhost` FUNCTION `func1`() RETURNS int(11) BEGIN declare r int default 0; RETURN r; END |
This function simply declares a variable and returns it. It is a dummy function
Function 2:
CREATE DEFINER=`root`@`localhost` FUNCTION `func2`() RETURNS int(11) BEGIN declare r int default 0; IF 1=2 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 1000) into r; END IF;
RETURN r; END |
This function calls another function, levenshtein_limit_n (calculates levenshtein distance). But wait: this code will never run – the condition IF 1=2 will never be true. So that is the same as function 1.
Function 3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
CREATE DEFINER=`root`@`localhost` FUNCTION `func3`() RETURNS int(11) BEGIN declare r int default 0; IF 1=2 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 1) into r; END IF; IF 2=3 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 10) into r; END IF; IF 3=4 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 100) into r; END IF; IF 4=5 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 1000) into r; END IF; RETURN r; END |
Here there are four conditions and none of these conditions will be true: there are 4 calls of “dead” code. The result of the function call for function 3 will be the same as function 2 and function 1.
Function 4:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
CREATE DEFINER=`root`@`localhost` FUNCTION `func3_nope`() RETURNS int(11) BEGIN declare r int default 0; IF 1=2 THEN select does_not_exit(‘test finc’, ‘test func’, 1) into r; END IF; IF 2=3 THEN select does_not_exit(‘test finc’, ‘test func’, 10) into r; END IF; IF 3=4 THEN select does_not_exit(‘test finc’, ‘test func’, 100) into r; END IF; IF 4=5 THEN select does_not_exit(‘test finc’, ‘test func’, 1000) into r; END IF; RETURN r; END |
This is the same as function 3 but the function we are running does not exist. Well, it does not matter as the
select does_not_exit will never run.
So all the functions will always return 0. We expect that the performance of these functions will be the same or very similar. Surprisingly it is not the case! To measure the performance I used the “benchmark” function to run the same function 1M times. Here are the results:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
+—————————–+ | benchmark(1000000, func1()) | +—————————–+ | 0 | +—————————–+ 1 row in set (1.75 sec)
+—————————–+ | benchmark(1000000, func2()) | +—————————–+ | 0 | +—————————–+ 1 row in set (2.45 sec)
+—————————–+ | benchmark(1000000, func3()) | +—————————–+ | 0 | +—————————–+ 1 row in set (3.85 sec)
+———————————-+ | benchmark(1000000, func3_nope()) | +———————————-+ | 0 | +———————————-+ 1 row in set (3.85 sec) |
As we can see func3 (with four dead code calls which will never be executed, otherwise identical to func1) runs almost 3x slower compared to func1(); func3_nope() is identical in terms of response time to func3().
Visualizing all system calls from functions
To figure out what is happening inside the function calls I used performance_schema / sys schema to create a trace with ps_trace_thread() procedure
- Get the thread_id for the MySQL connection:
mysql> select THREAD_ID from performance_schema.threads where processlist_id = connection_id();
+———–+
| THREAD_ID |
+———–+
| 49 |
+———–+
1 row in set (0.00 sec)
- Run ps_trace_thread in another connection passing the thread_id=49:
mysql> CALL sys.ps_trace_thread(49, concat(‘/var/lib/mysql-files/stack-func1-run1.dot’), 10, 0, TRUE, TRUE, TRUE);
+——————–+
| summary |
+——————–+
| Disabled 0 threads |
+——————–+
1 row in set (0.00 sec)
+———————————————+
| Info |
+———————————————+
| Data collection starting for THREAD_ID = 49 |
+———————————————+
1 row in set (0.00 sec)
- At that point I switched to the original connection (thread_id=49) and run:
mysql> select func1();
+————–+
| func1() |
+————–+
| 0 |
+————–+
1 row in set (0.00 sec)
- The sys.ps_trace_thread collected the data (for 10 seconds, during which I ran the
select func1() ), then it finished its collection and created the dot file:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
+———————————————————————–+
| Info |
+———————————————————————–+
| Stack trace written to /var/lib/mysql–files/stack–func3nope–new12.dot |
+———————————————————————–+
1 row in set (9.21 sec)
+——————————————————————————-+
| Convert to PDF |
+——————————————————————————-+
| dot -Tpdf -o /tmp/stack_49.pdf /var/lib/mysql–files/stack–func3nope–new12.dot |
+——————————————————————————-+
1 row in set (9.21 sec)
+——————————————————————————-+
| Convert to PNG |
+——————————————————————————-+
| dot -Tpng -o /tmp/stack_49.png /var/lib/mysql–files/stack–func3nope–new12.dot |
+——————————————————————————-+
1 row in set (9.21 sec)
Query OK, 0 rows affected (9.45 sec)
I repeated these steps for all the functions above and then created charts of the commands.
Here are the results:
Func1()
Func2()
Func3()
As we can see there is a sp/jump_if_not call for every “if” check followed by an opening tables statement (which is quite interesting). So parsing the “IF” condition made a difference.
For MySQL 8.0 we can also see MySQL source code documentation for stored routines which documents how it is implemented. It reads:
Flow Analysis Optimizations
After code is generated, the low level sp_instr instructions are optimized. The optimization focuses on two areas:Dead code removal,
Jump shortcut resolution.
These two optimizations are performed together, as they both are a problem involving flow analysis in the graph that represents the generated code.The code that implements these optimizations is sp_head::optimize().
However, this does not explain why it executes “opening tables”. I have filed a bug.
When slow functions actually make a difference
Well, if we do not plan to run one million of those stored functions we will never even notice the difference. However, where it will make a difference is … inside a trigger. Let’s say that we have a trigger on a table: every time we update that table it executes a trigger to update another field. Here is an example: let’s say we have a table called “form” and we simply need to update its creation date:
mysql> update form set form_created_date = NOW() where form_id > 5000; Query OK, 65536 rows affected (0.31 sec) Rows matched: 65536 Changed: 65536 Warnings: 0 |
That is good and fast. Now we create a trigger which will call our dummy func1():
CREATE DEFINER=`root`@`localhost` TRIGGER `test`.`form_AFTER_UPDATE` AFTER UPDATE ON `form` FOR EACH ROW BEGIN declare r int default 0; select func1() into r; END |
Now repeat the update. Remember: it does not change the result of the update as we do not really do anything inside the trigger.
mysql> update form set form_created_date = NOW() where form_id > 5000; Query OK, 65536 rows affected (0.90 sec) Rows matched: 65536 Changed: 65536 Warnings: 0 |
Just adding a dummy trigger will add 2x overhead: the next trigger, which does not even run a function, introduces a slowdown:
CREATE DEFINER=`root`@`localhost` TRIGGER `test`.`form_AFTER_UPDATE` AFTER UPDATE ON `form` FOR EACH ROW BEGIN declare r int default 0; END
mysql> update form set form_created_date = NOW() where form_id > 5000; Query OK, 65536 rows affected (0.52 sec) Rows matched: 65536 Changed: 65536 Warnings: 0 |
Now, lets use func3 (which has “dead” code and is equivalent to func1):
CREATE DEFINER=`root`@`localhost` TRIGGER `test`.`form_AFTER_UPDATE` AFTER UPDATE ON `form` FOR EACH ROW BEGIN declare r int default 0; select func3() into r; END
mysql> update form set form_created_date = NOW() where form_id > 5000; Query OK, 65536 rows affected (1.06 sec) Rows matched: 65536 Changed: 65536 Warnings: 0 |
However, running the code from the func3 inside the trigger (instead of calling a function) will speed up the update:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
CREATE DEFINER=`root`@`localhost` TRIGGER `test`.`form_AFTER_UPDATE` AFTER UPDATE ON `form` FOR EACH ROW BEGIN declare r int default 0; IF 1=2 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 1) into r; END IF; IF 2=3 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 10) into r; END IF; IF 3=4 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 100) into r; END IF; IF 4=5 THEN select levenshtein_limit_n(‘test finc’, ‘test func’, 1000) into r; END IF; END
mysql> update form set form_created_date = NOW() where form_id > 5000; Query OK, 65536 rows affected (0.66 sec) Rows matched: 65536 Changed: 65536 Warnings: 0 |
Memory allocation
Potentially, even if the code will never run, MySQL will still need to parse the stored routine—or trigger—code for every execution, which can potentially lead to a memory leak, as described in this bug.
Conclusion
Stored routines and trigger events are parsed when they are executed. Even “dead” code that will never run can significantly affect the performance of bulk operations (e.g. when running this inside the trigger). That also means that disabling a trigger by setting a “flag” (e.g.
if @trigger_disable = 0 then ... ) can still affect performance of bulk operations.
Related
via Planet MySQL
Why MySQL Stored Procedures, Functions and Triggers Are Bad For Performance
Brilliant Design for a Gas Can: The SureCan
Now relocated to farm country, I recently needed to gas up a lawn tractor. I went to Lowes to purchase a gas can. I grabbed the standard $20 one, which looks like this:
But next to it I spotted another gas can, listed for an absurd $50, that looked like this:
I couldn’t understand why this one cost more than double, and set the other can down to take a closer look. A sticker on the side demonstrated how to use it, and it did indeed appear innovatively designed. Since Lowes has a pretty liberal return policy, I left the $20 can on the shelf and purchased the $50 one to try it out.
After a trip to the gas station I returned to the farm and learned that the SureCan, as it’s called, works amazingly well. Here’s what it looks like in action:
Using it was incredibly easy, and I won’t be taking it back. Hoisting and aiming the thing was simple, and the trigger works perfectly, allowing you to dispense with precision.
I looked into it and the SureCan was invented by general contractor and cabinetmaker Brad Ouderkirk, who "spent a lot of his time filling gas powered machines and constantly spilling all over his expensive equipment." Ouderkirk spent four years designing the SureCan, building his own prototypes out of wood and plastic. Here’s a closer look at the design, development of and need for the SureCan:
One of our favorite types of stories is when someone looks at an established, tried-and-true object that everyone takes for granted, then figures out how to improve it. Congratulations to Ouderkirk for not only designing it, but successfully bringing it to market.
Ant-Man’s Michael Peña Saves the World in Netflix’s First Extinction Trailer
Night after night, a father has terrible dreams. Dreams of death. Invasion. Destruction. Then, those dreams start to become reality and he’ll stop at nothing to save his family. That’s the plot of Extinction, a new Netflix sci-fi film that just got its first trailer.
The film is set to start streaming on July 27. The father is played by Ant-Man and the Wasp’s Michael Peña and he’s joined by Luke Cage himself, Mike Colter, and Lizzy Caplan (who, oddly enough, played a SHIELD agent one time) in the alien invasion film. Here’s the trailer.
If all sounds slightly familiar, it’s because Extinction was originally going to be released by Universal but then was sold to Netflix. Generally, that’s not a great thing (see The Cloverfield Paradox) but there are exceptions (see Annihilation).
The trailer is certainly intriguing and we’d pay real money to see Peña fight aliens as the lead in a sci-fi movie. But now, we don’t have to. At least, not directly. It’s coming right to our homes in two short weeks.
via Gizmodo
Ant-Man’s Michael Peña Saves the World in Netflix’s First Extinction Trailer
Pay Your Age Day at Build-a-Bear on July 12
On Thursday, July 12th, 2018, pay your age (or your child’s age) for any furry friend at Build-a-Bear! The deal is pretty simple – all you have to do is become a Bonus Club Member –…
via Columbus on the Cheap
Pay Your Age Day at Build-a-Bear on July 12
Bet Your Life On Cheap FMJ? Armscor .223 Rem 62gr FMJ gel test
Buy it at Ventura Munitions: https://ift.tt/2NDKvM9 We shoot Armscor .223 Rem 62gr FMJ ammunition from a 10.5″ and 18″ AR15 into Clearballistics ballistic gel to measure velocity, penetration, expansion/fragmentation, and retained weight. If you aren’t already subscribed to us, you’re missing great content! Click here to subscribe. https://www.youtube.com/channel/UCnKbs5xffaEzzdKdPZvfhdQ?sub_confirmation=1 10.5″ Penetration: 15″ Retained weight: 51.4gr Neck: […]
The post Bet Your Life On Cheap FMJ? Armscor .223 Rem 62gr FMJ gel test appeared first on The Firearm Blog.
via The Firearm Blog
Bet Your Life On Cheap FMJ? Armscor .223 Rem 62gr FMJ gel test
DOJ Reaches Settlement On Publication of Files About 3D Printed Firearms
He Who Has No Name writes: Those who remember Cody Wilson and Defense Distributed — the self-described cryptoanarchist and his organization that published plans for 3D printable firearm parts, respectively — also remember that not long after the plans for the printable Liberator single-shot pistol hit the web, the Department of State seized the Defense Distributed website and prohibited Wilson from publishing 3D printable firearm plans, claiming violations of ITAR — the International Traffic in Arms Regulation, a U.S. law taxing and restricting the distribution of a wide variety of physical goods listed as having military value. Slashdot covered the website seizure here (the Department of Defense was initially misreported in sources to have been the agency responsible). In both a First and Second Amendment win, the Second Amendment Foundation has settled with the Department of State after suing on behalf of Defense Distributed. Slashdot reader schwit1 shares an excerpt from the report: "Under terms of the settlement, the government has agreed to waive its prior restraint against the plaintiffs, allowing them to freely publish the 3-D files and other information at issue. The government has also agreed to pay a significant portion of the plaintiffs’ attorney’s fees, and to return $10,000 in State Department registration dues paid by Defense Distributed as a result of the prior restraint. Significantly, the government expressly acknowledges that non-automatic firearms up to .50-caliber — including modern semi-auto sporting rifles such as the popular AR-15 and similar firearms — are not inherently military."
Read more of this story at Slashdot.
via Slashdot
DOJ Reaches Settlement On Publication of Files About 3D Printed Firearms
How to Take Care of Your Rifle
Firearms are wonderful things, and like all machines even the simplest rifle requires care and maintenance. Here are some pointers on how to take care of your rifle.
Keep Your Rifle Clean
A dirty rifle is more prone to corrosion and malfunction than a clean one, so it’s a good idea to keep that shootin’ iron nice and clean. This includes the bore, all moving parts, and even the exterior of the barrel, receiver, and stock.
Nooks and crannies can be cleaned with a toothbrush, if need be. Clean embedded crud out of checkering on the stock and any other areas of the gun’s exterior. It goes without saying to clean the bore and action to remove gunpowder residue and other fouling.
Clean gunk off using non-abrasive methods; mild solvent and a rag from an old t-shirt can work wonders, and won’t mess up your gun’s looks. Just make sure you don’t use any hard-core solvents that might damage plastic, wood finish, and/or painted metal parts.
Examine Your Rifle
It’s important to make sure your rifle works properly, so be sure to dig it out of storage from time to time to check it out. Old lubricants can turn to goo and gunk up the works, or maybe you forgot to clean it last time you used it. A few minutes of fondling and examination will show you its condition, so you’ll know it’s ready to go next time you need it.
Fire Your Rifle to Check Function and Zero (Aim)
You need to know your firearms will function whenever you need them — and hitting your target is pretty dang important, too. So fire your rifle to make sure it’s zeroed in and hitting where you aim, and to make sure everything works as it should. Does the bolt or lever move freely? On break-actions, does the latch hold it securely closed but allow easy, trouble-free opening? Do all safeties work properly (if present)? Do magazines fit properly, load and unload smoothly, and feed ammunition as they should? If the answer to any of those is “no,” you have a problem and should probably visit your local gunsmith.
Lubricate Moving Parts
Use high-quality oil or grease to lubricate all moving parts, per the manufacturer’s recommendations. Pivots, latches, catches, extractors, bolts, levers, the list goes on and on… just make sure you have lube where it ought to be and none where it shouldn’t. Your gun will thank you by always functioning well.
Protect Against Corrosion
Make sure all blued steel surfaces have a light coating of rust-preventative oil to prevent rust, and it doesn’t hurt to do the same to other metals/alloys as well. Corrosion is never a good thing for a firearm, and your rifle needs to be kept in good shape in order to remain dependable… and an undependable rifle isn’t much good to anyone.
Keep it Dry
Rifles were not meant to be used sopping wet. I’ve certainly done so while hunting, but the moisture is not good for them and your life will be happier if you dry your rifle thoroughly at the earliest opportunity. For hunters, this often means doing some work at the end of a long hunting day when you’d rather be eating supper, but it’s worth the work. Dry out your gun’s guts, lubricate it, wipe it down to prevent rust, and you’ll be glad you did.
Final Thoughts
Rifles are valuable tools and with some care, most rifles will far outlast the lives of their owners. Take care of your rifle and your rifle will take care of you.
The post How to Take Care of Your Rifle appeared first on AllOutdoor.com.
How Fracking Companies Use Facebook Surveillance To Ban Protest
An anonymous reader quotes a report from Motherboard:
Facebook is being used by oil and gas companies to clamp-down on protest. Three companies are currently seeking injunctions against protesters: British chemical giant INEOS, which has the largest number of shale gas drilling licenses in the UK; and small UK outfits UK Oil and Gas (UKOG), and Europa Oil and Gas. Among the thousands of pages of documents submitted to British courts by these companies are hundreds of Facebook and Twitter posts from anti-fracking protesters and campaign groups, uncovered by Motherboard in partnership with investigative journalists at DeSmog UK. They show how fracking companies are using social media surveillance carried out by a private firm to strengthen their cases in court by discrediting activists using personal information to justify banning their protests.
Included in the evidence supplied by the oil and gas companies to the courts are many personal or seemingly irrelevant campaigner posts. Some are from conversations on Facebook groups dedicated to particular protests or camps, while others have been captured from individuals’ own profile pages. For instance, a picture of a mother with her baby at a protest was submitted as part of the Europa Oil and Gas case. Another screenshot of a post in the Europa bundle shows a hand-written note from one of the protesters’ mothers accompanying a care package with hand-knitted socks that was sent to an anti-fracking camp. One post included in the UKOG hearing bundle shows two protesters sharing a pint in the sun — not at a protest camp, nor shared on any of the campaign pages’ Facebook groups. A screenshot from INEOS’s hearing bundle shows posts from a protester to his own Facebook wall regarding completely unrelated issues such as prescription drugs, and a generic moan about his manager.
via Slashdot
How Fracking Companies Use Facebook Surveillance To Ban Protest