> On April 23, 2014, 10:22 a.m., Ivan Kelly wrote:
> > bookkeeper-server/src/main/proto/BookkeeperProtocol.proto, line 80
> > <https://reviews.apache.org/r/17895/diff/2/?file=563033#file563033line80>
> >
> >     This would be better served with a boolean. protobuf will keep it 
> > compact.
> 
> Sijie Guo wrote:
>     being Flag will make it easier to add other flags in future.
> 
> Ivan Kelly wrote:
>     No it doesn't. Lets say you do add another flag in the future. How do you 
> specify that it's both a FENCE_LEDGER and NEW_FLAG? You need the field to be 
> repeated, and then you need code to loop through the flags. Compared to 
> msg.isFenceLedger(), this seems much more cumbersome.
> 
> Sijie Guo wrote:
>     I don't say this field is bits-set-like of flags. as the long poll 
> changes we mentioned, we are going to add a new flag 'ENTRY_PIGGYBACK' for 
> read. so a read request is either a normal read (without Flag), a fence read 
> (flag = FENCE_LEDGER) or a piggyback read (flag = ENTRY_PIGGYBACK). Being 
> repeated will be kind of complicated, as you need to loop all possible 
> permutation.
> 
> Ivan Kelly wrote:
>     This is ugly and shortsighted. There may well be a case in the future 
> where two flags need to be specified. What do we do then? Add a flags2 field?
> 
> Sijie Guo wrote:
>     why this couldn't be a 3rd flag? FENCE_LEDGER_AND_PIGGYBACK?
>     
>     in your repeated way, let's say you have n flags, you would have n! ways 
> to combine them. it is hard to figure out what kind of combination works for 
> what situation. as some of your flags are exclusive with others. so renaming 
> the combination specifically would make it clear.
> 
> Ivan Kelly wrote:
>     as you say, with n flags specified, there are n! combinations. so if 
> another flag as added, you will have to add n values to the enum to cover the 
> different combinations. whether the flags are exclusive is for the 
> application to decide. it shouldnt be implicit in the protocol encoding.
> 
> Sijie Guo wrote:
>     same explanation for OperationType is applying here. if n flags mostly 
> are used individually, an explicit way will just need to deal with around n 
> possibilities. but you need to write lots of if..else branches for inferring 
> in an implicit way.
> 
> Ivan Kelly wrote:
>     Your assumption here is that all the flag handling code will be in one 
> place in a big switch. this isnt the case. I dont know how you have 
> implemented piggyback, but i would guess it would be something like.
>     
>     Response processReadRequest(Request req) {
>         if (isFencing(req)) {
>             fenceLedger();
>         }
>         byte[] data = fetchEntry(req.getLedgerId(), req.getEntryId());
>         Response resp = new Response(OK, data);
>         if (isPiggyback(req)) {
>             addPiggyback(resp);
>         }
>         return resp;
>     }
>     
>     Now consider how #isPiggyback and #isFencing would be implemented with 
> enums and with individual boolean flags? which is shorter? Which is easier to 
> maintain?
> 
> Sijie Guo wrote:
>     isFencing => flag == Flag.FENCE_LEDGER
>     isPiggyback => flag == ENTRY_PIGGYBACK
>     
>     what is the difference above for maintaining?
>     
>     using the flag, the semantic is super clear that your request is either a 
> fencing request or a piggyback request. it would not happen that you received 
> a request that probably have two flags enabled, then what does it mean if the 
> requests have two boolean flags enabled, don't consider the case (that is 
> always the point that I made for OperationType and Flag here)? then which is 
> easier to maintain?
> 
> Ivan Kelly wrote:
>     my comment from yesterday doesn't wasnt saved by review board >:|
>     
>     Anyhow, what i asked was, can you guarantee that there will never *ever* 
> be a case where two flags will need to be set on a single op in the future?
> 
> Sijie Guo wrote:
>     well, I already made a comment on your case: "why this couldn't be a 3rd 
> flag? FENCE_LEDGER_AND_PIGGYBACK?", no? and this is how hedwig handles 
> subscription mode, 'create', 'attach', 'create_and_attach', no?
>     
>     and again, as I said in previous comment, if you define flags in an 
> explicit way, you would have much clearer branches on what kind of operations 
> should be executed on what flags, like below: (take an example, A, B, C, 
> A_AND_B, B_AND_A)
>     
>     switch (flag) {
>     case A:
>       a();
>       break;
>     case B:
>       b();
>       break;
>     case C:
>       c();
>       break;
>     case A_AND_B:
>       a();
>       b();
>       break;
>     case B_AND_A:
>       b();
>       // other executions between b() and a(), which is different from 
> A_AND_B case.
>       a();
>       break;
>     }
>     
>     but if you define flags in an implicit way, you need to check all 
> possible negative cases to avoid the program failed in abnormal cases (e.g. 
> bad combinations, bad order of flags). isn't that introducing much harder 
> work for maintenance? 
>
> 
> Rakesh R wrote:
>     If we have a set of flags, also consider both AND/OR conjunctions the 
> combinations may grow and thus increases the complexity of the problem. I 
> feel it doesn't matter whether you are using enum type or bool flag, both 
> will have 'chain of if conditions' either at the client side or at the server 
> side. If I understood correctly the switch case you are talking will be added 
> at the server side. Now for setting 'A_AND_B' enum type in the request, 
> client side we need to have the 'chain of if conditions' no?.
>     
>     I could see few advantages of having 'if chain' at the client side, 
> server would not worry about the conditional evaluation which may be in a 
> critical section. Secondly it would be easy to define strategies against enum 
> type and pass it over different layers without worrying about how they formed.
>     
>     If we think the problem space is small and assume we have only few set of 
> flags I prefer enum. Before reaching to a conclusion I've one question about 
> the number 'n' of flags and how much value 'n' can grow ?. Only my worry is, 
> once we set the protocol to enum type, as we all know couldn't get another 
> chance to change it later as 'n' increases.

