A single instance of the Impala shell. The process is started when this object is constructed, and then users should repeatedly call send_cmd(), followed eventually by get_result() to retrieve the process output. This constructor will wait until Impala shell is connected for the speci
| 224 | |
| 225 | |
| 226 | class ImpalaShell(object): |
| 227 | """A single instance of the Impala shell. The process is started when this object is |
| 228 | constructed, and then users should repeatedly call send_cmd(), followed eventually by |
| 229 | get_result() to retrieve the process output. This constructor will wait until |
| 230 | Impala shell is connected for the specified timeout unless wait_until_connected is |
| 231 | set to False or --quiet is passed into the args.""" |
| 232 | def __init__(self, vector, args=None, env=None, wait_until_connected=True, timeout=60, |
| 233 | stdout_file=None, stderr_file=None): |
| 234 | self.shell_process = self._start_new_shell_process(vector, args, env=env, |
| 235 | stdout_file=stdout_file, |
| 236 | stderr_file=stderr_file) |
| 237 | # When --quiet option is passed to Impala shell, we should not wait until we see |
| 238 | # "Connected to" because it will never be printed to stderr. The same is true |
| 239 | # if stderr is redirected. |
| 240 | if wait_until_connected and (args is None or "--quiet" not in args) and \ |
| 241 | stderr_file is None: |
| 242 | # We don't want to hang waiting for input. So, here are the scenarios |
| 243 | # we need to handle: |
| 244 | # 1. Shell process exits |
| 245 | # 2. Shell fails to connect. This can lead to an interactive prompt |
| 246 | # that blocks for input forever. The two messages to look for are |
| 247 | # "Error connecting" and "Socket error" |
| 248 | # 3. Process successfully connecting: "Connected to" |
| 249 | # Cases 1 and 2 should lead to an assert. |
| 250 | start_time = time.time() |
| 251 | process_status = None |
| 252 | connection_err = None |
| 253 | connected = False |
| 254 | while time.time() - start_time < timeout: |
| 255 | # Condition 1: check if the shell process has exited |
| 256 | # poll() returns None until the process exits |
| 257 | process_status = self.shell_process.poll() |
| 258 | if process_status is not None: |
| 259 | break |
| 260 | # readline() can block forever, so the timeout logic may not be effective |
| 261 | # if something gets stuck here. |
| 262 | line = self.shell_process.stderr.readline() |
| 263 | # Condition 2: check for errors connecting |
| 264 | if ImpalaShellClass.ERROR_CONNECTING_MESSAGE in line or \ |
| 265 | ImpalaShellClass.SOCKET_ERROR_MESSAGE in line: |
| 266 | connection_err = line |
| 267 | break |
| 268 | |
| 269 | # Condition 3: check if the connection is successful |
| 270 | connected = ImpalaShellClass.CONNECTED_TO_MESSAGE in line |
| 271 | if connected: |
| 272 | break |
| 273 | |
| 274 | assert process_status is None, \ |
| 275 | "Impala shell exited with return code {0}".format(process_status) |
| 276 | assert connection_err is None, connection_err |
| 277 | assert connected, "Impala shell is not connected" |
| 278 | |
| 279 | def pid(self): |
| 280 | return self.shell_process.pid |
| 281 | |
| 282 | def send_cmd(self, cmd): |
| 283 | """Send a single command to the shell. This method adds the end-of-query |
no outgoing calls