How to avoid race condition in table with pairs of id's - spring

I am working on small parking service and i think I get problem with race condition.
I have table in database "cars_on_parkings_ids" where i have pairs of carID and parkingID.
insert into cars_on_parkings_ids (ID, ID_CAR, ID_PARKING) values ('idOfPair', 'carID', 'parkingID');
When i want to chack if on parking is any free slot i am doing query like this (i have special slots with chargers intended for only electric cars and electric cars can park only on them, so i do not want to count them):
#Query(value = "SELECT COUNT(*) FROM CarOnParkingEnity cp INNER JOIN CarEntity c ON c.idCar = cp.idCar " +
"where c.powerType not like 'ELECTRIC' AND cp.idParking =:parkingId")
Integer findAmountOfTakenSlotsOnParking(#Param("parkingId") String parkingID);
and next, my service compare that number with number of parking slots in this parking.
So i have a problem with situation when 2 cars want to entry in very very close time and there is only 1 free slot. There is a few miliseconds between query and checking how many slots parking has.
if (carsOnParkingsRepository.findAmountOfTakenSlotsOnParking(parking.getIdParking())
< parking.getNumberOfParkingSlots()) {
return setCarToParking(carAtGateModel);
} else {
return new ResponseEntity<>(responseMessage.everySlotIsTaken(), HttpStatus.OK);
}
A. car1 want to entry on parking1
A. System is doing query about amount of taken places = returns 3
B. car1 want to entry on parking 1
B. System is doing query about amount of taken places = returns 3
A. System compare amount with number of parking slot from database with parkings. Parking has 4 slots
B. System compare amount with number of parking slot from database with parkings. Parking has 4 slots
A. Gate is getting up (3 < 4)
B. Gate is getting up (3 < 4) (but in real its 4/4
I do not know what should i use to avoid that situation. I was reading about add column '#Version' but it will not working with my pairs of ID's

Related

Laravel eloquent deep count with relationship

I want to get count from deep table and the relationship is A->B->C->D and I want total count of D.
For example;
A: 3 Boss
B: 5 Managers
C: 8 Human Resources
D: 25 Employees
Imagine that every boss has managers and every manager has human resources and also every human resource has employees. How can I get total count every boss's employees' with Laravel. (For instance, first boss has 7 employees at the end.) Should I have to write hard sql code like joins or can I handle with eloquent?
By the way, my tables:
A: id, name
B: id, name
A and B has pivot table.
C: id, name
B and C has pivot table
D: id, name
C and D has pivot table
So far, I tried to:
$a = Boss::with("a.b.c.d")->where("id", 10)->first();
dd($a->b->c->d->count());
It just gave me d's count but I want to all of a's.
There is no native relationship for this case.
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class A extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function d() {
return $this->hasManyDeep(D::class, ['a_b', B::class, 'b_c', C::class, 'c_d']);
}
}
$count = A::find($id)->d()->count();

Complicated Cube Query

I'm working on a fairly complicated view, which calculates the total cost of a guest's stayed based on data pulled from four different tables. The output however is not exactly what I want. My code is
CREATE OR REPLACE VIEW Price AS
SELECT UNIQUE
Booking.Booking_ID AS "Booking",
Booking.GuestID AS "Guest ID",
Room.Room_Price*(Booking.CheckOutDate-Booking.CheckInDate) AS "Room Price",
Add_Ons.Price AS "Add ons Price",
Room.Room_Price*(Booking.CheckOutDate-Booking.CheckInDate) + (Add_Ons.Price) AS "Total Price"
FROM Booking JOIN Room ON Room.Room_Num = Booking.Room_Num
JOIN Booking_Add_Ons ON Booking.Booking_ID = Booking_Add_Ons.Booking_ID
JOIN Add_ons ON Booking_Add_Ons.Add_On_ID = Add_Ons.Add_On_ID
ORDER BY Booking.Booking_ID;
Now, I'm trying to get this to return the total cost of all Addons, plus the cost of the hotel rooms as the total price, however it is returning the cost of the rooms + each of the addons on separate lines. As follows:
My question is, is it possible to use something like CUBE, or SUM to add up the rows, so that there is only one entry for each of the Bookings with the total price of all add-ons accounted for?

Efficient algorithm that takes a Twitter user and finds top users by order of how many of his followers they follow

The title is very wordy. So I'll explain with an example.
We have a database of 10,000 twitter users with each following up to 2000 users. The algorithm takes as input one random never before seen user (including the people that follow him), and returns the twitter users from the database by order of how many of his followers they follow.
i.e.
We have:
User A follows 1,2,3,4
User B follows 3,4,5,6
User C follows 4,8,9
We enter user X who has users 3,4,5 following him.
The algorithm should return:
B: 3 matches (3,4,5)
A: 2 matches (3,4)
C: 1 match (4)
Store the data as a sparse integer matrix A of size 10^5x10^5 with ones at the appropriate places. Then, given a user i, compute A[i,] * A (matrix multiplication). Then sort.
Assuming you have a table structure similar to this:
Table Users
Id (PK, uniqueidentifier, not null)
Username (nvarchar(50), not null)
Table UserFollowers
UserId (FK, uniqueidentifier, not null)
FollowerId (uniqueidentifier, not null)
You can use the following query to get the common parents of followers of the followers of the user in query
SELECT Users_Inner.Username, COUNT(Users_Inner.Id) AS [Total Common Parents]
FROM Users INNER JOIN
UserFollowers ON Users.Id = UserFollowers.FollowerId INNER JOIN
UserFollowers AS UserFollowers_Inner ON UserFollowers.FollowerId = UserFollowers_Inner.UserId INNER JOIN
Users AS Users_Inner ON UserFollowers_Inner.FollowerId = Users_Computed.Id
WHERE (UserFollowers.UserId = 'BD34A1FF-FCF5-4D35-B8A3-EFFB1587A874')
GROUP BY Users_Inner.Username
ORDER BY COUNT(Users_Inner.Id) DESC
would something like this work?
for f in followers(x)
for ff in followers(f)
count[ff]++ // assume it is initially 0
sort the ff-s by their counts
Unlike the matrix solution, the complexity of this is proportional to the number of people involved rather than the number of users on twitter.

Pig: Pulling individual fields out after a GROUP

In PigLatin, I want to pull the other fields out of a record I want to select because of an aggregate, such as MAX.
I'm having trouble explaining the problem, so here is an example. Let's say I want to grab the name of the oldest person at a household:
Relation A is four columns, (name, address, zipcode, age)
B = GROUP A BY (address, zipcode); # group by the address
# generate the address, the person's age, but how do I grab that person's name?
C = FOREACH B GENERATE FLATTEN(group), MAX(age), ??? Name ???;
How do I generate the name of the person with the MAX age?
The problem with your logic is there can be more then 1 people with the MAX(age). Then you have to GROUP BY (name, address, age). But to give you a quick answer I will write that gets only one of the max ages. (I am not sure its the optimum way though)
C = FOREACH B {
DA = ORDER A BY age DESC;
DB = LIMIT DA 1;
GENERATE FLATTEN(group), FLATTEN(DB.age), FLATTEN(DB.name);
}
Be careful with frail's answer which is accepted, as it would have undesirable behavior if the number in the LIMIT command is higher than 1. In particular, in that case the output would be a cross-product between all ages and names due to the last two FLATTEN calls. Then, if the value in the LIMIT is N, there would be N^2 output rows instead of intended N.
Much safer is to do the following in the GENERATE line, which would give exactly the same result as the accepted answer when 'LIMIT 1' is used:
GENERATE FLATTEN(group) AS (address, zipcode), FLATTEN(DB.(age, name)) AS (age, name);

Azure Table Storage - PartitionKey and RowKey selection to use between query

I am a total newbie with Azure! The purpose is to return the rows based on the timestamp stored in the RowKey. As there is a transaction cost with each query, I want to minimize the number of transactions/queries whilst maintain performance
These are the proposed Partition and Row Keys:
Partition Key: TextCache_(AccountID)_(ParentMessageId)
Row Key: (DateOfMessage)_(MessageId)
Legend:
AccountId - is an integer
ParentMessageId - The parent messageId if there is one, blank if it is the parent
DateOfMessage - Date the message was created - format will be DateTime.Ticks.ToString("d19")
MessageId - the unique Id of the message
I would like to get back from a single query the rows and any childrows that is > or < DateOfMessage_MessageId
Can this be done via my proposed PartitionKeys and RowKeys?
ie.. (in psuedo code)
var results = ctx.PartitionKey.StartsWith(TextCache_AccountId)
&& ctx.RowKey > (TimeStamp)_MessageId
Secondly, if there I have a number of accounts, and only want to return back the first 10, could it be done via a single query
ie.. (in psuedo code)
var results = (
(
ctx.PartitionKey.StartsWith(TextCache_(AccountId1)) &&
&& ctx.RowKey > (TimeStamp1)_MessageId1 )
)
||
(
ctx.PartitionKey.StartsWith(TextCache_(AccountId2)) &&
&& ctx.RowKey > (TimeStamp2)_MessageId2 )
) ...
)
.Take(10)
The short answer to your questions is yes, but there are some things you need to watch for.
Azure table storage doesn't have a direct equivalent of .StartsWith(). If you're using the storage library in combination with LINQ you can use .CompareTo() (> and < don't translate properly) which will mean that if you run a search for account 1 and you ask the query to return 1000 results, but there are only 600 results for account 1, the last 400 results will be for account 10 (the next account number lexically). So you'll need to be a bit smart about how you deal with your results.
If you padded out the account id with leading 0s you could do something like this (pseudo code here as well)
ctx.PartionKey > "TextCache_0000000001"
&& ctx.PartitionKey < "TextCache_0000000002"
&& ctx.RowKey > "123465798"
Something else to bear in mind is that queries to Azure Tables return their results in PartitionKey then RowKey order. So in your case messages without a ParentMessageId will be returned before messages with a ParentMessageId. If you're never going to query this table by ParentMessageId I'd move this to a property.
If TextCache_ is just a string constant, it's not adding anything by being included in the PartitionKey unless this will actually mean something to your code when it's returned.
While you're second query will run, I don't think it will produce what you're after. If you want the first ten rows in DateOfMessage order, then it won't work (see my point above about sort orders). If you ran this query as it is and account 1 had 11 messages it will return only the first 10 messages related to account 1 regardless if whether account 2 had an earlier message.
While trying to minimise the number of transactions you use is good practice, don't be too concerned about it. The cost of running your worker/web roles will dwarf your transaction costs. 1,000,000 transactions will cost you $1 which is less than the cost of running one small instance for 9 hours.

Resources