From several servers I would like to add keys like doc:1 and then doc:2 etc.
Now in order that the different servers do not try to add to, say, doc:2 at the same time, I thought there is some mechanism like "add to doc:{index}" and the index gets automatically bumped.
Is there some way to make that work?
You could use a distributed lock and have the winner write
for each server, attempt to acquire lock until success
on acquire lock
read numeric value
increment
write
release lock
docs
https://redis.io/docs/manual/patterns/distributed-locks/
https://redis.io/commands/incr/
You could use a key which you increment on every addition: the INCR command does just that, atomically, and returns the incremented value which you can use to generate the new key name.
> INCR counter
42
> SET doc:42 foobar
OK
Update: in the event you want the whole set of operations (incrementing the counter and setting the value) to be atomic, you can execute a Lua script instead:
> EVAL "local value = redis.call('INCR', 'counter'); redis.call('SET', 'doc:'..value, ARGV[1])" 0 foobar
(nil)
Explanation:
local value = redis.call('INCR', 'counter');
Execute INCR counter and store the result in the value variable.
redis.call('SET', 'doc:'..value, ARGV[1]);
Execute SET against the key named after the concatenation of doc: and the value variable using the data passed through the first EVAL argument - in our case foobar.
Finally, should you need to return the incremented counter value to the caller just append a final return value; block to the script.
Related
I am having difficulty troubleshooting some code.
I have a for loop and in it I clone a part (called EnemySiteHub).
I expect that I can store each cloned part to a table (called EnemySiteTable).
Unfortunately, even though the loop runs successfully and I actually see the cloned EnemySiteHubs during a run of the game.. The table is size remains 0.
Trying to access the table in code gives a nil error.
Code snip:
local ENEMYSITE_COUNT = 5
local EnemySiteTable = {} -- [[ Store the table of enemy site objects ]]
-- Loops until there are the amount of enemy site hubs set in ENEMYSITE_COUNT
for i = 1, ENEMYSITE_COUNT do
--Makes a copy of EnemySiteHub
local enemySite = ServerStorage.EnemySites.EnemySiteHub:Clone()
enemySite.Parent = workspace.EnemySites
EnemySiteTable[i] = enemySite
This line of code causes causes the error below.
local enemySiteTableSize = #enemySiteTable
18:12:37.984 - ServerScriptService.MoveEnemyToSite:15: attempt to get length of a nil value
Any help will be appreciated.
#array is used to retrieve the length of arrays. You will have to use some sort of table.function() or use a for i,v in pairs(EnemySiteTable) loop.
Here's some more information: https://developer.roblox.com/en-us/articles/Table
Thanks #pyknight202
The problem originated somewhere else in my code.
The EnemySiteTable is in a module script.
This code below is the correct code to give access to the EnemySiteTable
--Have the table of enemies accessible
EnemySiteManager.EnemySiteTable = EnemySiteTable
I had an error (typo) in that line of code.
The effect of that error kept returning a nil table, giving a table size of 0.
How to use the old keyword into ensure clause of a feature, the current statement doesn't seem to be valid at runtime
relationships: CHAIN -- any chain
some_feature
do
(...)
ensure
relationship_added: attached relationships as l_rel implies
attached old relationships as l_old_rel and then
l_rel.count = l_old_rel.count
end
For the whole case, following screenshots demonstrate the case
start of routine execution
end of routine execution
There are 2 cases to consider: when the original reference is void, and when — not:
attached relationships as r implies r.count =
old (if attached relationships as o then o.count + 1 else 1 end)
The intuition behind the assertion is as follows:
If relationships is Void on exit, we do not care about count.
If relationships is attached on exit, it has one more item compared to the old value. The old value may be attached or Void:
if the old value is attached, the new number of items is the old number plus 1;
if the old value is Void, the new number of items is 1.
First of all I'm new to power query, so I'm taking the first steps. But I need to try to deliver sometime at work so I can gain some breathing time to learn.
I have the following table (example):
Orig_Item Alt_Item
5.7 5.10
79.19 79.60
79.60 79.86
10.10
And I need to create a column that will loop the table and display the final Alt_Item. So the result would be the following:
Orig_Item Alt_Item Final_Item
5.7 5.10 5.10
79.19 79.60 79.86
79.60 79.86 79.86
10.10
Many thanks
Actually, this is far too complicated for a first Power Query experience.
If that's what you've got to do, then so be it, but you should be aware that you are starting with a quite difficult task.
Small detail: I would expect the last Final_Item to be 10.10. According to the example, the Final_Item will be null if Alt_Item is null. If that is not correct, well that would be a nice first step for you to adjust the code below accordingly.
You can create a new blank query, copy and paste this code in the Advanced Editor (replacing the default code) and adjust the Source to your table name.
let
Source = Table.Buffer(Table1),
AddedFinal_Item =
Table.AddColumn(
Source,
"Final_Item",
each if [Alt_Item] = null
then null
else List.Last(
List.Generate(
() => [Final_Item = [Alt_Item], Continue = true],
each [Continue],
each [Final_Item =
Table.First(
Table.SelectRows(
Source,
(x) => x[Orig_Item] = [Final_Item]),
[Alt_Item = "not found"]
)[Alt_Item],
Continue = Final_Item <> "not found"],
each [Final_Item])))
in
AddedFinal_Item
This code uses function List.Generate to perform the looping.
For performance reasons, the table should always be buffered in memory (Table.Buffer), before invoking List.Generate.
List.Generate is one of the most complex Power Query functions.
It requires 4 arguments, each of which is a function in itself.
In this case the first argument starts with () and the other 3 with each (it should be clear from the outline above: they are aligned).
Argument 1 defines the initial values: a record with fields Final_Item and Continue.
Argument 2 is the condition to continue: if an item is found.
Argument 3 is the actual transformation in each iteration: the Source table is searched (with Table.SelectRows) for an Orig_Item equal to Alt_Item. This is wrapped in Table.First, which returns the first record (if any found) and accepts a default value if nothing found, in this case a record with field Alt_Item with value "not found", From this result the value of record field [Alt_Item] is returned, which is either the value of the first record, or "not found" from the default value.
If the value is "not found", then Continue becomes false and the iterations will stop.
Argument 4 is the value that will be returned: Final_Item.
List.Generate returns a list of all values from each iteration. Only the last value is required, so List.Generate is wrapped in List.Last.
Final remark: actual looping is rarely required in Power Query and I think it should be avoided as much as possible. In this case, however, it is a feasible solution as you don't know in advance how many Alt_Items will be encountered.
An alternative for List.Generate is using a resursive function.
Also List.Accumulate is close to looping, but that has a fixed number of iterations.
This can be solved simply with a self-join, the open question is how many layers of indirection you'll be expected to support.
Assuming just one level of indirection, no duplicates on Orig_Item, the solution is:
let
Source = #"Input Table",
SelfJoin1 = Table.NestedJoin( Source, {"Alt_Item"}, Source, {"Orig_Item"}, "_tmp_" ),
Expand1 = ExpandTableColumn( SelfJoin1, "_tmp_", {"Alt_Item"}, {"_lkp_"} ),
ChkJoin1 = Table.AddColumn( Expand1, "Final_Item", each (if [_lkp_] = null then [Alt_Item] else [_lkp_]), type number)
in
ChkJoin1
This is doable with the regular UI, using Merge Queries, then Expand Column and adding a custom column.
If yo want to support more than one level of indirection, turn it into a function to be called X times. For data-driven levels of indirection, you wrap the calls in a list.generate that drop the intermediate tables in a structured column, though that's a much more advanced level of PQ.
It seems to me that a transaction in a method does not include the variables that are the arguments of the method. Because in my application I get the entity incremented without changes of the other models.
#ndb.transactional(xg=true)
def method(entity):
# `entity` is a datastore entity
# Transaction works here
Model.foo()
# ...here too
Model.bar()
# But not here! Always incremented.
entity.x += 1
entity.put()
In the example above the property x of the entity will be incremented even if the transaction fails.
Is it correct?
Yes. Since the entity get() was outside the transaction, there's no value to to roll back to (the transaction wouldn't know the previous value of entity. Also, if this transaction was actually intended to increment entity.x by one, it would fail to provide transactional consistency.
Imagine entity.x = 1, this transaction could potentially start, and a second request operating on the same request could run at the same time. Since both gets are outside of the transaction, they'll both read 1, then they'll both increment x to 2, and it'll save as 2, even though it was incremented twice and should be 3. Since the get() was outside the transaction, it would not be protected.
I have a situation where I need to update votes for a candidate.
Citizens can vote for this candidate, with more than one vote per candidate. i.e. one person can vote 5 votes, while another person votes 2. In this case this candidate should get 7 votes.
Now, I use Django. And here how the pseudo code looks like
votes = candidate.votes
vote += citizen.vote
The problem here, as you can see is a race condition where the candidate’s votes can get overwritten by another citizen’s vote who did a select earlier and set now.
How can avoid this with an ORM like Django?
If this is purely an arithmetic expression then Django has a nice API called F expressions
Updating attributes based on existing fields
Sometimes you'll need to perform a simple arithmetic task on a field, such as incrementing or decrementing the current value. The obvious way to achieve this is to do something like:
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold += 1
>>> product.save()
If the old number_sold value retrieved from the database was 10, then the value of 11 will be written back to the database.
This can be optimized slightly by expressing the update relative to the original field value, rather than as an explicit assignment of a new value. Django provides F() expressions as a way of performing this kind of relative update. Using F() expressions, the previous example would be expressed as:
>>> from django.db.models import F
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold = F('number_sold') + 1
>>> product.save()
This approach doesn't use the initial value from the database. Instead, it makes the database do the update based on whatever value is current at the time that the save() is executed.
Once the object has been saved, you must reload the object in order to access the actual value that was applied to the updated field:
>>> product = Products.objects.get(pk=product.pk)
>>> print product.number_sold
42
Perhaps the select_for_update QuerySet method is helpful for you.
An excerpt from the docs:
All matched entries will be locked until the end of the transaction block, meaning that other transactions will be prevented from changing or acquiring locks on them.
Usually, if another transaction has already acquired a lock on one of the selected rows, the query will block until the lock is released. If this is not the behavior you want, call select_for_update(nowait=True). This will make the call non-blocking. If a conflicting lock is already acquired by another transaction, DatabaseError will be raised when the queryset is evaluated.
Mind that this is only available in the Django development release (i.e. > 1.3).