realm / realm-object-server

Tracking of issues related to the Realm Object Server and other general issues not related to the specific SDK's
https://realm.io
293 stars 42 forks source link

Feature Request: Results or Object Lock (record locking) #433

Open Jaycyn opened 4 years ago

Jaycyn commented 4 years ago

Goals

Have the ability to lock objects/records.

The isolation part of the ACID test is addressed by locking of objects (in most cases one or more rows of data) until the associated transactions are completed. The locking of objects stops all other processes from being able to change these objects until the lock is removed.

Currently in a multi-user situation, a Realm object can be viewed by one user and deleted by another. There is no mechanic that prevents deleting an object that is 'in use' or even knowing what the status of that object is before attempting a transaction.

Expected Results

I would imagine the API being something like this:

let personResults = realm.objects(PersonClass.self).filter("is_available == true")
personResults.setLock(withStatus: .readOnly) //sets all person objects that are available to readOnly.

If another user wants to delete those person objects, they could obtain the lock status before attempting delete:

let lockStatus = personResults.lockStatus //or realm_object.lockStatus

switch lockStatus {
    case .readOnly:
    case .writeOnly:
    case .noLock
}

or if the object is readOnly, the delete attempt would return an error instead/in addition to being able to obtain it's status. I suggest the proactive approach of getting the status before deleting instead of reactive.

Realizing the server is not updated until a write transactions completes, the status could be done with a write, or perhaps the object function have it's own write.

Some have suggested manually adding a isLocked property to an object to obtain a similar functionality but that fails if for example, the client disconnects; there would be no way to 'reset' that lock status.

There would be additional benefit to adding an event observer to the server or enabling Server Functions that could take action when say, a user disconnects. Similar to the onDisconnect function in Firebase.

nirinchev commented 4 years ago

That doesn't really fit with the design of Realm and the synchronization model. Realm is eventually consistent in order to support offline-first scenarios. At no point can a device be confident what the status of an object is on the server. Imagine a scenario where client A tries to delete an object and since no one is using it, succeeds. Immediately after that though, the connection drops and that information is not sent to the server. By the time the device has reconnected, someone has obtained a lock on the object - should that transaction fail now? How would that failure be communicated to the user who may have moved on to another portion of the app and completely forgotten that they deleted something?

Apart from that, I don't see the real-world benefit of having such a system in place. Imagine a shared documents app - why would I want to keep editing a document if someone's just waiting for me to unlock it and delete it? In every scenario I can think of, it's better to communicate to users that the object that they're interacting with has been deleted than to let them interact with it and then have it disappear as soon as they restart the app or leave the screen.

Jaycyn commented 4 years ago

That doesn't really fit with the design of Realm and the synchronization model.

Why not? What's to say the need to grow Realm beyond what it currently is suggests the model could be expanded?

client A tries to delete an object and since no one is using it, succeeds. Immediately after that though, the connection drops and that information is not sent to the server.

If the delete was successful then the change would already be on the server because the write transaction would have concluded so that scenario would not exist.

Apart from that, I don't see the real-world benefit of having such a system in place.

If you are familiar with SQL, SQL-Server, MySQL, Oracle SQL, DB2, PostgeSQL and hundreds of other relational databases, they offer it, so there would be a real-world benefit. In fact, trying to find a Relational or Psueudo-Relational database that doesn't offer some form of object, record or row locking or some mechanic to protect data while in use is a challenge.

If you research other database justification for record locking, one reason is to ensure ACID compliance.

it's better to communicate to users that the object that they're interacting with has been deleted

100% Agree but that is not the reason for this Feature Request; the intent is to prevent that situation using a proactive approach. Let's take your example and give it real world use. Suppose we store word processing documents in realm. A user opens a document and begins reading it, a second user deletes it. There's nothing to prevent that from happening whereas in pretty much all other multi-user databases there is.

Taking a pro-active approach to ACID compliance is the point.

nirinchev commented 4 years ago

If the delete was successful then the change would already be on the server because the write transaction would have concluded so that scenario would not exist.

That's not how Realm works. All changes are made locally. Then a sync background thread picks up these changes and sends them to the server. At no point does committing a transaction depend on the server being accessible or approving it.

This is what I mean that your suggestion doesn't fit the model of Realm. We've gone for an approach where the client talks to the client database and the server talks to the server database and Sync sits between them and transfers data, but neither the server nor the client know about each other.

As for other relational databases - sure they offer that but not in a distributed manner. With all of them you talk to a Central database and as soon as the connection is gone, you're locked out of your data. Once again, this is not the model Realm has adopted as you can't rely on constant connectivity when running on mobile devices. That's why Realm doesn't have unique indexes, autoincrementing keys and a bunch of other features relational databases have - they just don't work in a distributed scenario.

