목적

protobuf 에서

reserved, 필드 삭제를 했을 때의 변화를 관찰하고,

왜 필드 삭제가 아닌 reserved를 해야 하는지를 알아본다.



protobuf 문서

 



상황별 비교

 

  기본 reserved delete
proto message TestRequest {
  int32 m1 = 1;
  string m2 = 2;
  int64 m3 = 3;
  int32 m4 = 4;
  string m5 = 5;
  int32 m6 = 6;
  string m7 = 7;
  int64 m8 = 8;
  int32 m9 = 9;
  string m10 = 10;
}
message TestRequest {
  int32 m1 = 1;
  string m2 = 2;
  int64 m3 = 3;
  reserved 4;
  string m5 = 5;
  int32 m6 = 6;
  reserved 7;
  int64 m8 = 8;
  int32 m9 = 9;
  string m10 = 10;
}
message TestRequest {
  int32 m1 = 1;
  string m2 = 2;
  int64 m3 = 3;


  string m5 = 5;
  int32 m6 = 6;


  int64 m8 = 7;
  int32 m9 = 8;
  string m10 = 9;
}
generated code boolean done = false;
while (!done) {
  int tag = input.readTag();
  switch (tag) {
    case 0:
      done = true;
      break;
    case 8:
      {

        m1_ = input.readInt32();
        break;
      }
    case 18:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m2_ = s;
        break;
      }
    case 24:
      {

        m3_ = input.readInt64();
        break;
      }
    case 32:
      {

        m4_ = input.readInt32();
        break;
      }
    case 42:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m5_ = s;
        break;
      }
    case 48:
      {

        m6_ = input.readInt32();
        break;
      }
    case 58:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m7_ = s;
        break;
      }
    case 64:
      {

        m8_ = input.readInt64();
        break;
      }
    case 72:
      {

        m9_ = input.readInt32();
        break;
      }
    case 82:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m10_ = s;
        break;
      }
    default:
      {
        if (!parseUnknownField(
            input, unknownFields, extensionRegistry, tag)) {
          done = true;
        }
        break;
      }
  }
}
boolean done = false;
while (!done) {
  int tag = input.readTag();
  switch (tag) {
    case 0:
      done = true;
      break;
    case 8:
      {

        m1_ = input.readInt32();
        break;
      }
    case 18:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m2_ = s;
        break;
      }
    case 24:
      {

        m3_ = input.readInt64();
        break;
      }
    case 42:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m5_ = s;
        break;
      }
    case 48:
      {

        m6_ = input.readInt32();
        break;
      }
    case 64:
      {

        m8_ = input.readInt64();
        break;
      }
    case 72:
      {

        m9_ = input.readInt32();
        break;
      }
    case 82:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m10_ = s;
        break;
      }
    default:
      {
        if (!parseUnknownField(
            input, unknownFields, extensionRegistry, tag)) {
          done = true;
        }
        break;
      }
  }
boolean done = false;
while (!done) {
  int tag = input.readTag();
  switch (tag) {
    case 0:
      done = true;
      break;
    case 8:
      {

        m1_ = input.readInt32();
        break;
      }
    case 18:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m2_ = s;
        break;
      }
    case 24:
      {

        m3_ = input.readInt64();
        break;
      }
    case 42:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m5_ = s;
        break;
      }
    case 48:
      {

        m6_ = input.readInt32();
        break;
      }
    case 64:
      {

        m8_ = input.readInt64();
        break;
      }
    case 72:
      {

        m9_ = input.readInt32();
        break;
      }
    case 82:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m10_ = s;
        break;
      }
    default:
      {
        if (!parseUnknownField(
            input, unknownFields, extensionRegistry, tag)) {
          done = true;
        }
        break;
      }
  }



serialized data

입력

 

m1 = 43690

m2 = "abcdefg"

m3 = 1431655765

m4 = 43690

m5 = "hijklmn"

m6 = 43690

m7 = "hijklmn"

m8 = 1431655765

m9 = 43690

m10 = "opqrstu"

 

출력

 

기본 reserved delete
08 AAD502
12 07 61626364656667
18 D5AAD5AA05
20 AAD502
2A 07 68696A6B6C6D6E
30 AAD502
3A 07 68696A6B6C6D6E
40 D5AAD5AA05
48 AAD502
52 07 6F707172737475
08 AAD502
12 07 61626364656667 
18 D5AAD5AA05

2A 07 68696A6B6C6D6E
30 AAD502

40 D5AAD5AA05
48 AAD502
52 07 6F707172737475
08 AAD502
12 07 61626364656667
18 D5AAD5AA05

2A 07 68696A6B6C6D6E
30 AAD502

40 D5AAD5AA05
48 AAD502
52 07 6F707172737475





결론

  1. 이미 stub이 배포 된 .proto 에서 필드를 제거 할 땐, reserved를 이용하자.
  2. 절대로 property number는 변경하지 말자.




추가

optional일 때는?



default optional
message TestRequest {
  int32 m1 = 1;
  int32 m2 = 2;
  int32 m3 = 3;
}
message OptionalTest {
int32 m1 = 1;
optional int32 m2 = 2;
int32 m3 = 3;
}
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
  case 0:
    done = true;
    break;
  case 8:
    {

      m1_ = input.readInt32();
      break;
    }
  case 16:
    {

      m2_ = input.readInt32();
      break;
    }
  case 24:
    {

      m3_ = input.readInt32();
      break;
    }
  default:
    {
      if (!parseUnknownField(
          input, unknownFields, extensionRegistry, tag)) {
        done = true;
      }
      break;
    }
}
}

boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
  case 0:
    done = true;
    break;
  case 8:
    {

      m1_ = input.readInt32();
      break;
    }
  case 16:
    {
      bitField0_ |= 0x00000001;
      m2_ = input.readInt32();
      break;
    }
  case 24:
    {

      m3_ = input.readInt32();
      break;
    }
  default:
    {
      if (!parseUnknownField(
          input, unknownFields, extensionRegistry, tag)) {
        done = true;
      }
      break;
    }
}
}

 

optional 일 때 추가되는 것들



default optional


private int m1_;







public int getM1() {
  return m1_;
}


public Builder setM1(int value) {
  m1_ = value;
  onChanged();
  return this;
}

public Builder clearM1() {
  m1_ = 0;
  onChanged();
  return this;
}

private int bitField0_;

private int m2_;

public boolean hasM2() {
return ((bitField0_ & 0x00000001) != 0);
}

public int getM2() {
return m2_;
}

public Builder setM2(int value) {
bitField0_ |= 0x00000001;
m2_ = value;
onChanged();
return this;
}

public Builder clearM2() {
bitField0_ = (bitField0_ & ~0x00000001);
m2_ = 0;
onChanged();
return this;
}

 

+ Recent posts