> Now for setting 'A_AND_B' enum type in the request, client side we need to 
> have the 'chain of if conditions' no?.

why client need to have the chain? client just need to set different flag value 
to indicate different type of single read. 

>  how much value 'n' can grow?

I could tell the future. but I don't see it would grow too much. A specific 
enum value would make semantic more clear.


> On April 23, 2014, 10:22 a.m., Ivan Kelly wrote:
> > bookkeeper-server/src/main/proto/BookkeeperProtocol.proto, line 33
> > <https://reviews.apache.org/r/17895/diff/2/?file=563033#file563033line33>
> >
> >     This should certainly not be an enum. Otherwise we need to bump the 
> > protocol version each time we add an error code.
> >     
> >     Imagine the scenario where both server and client are running 4.3.0. 
> > Then the server is upgraded with 4.3.1 which a new error EPRINTERONFIRE. It 
> > sends this to the client who throws a decode error.
> 
> Sijie Guo wrote:
>     how could being not enum help this? if it is integer, client still has no 
> idea how to interpret, so it is still invalid response from 4.3.0 client. I 
> thought we reached an agreement on enum on the ticket, no?
> 
> Ivan Kelly wrote:
>     So for version and operationtype, enum is ok. These originate at the 
> client, so if the servers are always upgraded at the client, there's no 
> interoperability issues. Status codes originate at the server though, so it 
> is possible for the server to send a statuscode that is unrecognised to a 
> client. The normal way to handle this would be a "else" or "default:" to pass 
> this up to the client as a BKException.UnexpectedConditionException. If it's 
> an enum, this will throw a decode exception in the netty decoder, which is 
> harder to handle.
>     
>     To resolve this on the server side, by checking the version and only 
> sending errors valid for that version, implies two things. Firstly, every 
> error code change will require the version to be bumped and secondly, that 
> there will need to be a list maintained for which errors are valid for each 
> version. This goes against the motivation for using protobuf in the first 
> place.
> 
> Sijie Guo wrote:
>     this is the application level agreement, no? it doesn't matter that u are 
> using a protobuf protocol or using current protocol, or it also doesn't 
> matter that u are using an integer or an enum. in any case, the best way is 
> as you described, you shouldn't send new status code back to an old client, 
> as the new status code is meaningless to the old client.
> 
> Ivan Kelly wrote:
>     but how do you know its an old client? Only by bumping the version number 
> each time you add an error code. In which case you end up with a whole lot of 
> junk like "if (client.version == X) { send A } else if (client.version == Y) 
> { send B } else if (client.version ..." which is exactly what protobuf was 
> designed to avoid (see "A bit of history" on 
> https://developers.google.com/protocol-buffers/docs/overview).
> 
> Sijie Guo wrote:
>     a else or default branch would make the behavior unpredictable as an old 
> client is treating a new status code as some kind of unknown. as you said, 
> you want to treat them as UnexpectedConditionException. But what does 
> UnexpectedConditionException means? doesn't it mean the sever already breaks 
> backward compatibility, since server couldn't satisfy the old client's 
> request.
>     
>     so still, if server wants to be backward compatibility to clients, in any 
> cases, it needs to know what version of protocol that the client is speaking 
> and handle them accordingly, not just let client to do their job in an 
> unexpected way.
>     
>     I don't see any elegant solutions without detecting protocol version. if 
> you have, please describe how not being enum would avoid this.
> 
> Ivan Kelly wrote:
>     the default behaviour for an unknown error code is something we already 
> use today.
>     
> https://github.com/apache/bookkeeper/blob/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java#L714
>     
>     The client only needs to know that the request failed. the point of the 
> different error codes is so that the client could take specific recovery 
> steps. the default behaviour is just to pass the error up.
> 
> Sijie Guo wrote:
>     the default behavior was there just for all already known status codes. 
> but it doesn't mean it is correct for any unknown status codes. and when u 
> are saying 'the client only needs to know that the request failed', you are 
> making an assumption that there is only one status code indicating OK, other 
> status code should be taken as failed. but it isn't true. say in an old 
> protocol, we supported range reads, it responded with OK, list of entry 
> response (0 = <data>, 1 = missing, 2 = missing, 3 = <data>). if we are going 
> to improve our protocol to make communication more efficient, we are going to 
> change the protocol to get rid of transferring missing entries: responding 
> with PARTIAL_OK, list of existing entries (0 = <data>, 3 = <data>). 
>     
>     in this case, if server doesn't distinguish the client's protocol, just 
> respond every range reads with PARTIAL_OK, would did break the compatibility 
> with old protocol, as old protocol treats it as failure by default behavior. 
> in order to maintain backward compatibility, server needs to detect the 
> client's protocol and responds accordingly. as what I said, for backward 
> compatibility, a protocol doesn't really help if it involves behavior in 
> application agreement. and a default behavior is not exact right.
>     
>     for me, using protocol. it means that it is easy for us to add new 
> requests type, add new fields in existing requests. besides that, we need to 
> keep the backward compatibility in our level.
> 
> Ivan Kelly wrote:
>     when i say that 'the client only needs to know that the request failed', 
> it means that the client only needs to recognise the statuses which indicate 
> success. for any request, the status codes which indicate success should 
> never change. For a read request or add request, only OK is SUCCESS. For 
> range read,  only PARTIAL_OK and OK are success. But the client will never 
> send a range read request unless it already knows about PARTIAL_OK.
> 
> Sijie Guo wrote:
>     > “But the client will never send a range read request unless it already 
> knows about PARTIAL_OK.” 
>     
>     the example that I made is that the range read introduced with OK, but if 
> it is going to evolved to have PARTIAL_OK. then that will be an problem.
> 
> Ivan Kelly wrote:
>     Partial_ok doesn't make sense if you're using the concept of packet 
> status and operation status (as mentioned below).
> 
> Sijie Guo wrote:
>     well, if u are talking about a specific case (e.g. range read), I might 
> agree with u. but if you read my comments, it is just the case that I 
> explained how the protocol might be evolved. And my point is and always will 
> be for backward compatibility, the server shouldn't send any unknown 
> codes/fields back to clients that speaks old protocol, this is part of 
> application-level agreement, no matter using enum or integer.
> 
> Rakesh R wrote:
>     Using enum is more readable and would be good for newcomers too. Assume a 
> case where we are introducing new EC for an existing request type at the side 
> server side, EC#NEW_ERR_CODE in 4.3.1 and client is old one 4.3.0. Ideally in 
> this case, bk client should say its unknown code.
>     
>     Does this create any parsing issues at the protobuf ?. If not, I'm OK 
> using enum for the StatusCode too.
> 
> Sijie Guo wrote:
>     if you read the conversation about this, my point is that for correct 
> backward compatibility, we should avoid sending unknown error codes back to 
> an old client.
> 
> Rakesh R wrote:
>     So server should have version specific checks and generates the error 
> codes, isn't it ?.
> 
> Sijie Guo wrote:
>     yes. exact as what I pointed. sending responses matching exact version of 
> protocol, isn't that exactly for application level backward compatible? why 
> this would be the concern?
> 
> Rakesh R wrote:
>     There is no big concern here. I'm trying to understand the current 
> approach and the future path to avoid any compatibility issues later.
> 
> Sijie Guo wrote:
>     for backward compatibility, it is comprised of wire compatibility and 
> application-semantic compatibility. using protobuf, we could easily achieve 
> wire compatibility by adding new optional fields. for application-semantic, 
> the server needs to detect what version of the client is talking, and send 
> correct version of responses according to its version. the version field in 
> the request/response structure helps achieving this.
> 
> Rakesh R wrote:
>     Maintaining version list has its own complexities, but again it depends 
> on the client side requirements. As I know protobuf parser would not get 
> decode exceptions if any unknown enum code comes from server, instead this 
> will return a null value. If this is the behavior of protobuf, then today its 
> not a blocker for this patch. Because in your patch, you have already handled 
> unknown error code in PerChannelBookieClient#statusCodeToExceptionCode() and 
> treats this code as an op failure.

version list is more for application level semantic backward compatibility. a 
clear specific version for backward compatibility would be more clear than any 
implicit solution. although it might introduce code, it is clear for 
maintenance.


- Sijie


-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviews.apache.org/r/17895/#review41130
-----------------------------------------------------------


On April 24, 2014, 7:43 a.m., Sijie Guo wrote:
> 
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://reviews.apache.org/r/17895/
> -----------------------------------------------------------
> 
> (Updated April 24, 2014, 7:43 a.m.)
> 
> 
> Review request for bookkeeper and Ivan Kelly.
> 
> 
> Bugs: BOOKKEEPER-582
>     https://issues.apache.org/jira/browse/BOOKKEEPER-582
> 
> 
> Repository: bookkeeper-git
> 
> 
> Description
> -------
> 
> - introducing protobuf support for bookkeeper
> - for server: introduce packet processor / EnDecoder for different protocol 
> supports
> - for client: change PCBC to use protobuf to send requests
> - misc changes for protobuf support
> 
> (bookie server is able for backward compatibility) 
> 
> 
> Diffs
> -----
> 
>   bookkeeper-server/pom.xml ebc1198 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/IndexInMemPageMgr.java
>  56487aa 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerChecker.java
>  28e23d6 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/client/PendingReadOp.java
>  fb36b90 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/processor/RequestProcessor.java
>  241f369 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieProtoEncoding.java
>  1154047 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieRequestHandler.java
>  b922a82 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieRequestProcessor.java
>  8155b22 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookkeeperProtocol.java
>  PRE-CREATION 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PacketProcessorBase.java
>  PRE-CREATION 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PacketProcessorBaseV3.java
>  PRE-CREATION 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
>  a10f7d5 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/ReadEntryProcessor.java
>  PRE-CREATION 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/ReadEntryProcessorV3.java
>  PRE-CREATION 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/WriteEntryProcessor.java
>  PRE-CREATION 
>   
> bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/WriteEntryProcessorV3.java
>  PRE-CREATION 
>   bookkeeper-server/src/main/proto/BookkeeperProtocol.proto PRE-CREATION 
>   bookkeeper-server/src/main/resources/findbugsExclude.xml 97a6156 
>   
> bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestProtoVersions.java
>  5fcc445 
>   
> bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java
>  3f8496f 
>   
> bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java
>  bc05229 
>   
> bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TestBackwardCompat.java
>  8376b46 
>   compat-deps/bookkeeper-server-compat-4.2.0/pom.xml PRE-CREATION 
>   compat-deps/hedwig-server-compat-4.2.0/pom.xml PRE-CREATION 
>   compat-deps/pom.xml f79582d 
>   hedwig-server/pom.xml 06cf01c 
>   
> hedwig-server/src/test/java/org/apache/hedwig/server/TestBackwardCompat.java 
> 8da109e 
> 
> Diff: https://reviews.apache.org/r/17895/diff/
> 
> 
> Testing
> -------
> 
> unit tests. backward tests.
> 
> 
> Thanks,
> 
> Sijie Guo
> 
>

Reply via email to