With your example - the current behavior seems to me like the correct one - i.e. the owner of the document has decided they don't want anyone else to read the document (e.g. because it contains sensitive information or because they're embarrassed, whatever). At this point the app should do its best to prevent people from reading it, regardless of whether someone was in the middle of it or not. And I'm sorry but I don't see how this relates to ACID compliance at all as that governs what guarantees there are for the data stored on disk in case of errors or power failures (Realm is ACID compliant).

I want to clarify, I do not want to argue about this as that's not productive - the reasons I gave you are valid and we have no plans to ship such a feature at least for the next year, maybe ever. If you describe exactly what is the problem you're trying to solve, we could try to give you a best practice approach using the current API.

Jaycyn commented 4 years ago

That's not how Realm works.

I am sorry, but I think the point of the request has been missed.

It is how realm works based on what I said. If an object is deleted, once it's written locally, at some point in time thereafter, that change is committed to the server.

Regardless of whether the server and client know about each other, preventing an object from randomly being deleted could be a Realm feature and what we are after is preventing data from being deleted that shouldn't be.

as the connection is gone, you're locked out of your data

That is not accurate. Many offer offline persistence which enable the app to continue to operate, even when offline due to a disconnect or interruption.

the owner of the document has decided they don't want anyone else to read the document

Again, that's not the point. Let me give you a real-world example. In an inventory control system. A user is adding items to a purchase order. Another user decides (for whatever reason or even accidentally) to delete the item. If that item is showing on a PO and another user deletes it.... well, you can see the issue. Again, that would cause a massive issue in a multi-user environment and there's no mechanic in place to prevent it.

And I'm sorry but I don't see how this relates to ACID compliance

Read: ACID

Many databases rely upon locking to provide ACID capabilities. Locking means that the -> transaction <- marks the data that it accesses so that the DBMS knows not to allow other transactions to modify it until the first transaction succeeds or fails.

Note it says transaction not read or write, but transaction. It I start a read transaction on an object in Realm, that item can be deleted. Pretty straightforward issue.

I want to clarify, I do not want to argue about this as that's not productive - the reasons I gave you are valid and we have no plans to ship such a feature at least for the next year, maybe ever

Very odd standpoint. It's your job to ensure your product is as good as it can be and that process starts by listening to your developers. Have you ever considered 'hey, maybe we are overlooking something here?' I am not saying 'do it, or else' but I am saying there may be a need for a feature like this and to consider it in the future.

There are ways the Realm product can improve. Have you asked yourself why it's not taken the industry by storm? Why there is such a tiny development community? Why Mongo now owns the product? Have you noticed there have only been 5 posts on Git in the last year?

I feel it's because there are industry standard (I would almost say required) features missing from the platform. Therefore developers go elsewhere to other platforms that offer those features. Don't get me wrong, Realm is fantastic - but it could be even more fantastic with additional basic features.

I personally know a number of developers that started with Realm based on my recommendation that abandoned it due to a lack of multi-user mechanics.

I would think you would welcome feedback and positive suggestions that may help improve the product.

the reasons I gave you are valid and we have no plans to ship such a feature at least for the next year, maybe ever.

Hmm.

If you describe exactly what is the problem you're trying to solve

If you would take a moment and read the feature request, that's outlined pretty clearly.

A Realm object can be viewed by one user and deleted by another. I would like a FEATURE that would prevent that from occurring.

I am not sure who you are or why your commenting in this fashion to a Feature Request but it's Feature Request. Simple as that. There's a need for this as evidenced by a vast amount of other databases offering it as a feature. If nobody wanted it, they wouldn't have it.

You are welcome to close this Feature Request or delete it but we have a need for that feature which means there are probably others. And hey, it may even improve the product and attract more developers which means Realm generates more revenue for everyone. Not a bad deal IMO.

nirinchev commented 4 years ago

As I said, I don't want to argue about it. I understand that you see value in this feature request, unfortunately as it is worded, it goes against the way Realm is designed and the problems it solves.

If you're interested in trying to solve this with the current set of API, you can consider using soft deletes instead of hard ones. Then a device can freely mark an object as deleted, regardless of whether someone is interacting with it or not. Then the device that interacts with it can "revive" it by reverting the change. There are certain intricacies around how this would work, but without a more concrete set of requirements than "we need to prevent deletes", this is a path you may wish to explore.

Once again, I don't want to shoot your proposal down or anything, it just goes against so many architectural decisions we've made that it's similar to going and asking MongoDB to support SQL or foreign keys - I'm sure that it could be useful and benefit some people, it's just not what the database was designed to do. Maybe we'll get to a point where this is the best thing we can work on, but for the time being this is definitely not something we can commit to in the near future. If the existence of this functionality is critical for your use case, you'll need to either find a workaround or a different database.