YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/yql/redis/redisserver/redis_parser.h
Line
Count
Source
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
#ifndef YB_YQL_REDIS_REDISSERVER_REDIS_PARSER_H_
14
#define YB_YQL_REDIS_REDISSERVER_REDIS_PARSER_H_
15
16
#include <memory>
17
#include <string>
18
19
#include <boost/container/small_vector.hpp>
20
21
#include "yb/client/client_fwd.h"
22
23
#include "yb/util/status_fwd.h"
24
#include "yb/util/net/socket.h"
25
#include "yb/util/size_literals.h"
26
27
#include "yb/yql/redis/redisserver/redis_fwd.h"
28
29
namespace yb {
30
namespace redisserver {
31
32
constexpr size_t kMaxRedisValueSize = 512_MB;
33
constexpr int64_t kNoneTtl = -1;
34
35
CHECKED_STATUS ParseSet(client::YBRedisWriteOp *op, const RedisClientCommand& args);
36
CHECKED_STATUS ParseGet(client::YBRedisReadOp* op, const RedisClientCommand& args);
37
38
// TODO: make additional command support here
39
40
// RedisParser is a finite state machine with memory.
41
// It could remember current parsing state and be invoked again when new data arrives.
42
// In this case parsing will be continued from the last position.
43
class RedisParser {
44
 public:
45
  explicit RedisParser(const IoVecs& source)
46
211k
      : source_(source), full_size_(IoVecsFullSize(source)) {
47
211k
  }
48
49
  void SetArgs(boost::container::small_vector_base<Slice>* args);
50
51
  // Begin of input is going to be consumed, so we should adjust our pointers.
52
  // Since the beginning of input is being consumed by shifting the remaining bytes to the
53
  // beginning of the buffer.
54
  void Consume(size_t count);
55
56
  // New data arrived, so update the end of available bytes.
57
  void Update(const IoVecs& source);
58
59
  // Parse next command.
60
  Result<size_t> NextCommand();
61
62
 private:
63
  // Redis command could be of 2 types.
64
  // First one is just single line that terminates with \r\n.
65
  // Second one is bulk command, that has form:
66
  // *<BULK_ARGUMENTS>\r\n
67
  // $<SIZE_IN_BYTES_OF_BULK_ARGUMENT_1>\r\n
68
  // <BULK_ARGUMENT_1>\r\n
69
  // ...
70
  // $<SIZE_IN_BYTES_OF_BULK_ARGUMENT_N>\r\n
71
  // <BULK_ARGUMENT_N>\r\n
72
  enum class State {
73
    // Initial state of parser.
74
    INITIAL,
75
    // We determined that command is single line command and waiting for \r\n
76
    SINGLE_LINE,
77
    // We are parsing the first line of a bulk command.
78
    BULK_HEADER,
79
    // We are parsing bulk argument size. arguments_left_ has valid value.
80
    BULK_ARGUMENT_SIZE,
81
    // We are parsing bulk argument body. arguments_left_, current_argument_size_ have valid values.
82
    BULK_ARGUMENT_BODY,
83
    // Just mark that we finished parsing of command. Will become INITIAL in NextCommand.
84
    FINISHED,
85
  };
86
87
  CHECKED_STATUS AdvanceToNextToken();
88
  CHECKED_STATUS Initial();
89
  CHECKED_STATUS SingleLine();
90
  CHECKED_STATUS BulkHeader();
91
  CHECKED_STATUS BulkArgumentSize();
92
  CHECKED_STATUS BulkArgumentBody();
93
  CHECKED_STATUS FindEndOfLine();
94
95
  // Parses number with specified bounds.
96
  // Number is located in separate line, and contain prefix before actual number.
97
  // Line starts at token_begin_ and pos_ is a start of next line.
98
  Result<ptrdiff_t> ParseNumber(char prefix,
99
                                ptrdiff_t min,
100
                                ptrdiff_t max,
101
                                const char* name);
102
103
  // Returns pointer to byte with specified offset in all iovecs of source_.
104
  // Pointer byte is valid, the end of valid range should be determined separately if required.
105
  const char* offset_to_pointer(size_t offset) const;
106
107
  std::pair<size_t, size_t> offset_to_idx_and_local_offset(size_t offset) const;
108
109
7.31M
  char char_at_offset(size_t offset) const {
110
7.31M
    return *offset_to_pointer(offset);
111
7.31M
  }
112
113
  static constexpr size_t kNoToken = std::numeric_limits<size_t>::max();
114
115
  // Data to parse.
116
  IoVecs source_;
117
118
  size_t full_size_;
119
120
  // Current parsing position.
121
  size_t pos_ = 0;
122
123
  // Command arguments.
124
  boost::container::small_vector_base<Slice>* args_ = nullptr;
125
126
  // Parser state.
127
  State state_ = State::INITIAL;
128
129
  // Beginning of last token.
130
  size_t token_begin_ = kNoToken;
131
132
  // Mark that current token is incomplete.
133
  bool incomplete_ = false;
134
135
  // Number of arguments left in bulk command.
136
  size_t arguments_left_ = 0;
137
138
  // Size of the current argument in bulk command.
139
  size_t current_argument_size_ = 0;
140
141
  std::vector<char> number_buffer_;
142
};
143
144
}  // namespace redisserver
145
}  // namespace yb
146
147
#endif  // YB_YQL_REDIS_REDISSERVER_REDIS_PARSER_H_