Closed aavshr closed 4 years ago
ping @linxing for: https://github.com/casbin/xorm-adapter/pull/27
Also ping our members and contributors: @nodece @GopherJ @dovics Do you have any suggestions?
Why not obtain the lock in the SavePolicy() ?
@linxing it added the lock in SavePolicy()
:
What did you mean by Why not obtain the lock in the SavePolicy() ?
?
I mean only add the lock in SavePolicy()
. I think such as LoadPolicy()
and RemoveFilteredPolicy
no need to locked @hsluoyz
BTW. gorm-adapter have the same problem.
@aavshr
I mean only add the lock in
SavePolicy()
. I think such asLoadPolicy()
andRemoveFilteredPolicy
no need to locked @hsluoyz
To prevent race conditions. Here's my thinking behind these changes. Please, correct me if I'm wrong. Consider the following scenario where there are two simultaneous calls on SavePolicy()
and then LoadPolicy()
and LoadPolicy()
does not have to acquire a lock.
SavePolicy()
locks the mutex and deletes the table and is now in the middle of creating a table and re-inserting the policies from memory. LoadPolicy()
is called and it attemps to load the policies from the database. It is allowed to do so if it does not need to obtain the lock. However, SavePolicy()
has not finished running yet. This will lead to unwanted behavior as LoadPolicy()
will either find that the table does not exist (as SavePolicy()
deleted it) or will not load all the policies (as SavePolicy()
is not finished inserting the policies in the database)A code like this can potentially lead to unexpected behavior without the locks.
go adapter.SavePolicy()
go adapter.LoadPolicy()
BTW. gorm-adapter have the same problem.
I haven't looked at the gorm-adapter. Also, I'm not sure if the underlying engines themselves prevent these race conditions.
All this also depends on how people use the adapter. If the adapter is not meant for concurrent use, then I think we need a disclaimer to say so. I personally had to use it on a server that checks for user permissions. And it was pretty common where I had to handle concurrent requests where one request would want to read from the database( LoadPolicy()
) whereas the other wants to write to it (SavePolicy()
).
I also think that dropping the table entirely is also pretty dangerous and maybe there is a better way to do all this. I would love some input regarding this.
@aavshr @linxing I remembered we already have the synced enforcer: https://github.com/casbin/casbin/blob/master/enforcer_synced.go . The API of that enforcer is protected by locks. So we don't add any locks in the adapter layer. Users can customize their own based on their scenarios.
And sorry that I have to revert this PR: https://github.com/casbin/xorm-adapter/pull/27
A routine should only release the lock when it's done with the entire
SavePolicy()
and other operations. https://github.com/casbin/xorm-adapter/blob/master/adapter.go#L258-L287For instance, consider the following scenario where two routines (A and B) are calling
savePolicy()
at the same time.dropTable()
I hope this is clear enough. This is only one of many scenarios I can think of when things might be problematic.