couchdb icon indicating copy to clipboard operation
couchdb copied to clipboard

Enhance step 3 of replication protocol "Find Common Ancestry" (GET /source/_local/replication-id) to return Database update_seq too in response header, if a dbseq=true request header is provided in the request.

Open anuragvohraec opened this issue 4 years ago • 8 comments

Enhance step 3 of replication protocol "Find Common Ancestry" (GET /source/_local/replication-id) to return Database update_seq too in response header, if a dbseq:true header is provided in the request.

Summary

As of now the first three steps of replication protocol is required to determine if a replication is required or not :

  1. Verify Peers (HEAD /peers )
  2. Get Peers Information (GET /peers to know update_seq of source and target)
  3. Find Common Ancestry (GET /source/_local/replication-id)

For a client side replicator, these three steps (hence 3 HTTP requests) are needed to determine if replication is required or not. However such clients (say browser based) only step 3: GET /source/_local/replication-id, can be sufficient to determine if replication is required or not with remote server, provided:

If in step-3 we have a provision to provide DB update_seq, and a status text for 404 of what went wrong.(Wrong like DB do not exist/local doc do not exist).

In many cases a client side replicator won't have rights to create DB at remote CouchDB server. For such cases, without effecting any other cases, if this enhancement is done, we can save HTTP calls to the remote couchdb server.

image

Desired Behaviour

If in request "Find Common Ancestry" (GET /source/_local/replication-id) , if we provide a request header dbseq=true, it must return a response header update_seq: DB_UPDATE_SEQ, along with usual reply.

This will make step 2 a bit redundant. And for making step 1 redudant, step 3 status text can be modified to give more information for 404, if its DB which do not exist or local doc.

Header based approach, can make old client work as they use to work, and new clients which are sure about source and target existence (say one time during mobile application start), can only do step 3 and know if they need to replicate or not.

Now this may be not a big change, but instead of 3 HTTP request, such clients will only require 1 HTTP request to determine if replication is required or not.

Possible Solution

To make replication protocol work all good with old clients, if for request GET /source/_local/replication-id if a dbseq:true header is provided, then along with the usual reponse, an addtional header update_seq too must be provided.

And if the DB do not exist, then along with 404 status text should be "DB do not exist", and if the local doc "_local/replication_id" do not exist then a corresponding message must be provided.

Additional context

My mobile app (with a client side replicator) do not have rights to create target at remote couchdb server, and do checks existence of remote DB once during initialization.

Currently while replicating , it needs to first get update_seq from DB and then get local replication doc. If we can just enhance step3 (GET /source/_local/replication-id) to provide update seq of db too, then we can reduce first 3 steps to one step at client side replication.

The aim is to reduce multiple request to remote server, when it can be done in one single request. So by a small enahcement such clients can determine requirement for replication in a single step.

anuragvohraec avatar Dec 22 '20 08:12 anuragvohraec

If this is implemented, I will suggest dbseq=true to be a query param instead of request header, as its used as a query in here.

anuragvohraec avatar Jan 06 '21 00:01 anuragvohraec

Hi team, Any comment on this ?

anuragvohraec avatar Jun 10 '21 02:06 anuragvohraec

As far as db / doc not found, I think error reason is already provided:

 % http $DB/mydb2/doc4
HTTP/1.1 404 Object Not Found

{
    "error": "not_found",
    "reason": "Database does not exist."
}
% http $DB/mydb1/doc2
HTTP/1.1 404 Object Not Found

{
    "error": "not_found",
    "reason": "missing"
}

As for dbseq=true we have a similar idea already with the local_seq=true parameter:

% http $DB/mydb1/doc1'?local_seq=true'

{
    "_id": "doc1",
    "_local_seq": "00000008d5c93d5a00000000",
    "_rev": "1-4b8a35d3f70a5962f86c6dd06ceb599c",
    "a": "b"
}

We return the doc update sequence along with a body. I wonder if we can co-opt this feature to return the current dbseq. Something like?

% http $DB/mydb1/doc1'?db_seq=true'

{
    "_id": "doc1",
    "_db_seq": "00000008d5c93d5a110000000",
    "_rev": "1-4b8a35d3f70a5962f86c6dd06ceb599c",
    "a": "b"
}

Though it would be kinda hacky since it won't be document related per-se, so maybe a header is more logical there...

nickva avatar Jun 11 '21 16:06 nickva

As far as db / doc not found, I think error reason is already provided:

 % http $DB/mydb2/doc4
