In the 2.x client, we intentionally changed the packaging structure for two reasons. One is that it’s a new major version with new API. Second is that we wanted people to be able to run the 1.x and the 2.x in the same app concurrently to facilitate slower migrations.
You can see the 2.x API in the API reference, as linked off of the documentation.
With regard to getAndLock(), it’s actually best characterized as a cooperative pessimistic lock with a timeout. What that means is as long as all code paths are using the same getAndLock() access path, only one will succeed with the lock if many actors are going after it once, and the others will then learn that it’s locked. It’s that actor’s responsibility to unlock the document with either an unlock or a CAS operation. If it doesn’t do so within a timeout period, then the lock will be released.
The CAS based optimistic locking is, of course, still there and I personally think it’s generally the preferred approach if you can refactor the problem in that way.
I usually see the getAndLock() type approach to be best used if your application is grabbing a graph of objects for update and wants reasonable assurances (with no failures) that it has exclusive access. However, it’s up to the app to handle the failure cases.