HTTP/1.1 404 Object Not Found

{
    "error": "not_found",
    "reason": "Database does not exist."
}

Yes, my mistake. I some how missed it.

As for dbseq=true we have a similar idea already with the local_seq=true parameter:

Works only for normal docs, but for local docs (replication logs) it won't return anything. Morever the _local_seq is not DB update sequence which is used to determine if replication is required or not.

We return the doc update sequence along with a body. I wonder if we can co-opt this feature to return the current dbseq. Something like?

% http $DB/mydb1/doc1'?db_seq=true'

I would suggest it to be for local docs (replication logs) $db/mydb1/_local/replogs1?db_seq=true;

anuragvohraec avatar Jun 13 '21 07:06 anuragvohraec

Works only for normal docs, but for local docs (replication logs) it won't return anything.

Right, local seq is the update seq of the document, so it won't be usable even if it worked for local documents. But since we have an API to return a sequence in the document I wanted to see if it would make sense having the same kind of API rather than invent something completely new, like returning data in the headers. So far I am 50/50 on the approaches...

With the main branch where sequences are global, it might be interesting to return both _local_seq and _db_seq so in one response we can tell when the document was updated relative to other documents, even in different databases on the same FDB cluster, and also, find out what the current db sequence is when this document was read.

Regarding the replication problem, I was wondering if connections are re-used if 1 vs 2 or 3 connection would have that much of an impact. Some time is spent during the SSL negotiation when setting up a new connection, but after that if the connection stays open there may not be a huge difference between having one or a few more requests.

nickva avatar Jun 13 '21 17:06 nickva

we have an API to return a sequence in the document I wanted to see if it would make sense having the same kind of API rather than invent something completely new, like returning data in the headers...

Yeah any approach would be ok, as long as we get the DB update seq, along with the local docs. I suggested headers/flag based solution so that none of the old client has any kind API problems, for backward compatibility in mind. Specifically the one which has some kind of checks in place for the data they receive from couchdb.

With the main branch where sequences are global, it might be interesting to return both _local_seq and _db_seq so in one response we can tell when the document was updated relative to other documents, even in different databases on the same FDB cluster, and also, find out what the current db sequence is when this document was read.

Absolutely!, will have many usefull cases.

Regarding the replication problem, I was wondering if connections are re-used if 1 vs 2 or 3 connection would have that much of an impact. Some time is spent during the SSL negotiation when setting up a new connection, but after that if the connection stays open there may not be a huge difference between having one or a few more requests.

I am not able to understand this, not an expert on this matter. Are you suggesting that few steps of replication can be combined onto a single connections ?

anuragvohraec avatar Jun 14 '21 15:06 anuragvohraec

I am not able to understand this, not an expert on this matter. Are you suggesting that few steps of replication can be combined onto a single connections ?

Exactly! That's how connection sharing works. After the TCP connection is established to a host, port, SSL session is setup, it can be reused for multiple requests:

  • Connect to 192.168.1.1:443 + do the SSL handshake...
    • GET /mydb ...
    • GET /mydb/_local/doc ...

The time to connect and do the SSL handshake can be expensive, so instead of tearing down the connection and making a new one every time, it can be re-used. Some client libraries can do this too, for example with requests is may look like: https://docs.python-requests.org/en/master/user/advanced/

nickva avatar Jun 14 '21 15:06 nickva

Exactly! That's how connection sharing works. After the TCP connection is established to a host, port, SSL session is setup, it can be reused for multiple requests: The time to connect and do the SSL handshake can be expensive, so instead of tearing down the connection and making a new one every time, it can be re-used. Some client libraries can do this too, for example with requests is may look like: https://docs.python-requests.org/en/master/user/advanced/

After reading your comments, I have been overthinking on this and come to a concluson that REST based API is over all bad. A web socket based API layer would have been way faster and efficient in handling DB connections. So may be couchdb 5.0 can be build on top of websockets. This way a data can be updated to ever listner in nearly real time RethinkDB is an example to this.

anuragvohraec avatar Oct 14 '21 12:10 anuragvohraec

At some point we might have another API or implement HTTP/2, HTTP/3, websockets, etc, but it probably won't be in the contexts of this issue. There are already issues on the roadmap with those ideas.

For now connection pooling as described in https://github.com/apache/couchdb/issues/3308#issuecomment-860778557 will avoid making new TCP/TLS connection.

nickva avatar Nov 13 '23 18:11 nickva