Example #1
0
    def read(self, target_filename: str, *, remove: optional(bool) = None, frag_size: optional(int) = None) -> bytes:

        try:

            self._remove = remove or False
            self._target_filename, _ = self._normalize_filename(target_filename)

            file_size = os_path.getsize(self._target_filename)
            frag_size = frag_size or 65536

            pmnc.log.info("reading {0:d} byte(s) from file {1:s}".\
                          format(file_size, self._target_filename))
            try:

                data = BytesIO()

                with open(self._target_filename, "rb") as f:
                    while not pmnc.request.expired:
                        portion = f.read(frag_size)
                        if not portion:
                            break
                        data.write(portion)
                    else:
                        raise Exception("request deadline reading data from file {0:s}".\
                                        format(self._target_filename))

            except:
                pmnc.log.info("reading {0:d} byte(s) from file {1:s} failed: {2:s}".\
                              format(file_size, self._target_filename, exc_string()))
                raise
            else:
                return data.getvalue()

        except:
            ResourceError.rethrow(recoverable = True) # no irreversible changes
Example #2
0
 def delete(self, key: str):
     try:
         self._txn = \
             pmnc.state.explicit_transaction(self.source_module_name,
                                             self._txn, self._delete, key)[0]
     except:
         ResourceError.rethrow(recoverable = True, terminal = False)
Example #3
0
    def send(self, message_text: str, **kwargs) -> str:

        try:

            header_fields = " and {0:d} custom header field(s): {1:s}".\
                            format(len(kwargs), ", ".join(kwargs.keys())) \
                            if kwargs else ""

            correlation_id = kwargs.get("JMSCorrelationID")

            message_description = \
                "JMS message{0:s} with {1:d} content byte(s){2:s}".\
                format(" {0:s}".format(correlation_id) if correlation_id else "",
                       len(message_text), header_fields)

            pmnc.log.info("sending {0:s}".format(message_description))
            try:
                pkt = self._sync_adapter_command("SEND", XPmncMessageText = message_text, **kwargs)
            except:
                pmnc.log.warning("sending {0:s} failed: {1:s}".\
                                 format(message_description, exc_string()))
                raise
            else:
                self._message_id = pkt["XPmncMessageID"]

        except:
            ResourceError.rethrow(recoverable = True) # no irreversible changes
        else:
            return self._message_id
Example #4
0
 def set(self, key: str, value):
     try:
         self._txn = \
             pmnc.state.explicit_transaction(self.source_module_name,
                                             self._txn, self._set, key, value)[0]
     except:
         ResourceError.rethrow(recoverable = True, terminal = False)
Example #5
0
 def _map_reduce(self, collection: valid_collection, params: dict,
                 **kwargs) -> MongoDB_Response:
     params_ = odict({"mapreduce": collection})
     try:
         params_.update(map=params.pop("map"))
         params_.update(reduce=params.pop("reduce"))
     except KeyError:
         ResourceError.rethrow(
             description="map and reduce functions must be specified")
     query = params.pop("having", {})
     params_.update(params)
     out = "{0:s}.mr_{1:s}".format(collection,
                                   b2a_hex(urandom(8)).decode("ascii"))
     params_["out"] = out
     rs = self._command("", "mapreduce", params_, **kwargs)
     try:
         counts = rs.documents[0]["counts"]
         if pmnc.log.debug:
             pmnc.log.debug(
                 "-- MAP/REDUCE: IN={0[input]:d}, EMIT={0[emit]:d}, "
                 "OUT={0[output]:d}".format(counts))
         return self._find(out,
                           query,
                           docs_to_return=-counts["output"],
                           exhaust=True)
     finally:
         self._drop(out)
Example #6
0
 def get(self, key: str, default=None):
     try:
         self._txn, result = pmnc.state.explicit_transaction(
             self.source_module_name, self._txn, self._get, key, default
         )
     except:
         ResourceError.rethrow(recoverable=True, terminal=False)
     else:
         return result
Example #7
0
 def get(self, key: str, default = None):
     try:
         self._txn, result = \
             pmnc.state.explicit_transaction(self.source_module_name,
                                             self._txn, self._get, key, default)
     except:
         ResourceError.rethrow(recoverable = True, terminal = False)
     else:
         return result
Example #8
0
    def _execute_sql(self, sql, params):

        try:
            param_list = ", ".join("@{0:s} = {1:s}".format(n, v) for n, v in params.items())
            at_params = { n: "@{0:s}".format(n) for n in params.keys() }
            sql = sql.format(**at_params)
        except:
            ResourceError.rethrow(recoverable = True, terminal = False)

        cursor = self._connection.cursor()
        try:

            for n, v in params.items():
                cursor.execute("SET @{0:s}={1:s}".format(n, v))

            pmnc.log.info(">> {0:s}".format(sql))
            if param_list:
                if pmnc.log.debug:
                    pmnc.log.debug("-- {0:s} -- ({1:s})".format(sql, param_list))

            records = []
            try:

                cursor.execute(sql)
                rowcount = cursor.rowcount

                if rowcount >= 0:
                    pmnc.log.info("<< OK, {0:d} record(s)".format(rowcount))
                    if rowcount > 0 and cursor.description:
                        column_names = [ t[0] for t in cursor.description ]
                        for record in cursor.fetchall():
                            records.append(dict(zip(column_names, record)))
                else:
                    pmnc.log.info("<< OK")

            except MySQL_Error as e:
                code, message = e.args[0].args
                pmnc.log.warning("<< {0:s}{1:s} !! MySQL_Error(\"[{2:d}] {3:s}\") in {4:s}".\
                                 format(sql, " -- ({0:s})".format(param_list)
                                        if param_list else "", code, message, trace_string()))
                SQLResourceError.rethrow(recoverable = True,
                        code = code, description = message) # note that there is no state
            except Exception:
                pmnc.log.warning("<< {0:s}{1:s} !! {2:s}".\
                                 format(sql, " -- ({0:s})".format(param_list)
                                        if param_list else "", exc_string()))
                ResourceError.rethrow(recoverable = True)
            else:
                return records

        finally:
            cursor.close()
Example #9
0
    def _execute_sql(self, sql, params):

        try:
            sql, params = self._convert_to_qmarks(sql, params)
            param_list = ", ".join(map(lambda x: isinstance(x, str)
                                                 and "'{0:s}'".format(x)
                                                 or str(x), params))
        except:
            ResourceError.rethrow(recoverable = True, terminal = False)

        pmnc.log.info(">> {0:s}".format(sql))
        if param_list:
            if pmnc.log.debug:
                pmnc.log.debug("-- {0:s} -- ({1:s})".format(sql, param_list))

        records = []
        try:

            self._cursor.execute(sql, params)

            rowcount = self._cursor.rowcount
            if rowcount >= 0:
                pmnc.log.info("<< OK, {0:d} record(s)".format(rowcount))
                if self._cursor.description and rowcount > 0:
                    column_names = [ t[0].decode("ascii") for t in self._cursor.description ]
                    for record in self._cursor.fetchall():
                        records.append(dict(zip(column_names, record)))
            else:
                pmnc.log.info("<< OK")

        except ProgrammingError as e:
            try:
                level, state, message = map(self._decode_message, e.args)
            except:
                state, message = "PG800", str(e)
            state = state.upper()
            pmnc.log.warning("<< {0:s}{1:s} !! PostgreSQL_Error(\"[{2:s}] {3:s}\") in {4:s}".\
                             format(sql, " -- ({0:s})".format(param_list)
                                    if param_list else "", state, message, trace_string()))
            SQLResourceError.rethrow(
                    state = state, description = message, # note that there is no code
                    recoverable = True, terminal = state[:2] not in self._safe_states)
        except:
            pmnc.log.warning("<< {0:s}{1:s} !! {2:s}".\
                             format(sql, " -- ({0:s})".format(param_list)
                                    if param_list else "", exc_string()))
            ResourceError.rethrow(recoverable = True)
        else:
            return records
 def _py_to_sql_int(self, v):
     if -2147483648 <= v <= 2147483647:
         return "adInteger", 4, v
     elif -9223372036854775808 <= v <= 9223372036854775807:
         return "adBigInt", 8, v
     else:
         raise ResourceError(description = "integer value too large",
                             recoverable = True, terminal = False)
Example #11
0
    def _execute_sql(self, sql, params):

        try:
            sql, params = self._convert_bind_points(sql, params)
            param_list = ", ".join("{0:s}={1:s}".format(k, isinstance(v, str) and "'{0:s}'".format(v) or str(v))
                                   for k, v in params.items())
        except:
            ResourceError.rethrow(recoverable = True, terminal = False)

        pmnc.log.info(">> {0:s}".format(sql))
        if param_list:
            if pmnc.log.debug:
                pmnc.log.debug("-- {0:s} -- ({1:s})".format(sql, param_list))

        records = []
        try:

            self._cursor.execute(sql, params)

            rowcount = self._cursor.rowcount
            if rowcount >= 0:
                pmnc.log.info("<< OK, {0:d} record(s)".format(rowcount))
                if self._cursor.description and rowcount > 0:
                    column_names = [ t.name for t in self._cursor.description ]
                    for record in self._cursor.fetchall():
                        records.append(dict(zip(column_names, record)))
            else:
                pmnc.log.info("<< OK")

        except PGError as e:
            state, message = e.pgcode, " ".join(s.strip() for s in e.pgerror.split("\n"))
            pmnc.log.warning("<< {0:s}{1:s} !! {2:s}(\"{3:s}{4:s}\") in {5:s}".\
                             format(sql, " -- ({0:s})".format(param_list) if param_list else "",
                                    e.__class__.__name__, "[{0:s}] ".format(state) if state else "",
                                    message, trace_string()))
            SQLResourceError.rethrow(
                    state = state, description = message, # note that there is no code
                    recoverable = True, terminal = not state or state[:2] not in self._safe_states)

        except:
            pmnc.log.warning("<< {0:s}{1:s} !! {2:s}".\
                             format(sql, " -- ({0:s})".format(param_list)
                                    if param_list else "", exc_string()))
            ResourceError.rethrow(recoverable = True)
        else:
            return records
Example #12
0
    def write(self, target_filename: str, data_b: bytes, *, overwrite: optional(bool) = True):

        try:

            self._overwrite = overwrite or False
            self._target_filename, target_directory = self._normalize_filename(target_filename)

            # determine the location of temporary files
            # and create the temporary directory if necessary

            temp_directory = os_path.normpath(self._temp_directory or target_directory)
            if not os_path.isdir(temp_directory):
                self._create_directory(temp_directory)

            # write data to a temporary file and make sure
            # it has been persistently stored to disk

            h, self._temp_filename = mkstemp(dir = temp_directory,
                                             suffix = self._temp_suffix)

            pmnc.log.info("writing {0:d} byte(s) to a temporary file {1:s}".\
                          format(len(data_b), self._temp_filename))
            try:
                with fdopen(h, "wb") as f:
                    f.write(data_b)
                    f.flush()
                    fsync(h)
            except:
                pmnc.log.warning("writing {0:d} byte(s) to a temporary file {1:s} failed: " \
                                 "{2:s}".format(len(data_b), self._temp_filename, exc_string()))
                raise

            # explicitly set permissions on the temporary file

            chmod(self._temp_filename, self._perm_mask)

            # this is a pessimistic safety check, if the target file already exists,
            # we are most likely unable to commit the transaction anyway, therefore
            # fail early to cause rollback

            if os_path.exists(self._target_filename) and not self._overwrite:
                raise Exception("file {0:s} already exists".format(self._target_filename))

        except:
            ResourceError.rethrow(recoverable = True) # no irreversible changes
Example #13
0
 def _sync_request(self,
                   rq: MongoDB_Request,
                   check: optional(callable) = None) -> MongoDB_Response:
     pmnc.log.info(">> {0:s}".format(rq))
     try:
         rs = self._connection.sync_request(rq,
                                            Timeout(pmnc.request.remain))
         if rs.cursor_not_found:
             raise MongoDB_Error("cursor not found")
         if check: check(rs)
     except MongoDB_Error as e:
         pmnc.log.warning("<< {0:s} !! {1:s}".format(rq, exc_string()))
         ResourceError.rethrow(code=e.code,
                               description=str(e),
                               terminal=e.code is not None)
     except Exception as e:
         pmnc.log.warning("<< {0:s} !! {1:s}".format(rq, exc_string()))
         ResourceError.rethrow(description=str(e))
     else:
         pmnc.log.info("<< OK, {0:s}".format(rs))
         return rs
Example #14
0
    def __call__(self, *args):

        try:
            method, self._attrs = ".".join(self._attrs), []
            request = dumps(args,
                            methodname=method,
                            encoding=self._request_encoding,
                            allow_none=self._allow_none)
            request_description = "XMLRPC request {0:s} to {1:s}".\
                                  format(method, self._http_resource.server_info)
        except:
            ResourceError.rethrow(recoverable=True)

        pmnc.log.info("sending {0:s}".format(request_description))
        try:

            status_code, headers, content = \
                self._http_resource.post(self._server_uri, request.encode(self._request_encoding),
                                         { "Content-Type": "text/xml" })

            if status_code != 200:
                raise Exception(
                    "HTTP request returned code {0:d}".format(status_code))

            result = loads(content)[0][0]

        except Fault as e:
            pmnc.log.warning("{0:s} returned fault {1:d}: {2:s}".\
                             format(request_description, e.faultCode, e.faultString))
            ResourceError.rethrow(code=e.faultCode,
                                  description=e.faultString,
                                  terminal=False)
        except:
            pmnc.log.warning("{0:s} failed: {1:s}".\
                             format(request_description, exc_string()))
            raise
        else:
            pmnc.log.info("XMLRPC request returned successfully")

        return result
Example #15
0
 def _async_request(self, rq: MongoDB_Request):
     pmnc.log.info(">> {0:s}".format(rq))
     try:
         self._connection.async_request(rq, Timeout(pmnc.request.remain))
         gle_rq = OP_QUERY("{0:s}.$cmd".format(self._database),
                           {"getlasterror": 1})
         gle_rs = self._connection.sync_request(
             gle_rq, Timeout(pmnc.request.remain))
         MongoDB_Connection._command_check(gle_rs)
         d = gle_rs.documents[0]
         err = d.get("err")
         if err: raise MongoDB_Error(err, d.get("code"))
     except MongoDB_Error as e:
         pmnc.log.warning("<< {0:s} !! {1:s}".format(rq, exc_string()))
         ResourceError.rethrow(code=e.code,
                               description=str(e),
                               terminal=e.code is not None)
     except Exception as e:
         pmnc.log.warning("<< {0:s} !! {1:s}".format(rq, exc_string()))
         ResourceError.rethrow(description=str(e))
     else:
         pmnc.log.info("<< OK")
Example #16
0
def execute_reverse(target_cage: valid_cage_name, module: valid_module_name,
                    method: valid_method_name, args: tuple, kwargs: dict):

    # wrap up an RPC call identical to how it's done in protocol_rpc.py

    request_dict = pmnc.request.to_dict()

    # remove request parameters that must not cross the RPC border

    request_dict["parameters"].pop("retry", None)

    # wrap all the call parameters in a plain dict

    request = dict(source_cage=__cage__,
                   target_cage=target_cage,
                   module=module,
                   method=method,
                   args=args,
                   kwargs=kwargs,
                   request=request_dict)

    request_description = "reverse RPC request {0:s}.{1:s} to {2:s}".\
                          format(module, method, target_cage)

    # create a one-time response queue just for this request

    rs_queue = InterlockedQueue()
    request_id = pmnc.request.unique_id

    with _rs_queues_lock:
        _rs_queues[request_id] = rs_queue  # register the call as being active
    try:

        pmnc.log.info("sending {0:s}".format(request_description))
        try:

            # enqueue the call and wait for response

            rq_queue = _get_rq_queue(target_cage)
            rq_queue.push((request_id, request))

            response = pmnc.request.pop(rs_queue)
            if response is None:
                raise Exception("request deadline waiting for response")

            try:
                result = response["result"]
            except KeyError:
                raise RPCError(description=response["exception"],
                               terminal=False)

        except RPCError as e:
            pmnc.log.warning("{0:s} returned error: {1:s}".\
                             format(request_description, e.description))
            raise
        except:
            pmnc.log.warning("{0:s} failed: {1:s}".\
                             format(request_description, exc_string()))
            ResourceError.rethrow(recoverable=False)
        else:
            pmnc.log.info("reverse RPC request returned successfully")
            return result

    finally:
        with _rs_queues_lock:
            del _rs_queues[request_id]  # unregister the call
Example #17
0
    def _execute_sql(self, sql, params):

        try:
            sql, params = self._convert_to_named(sql, params)
            param_list = ", ".join(map(lambda n_v: "{0:s} = {1:s}".\
                                       format(n_v[0], isinstance(n_v[1], str) and
                                                      "'{0:s}'".format(n_v[1]) or str(n_v[1])),
                                       params.items()))
        except:
            ResourceError.rethrow(recoverable = True, terminal = False)

        pmnc.log.info(">> {0:s}".format(sql))
        if param_list:
            if pmnc.log.debug:
                pmnc.log.debug("-- {0:s} -- ({1:s})".format(sql, param_list))

        try:

            cursor = self._connection.cursor()
            try:

                # avoid using floats with numbers

                cursor.numbersAsStrings = True

                # avoid truncation of timestamps and intervals

                param_sizes = {}
                for n, v in params.items():
                    if isinstance(v, datetime):
                        param_sizes[n] = TIMESTAMP
                    elif isinstance(v, timedelta):
                        param_sizes[n] = INTERVAL
                if param_sizes:
                    cursor.setinputsizes(**param_sizes)

                # execute the query, making stored procedure a special case

                execute = self._execute_parser.match(sql)
                if execute:
                    proc_name = execute.group(1)
                    result = self._connection.cursor()
                    try:
                        params.update(result = result) # providing out sys_refcursor parameter result
                        cursor.callproc(proc_name, keywordParameters = params)
                    finally:
                        try:
                            cursor.close()
                        finally:
                            cursor = result
                else:
                    cursor.execute(sql, **params)

                # extract the result

                if cursor.description is not None:
                    description = tuple(dict(name = t[0], type_name = t[1].__name__) for t in cursor.description)
                    records = [ { field["name"]: self.cx_TYPE(field["type_name"], value)
                                  for field, value in zip(description, record) } for record in cursor ]
                else:
                    records = [] # not a SELECT query

                records_affected = cursor.rowcount

            finally:
                cursor.close()

            if records_affected > 0:
                pmnc.log.info("<< OK, {0:d} record(s)".format(records_affected))
            else:
                pmnc.log.info("<< OK")

        except Oracle_Error as e:
            e = e.args[0]
            if isinstance(e, _Oracle_Error):
                code, message = e.code, e.message
            else:
                code, message = -1, "cx_Oracle error: {0:s}".format(str(e))
            pmnc.log.warning("<< {0:s}{1:s} !! Oracle_Error(\"{2:d}: {3:s}\") in {4:s}".\
                             format(sql, " -- ({0:s})".format(param_list)
                                    if param_list else "", code, message, trace_string()))
            SQLResourceError.rethrow(
                    code = code, description = message, recoverable = True) # note that there is no state
        except:
            pmnc.log.warning("<< {0:s}{1:s} !! {2:s}".\
                             format(sql, " -- ({0:s})".format(param_list)
                                    if param_list else "", exc_string()))
            ResourceError.rethrow(recoverable = True)
        else:
            return records
 def _py_to_sql_Decimal(self, v):
     return "adDecimal", self._decimal_bytes, \
            self._ensure_decimal_in_range(v,
                 lambda description: ResourceError(description = description,
                                                   recoverable = True, terminal = False))
 def _adodb_to_py_adDecimal(self, v):
     if isinstance(v, str): v = v.replace(",", ".")
     return self._ensure_decimal_in_range(Decimal(v),
                 lambda description: ResourceError(description = description,
                                                   recoverable = True, terminal = True))
Example #20
0
def execute_reverse(target_cage: valid_cage_name, module: valid_module_name,
                    method: valid_method_name, args: tuple, kwargs: dict):

    # wrap up an RPC call identical to how it's done in protocol_rpc.py

    request_dict = pmnc.request.to_dict()

    # remove request parameters that must not cross the RPC border

    request_dict["parameters"].pop("retry", None)

    # wrap all the call parameters in a plain dict

    request = dict(source_cage = __cage__,
                   target_cage = target_cage,
                   module = module, method = method,
                   args = args, kwargs = kwargs,
                   request = request_dict)

    request_description = "reverse RPC request {0:s}.{1:s} to {2:s}". \
                          format(module, method, target_cage)

    # create a one-time response queue just for this request

    rs_queue = InterlockedQueue()
    request_id = pmnc.request.unique_id

    with _rs_queues_lock:
        _rs_queues[request_id] = rs_queue # register the call as being active
    try:

        pmnc.log.info("sending {0:s}".format(request_description))
        try:

            # enqueue the call and wait for response

            rq_queue = _get_rq_queue(target_cage)
            rq_queue.push((request_id, request))

            response = pmnc.request.pop(rs_queue)
            if response is None:
                raise Exception("request deadline waiting for response")

            try:
                result = response["result"]
            except KeyError:
                raise RPCError(description = response["exception"], terminal = False)

        except RPCError as e:
            pmnc.log.warning("{0:s} returned error: {1:s}".\
                             format(request_description, e.description))
            raise
        except:
            pmnc.log.warning("{0:s} failed: {1:s}".\
                             format(request_description, exc_string()))
            ResourceError.rethrow(recoverable = False)
        else:
            pmnc.log.info("reverse RPC request returned successfully")
            return result

    finally:
        with _rs_queues_lock:
            del _rs_queues[request_id] # unregister the call
Example #21
0
    def submit_sm(self, *, dest_addr_ton: byte, dest_addr_npi: byte, destination_addr: str,
                  short_message: either(str, bytes), **kwargs) -> optional(str):

        try:

            destination_addr_b = destination_addr.encode("ascii", "replace")

            kwargs.setdefault("service_type", b"")
            kwargs.setdefault("source_addr_ton", self._source_addr_ton)
            kwargs.setdefault("source_addr_npi", self._source_addr_npi)
            kwargs.setdefault("source_addr", self._source_addr.encode("ascii", "replace"))
            kwargs.setdefault("esm_class", 0x00)
            kwargs.setdefault("protocol_id", 0x00)
            kwargs.setdefault("priority_flag", 0x00)
            kwargs.setdefault("schedule_delivery_time", b"")
            kwargs.setdefault("validity_period", b"")
            kwargs.setdefault("registered_delivery", 0x00)
            kwargs.setdefault("replace_if_present_flag", 0x00)
            kwargs.setdefault("sm_default_msg_id", 0x00)

            # if message text is provided as str, encode it to bytes using default
            # GSM7/UCS2 encoding, otherwise require the encoding to be specified

            if isinstance(short_message, str):
                if "data_coding" in kwargs:
                    raise Exception("data_coding is specified, provide short_message of type bytes")
                data_coding, short_message_b = self._encode_message(short_message)
                kwargs["data_coding"] = data_coding
            elif "data_coding" in kwargs:
                short_message_b = short_message
            else:
                raise Exception("data_coding is not specified, provide short_message of type str")

            if len(short_message_b) > self._frag_size and self._frag_method: # the message needs to be fragmented

                bits_per_char = Resource._encoding_bits.get(kwargs["data_coding"], 8)

                if bits_per_char < 8 and not self._pack_7bit:
                    bits_per_char = 8 # 7-bit characters are treated by some providers as octets, not septets

                msg_id = self._frag_count.next() # with 16 bits having a counter is better than picking at random

                if self._frag_method == "udh": # UDH is prepended to each fragment

                    udh = kwargs.pop("udh", []) # sender could have provided his own UDH

                    frags = self._frag_message(short_message_b, bits_per_char, self._frag_size, 7) # 7 bytes are reserved to UDH
                    reqs = [ SubmitSmPDU.create(dest_addr_ton = dest_addr_ton,
                                                dest_addr_npi = dest_addr_npi,
                                                destination_addr = destination_addr_b,
                                                short_message = short_message_b,
                                                udh = udh + [ (0x08, pack("BBBB", msg_id >> 8, msg_id & 0xff, len(frags), i + 1)) ],
                                                **kwargs)
                             for i, short_message_b in enumerate(frags) ]

                elif self._frag_method == "sar": # sar_... optional parameters are added to each fragment

                    kwargs.setdefault("sar_msg_ref_num", msg_id) # sender could have provided his own value

                    frags = self._frag_message(short_message_b, bits_per_char, self._frag_size)
                    reqs = [ SubmitSmPDU.create(dest_addr_ton = dest_addr_ton,
                                                dest_addr_npi = dest_addr_npi,
                                                destination_addr = destination_addr_b,
                                                short_message = short_message_b,
                                                sar_segment_seqnum = i + 1,
                                                sar_total_segments = len(frags),
                                                **kwargs)
                             for i, short_message_b in enumerate(frags) ]

            else: # no fragmentation required or possible

                reqs = [ SubmitSmPDU.create(dest_addr_ton = dest_addr_ton,
                                            dest_addr_npi = dest_addr_npi,
                                            destination_addr = destination_addr_b,
                                            short_message = short_message_b,
                                            **kwargs) ]

        except:
            ResourceError.rethrow(recoverable = True, terminal = False)

        try:

            pmnc.log.info("sending short message \"{0:s}\" for {1:s}".\
                          format(short_message, destination_addr))
            try:

                # send all the fragments

                message_id = None
                for req in reqs:
                    self._interface.send(req)

                # the responses are waited upon after all the requests have been sent

                if not self._asynchronous:
                    for req in reqs:
                        resp = _wait_response(req, pmnc.request.remain)
                        resp_id = resp.message_id.value.decode("ascii", "replace")
                        if resp_id and resp_id != message_id:
                            message_id = resp_id # the last different message_id is returned

            except:
                pmnc.log.warning("sending short message \"{0:s}\" for {1:s} failed: {2:s}".\
                                 format(short_message, destination_addr, exc_string()))
                raise
            else:
                pmnc.log.info("short message has been sent{0:s}".\
                              format(" as {0:s}".format(message_id) if message_id else ""))

        except:
            ResourceError.rethrow(recoverable = False, terminal = False)

        return message_id # possibly None, if sending asynchronously
Example #22
0
    def wu_participate(self, transaction_start, participant_index,
                       resource_name, attrs, args, kwargs, res_args, res_kwargs):

        # see whether the request by which this transaction was created
        # has expired in the meantime, and if it has, simply bail out
        # because the transaction should have long been perished

        # no attempt to execute the request is taken and no result
        # is delivered, simply because the transaction is assumed
        # to already be aborted, nowhere to report the result

        if pmnc.request.expired:
            pmnc.log.error("execution of resource {0:s} in transaction "
                           "{1:s} was late".format(resource_name, self))
            return

        try:

            pmnc.log.debug("resource {0:s} joins transaction {1:s}".\
                           format(resource_name, self))

            resource_instance = None        # no instance has been allocated yet
            resource_in_transaction = False # no transaction has been started on the instance
            resource_failed = True          # (preventive) request execution has been a failure

            while True: # breaks when the result is obtained, either value or exception

                # any failure prior to actual resource allocation results
                # in a recoverable ResourceError, pointlessly terminal

                try:

                    # the pending interval is measured from the beginning of the
                    # transaction, not from the beginning of the request

                    pending_ms = int((time() - transaction_start) * 1000)
                    pmnc.performance.sample("resource.{0:s}.pending_time".\
                                            format(resource_name), pending_ms)

                    # allocate a resource instance from a specific resource pool

                    resource_pool = pmnc.shared_pools.get_resource_pool(resource_name)
                    resource_instance = resource_pool.allocate()

                except: # tested
                    result = ResourceError.snap_exception(
                                    participant_index = participant_index,
                                    recoverable = True, terminal = True) # but not really terminal,
                    break # while True                                   # no instance to terminate

                # some resource instance has been allocated, beginning a transaction,
                # a failure would result in a ResourceError, recoverable yet terminal
                # unless explicitly specified otherwise

                try:

                    # see if a transaction should be started in as much time as the request has left

                    if pmnc.request.remain < resource_instance.min_time:
                        raise ResourceError(description = "transaction {0:s} is declined by resource instance " # tested
                                                          "{1:s}".format(self, resource_instance.name),
                                            recoverable = True, terminal = False) # the instance stays alive

                    pmnc.log.debug("resource instance {0:s} is used in transaction {1:s}, {2:s}".\
                                   format(resource_instance.name, self, self._resource_ttl(resource_instance)))

                    # begin a new transaction, this is presumably reversible operation

                    resource_instance.begin_transaction(self._xid,
                                                        source_module_name = self._source_module_name,
                                                        transaction_options = self._options,
                                                        resource_args = res_args,
                                                        resource_kwargs = res_kwargs)

                except ResourceError as e:
                    result = self._apply_error(participant_index, resource_instance, e)
                    break # while True
                except: # tested
                    result = ResourceError.snap_exception(
                                    participant_index = participant_index,
                                    recoverable = True, terminal = True)
                    resource_instance.expire()
                    break # while True
                else:
                    resource_in_transaction = True

                # resource instance is now in transaction, executing the request,
                # a failure would result in a ResourceError, unrecoverable and
                # terminal unless explicitly specified otherwise

                try:

                    # replay attribute accesses to obtain the actual target method

                    target_method = resource_instance
                    for attr in attrs:
                        target_method = getattr(target_method, attr)

                    # execute the request, registering the execution time

                    with pmnc.performance.timing("resource.{0:s}.processing_time".format(resource_name)):
                        result = target_method(*args, **kwargs)

                except ResourceError as e:
                    result = self._apply_error(participant_index, resource_instance, e)
                    break # while True
                except Exception: # tested
                    result = ResourceError.snap_exception(
                                    participant_index = participant_index,
                                    recoverable = False, terminal = True)
                    resource_instance.expire()
                    break # while True
                else:
                    resource_instance.reset_idle_timeout()
                    resource_failed = False
                    break # while True

            # we got an intermediate result, possibly an exception

            try:

                self._results.push((participant_index, result)) # deliver the result to the pending transaction

                # register the actual result of this participant

                pmnc.performance.event("resource.{0:s}.transaction_rate.{1:s}".\
                                       format(resource_name, resource_failed and "failure" or "success"))

                if not resource_in_transaction: # as we couldn't begin a transaction,
                    return "failure"            # we are not interested in the decision

                pmnc.log.debug("resource instance {0:s} is waiting for decision in "
                               "transaction {1:s}".format(resource_instance.name, self))

                # figure out whether the resource has to commit or rollback

                commit_transaction = False

                if pmnc.request.wait(self._decision): # wait for transaction's decision
                    if self._commit.is_set():
                        if not resource_failed:
                            commit_transaction = True
                            pmnc.log.debug("resource instance {0:s} decided to commit in transaction "
                                           "{1:s}".format(resource_instance.name, self))
                        else:
                            pmnc.log.warning("resource instance {0:s} had to rollback despite decision to commit "
                                             "in transaction {1:s}".format(resource_instance.name, self))
                    else:
                        pmnc.log.debug("resource instance {0:s} decided to rollback in transaction "
                                       "{1:s}".format(resource_instance.name, self))
                else:
                    pmnc.log.warning("resource instance {0:s} had to abandon waiting for decision and "
                                     "rollback in transaction {1:s}".format(resource_instance.name, self))

                # complete the transaction and return the final outcome

                if commit_transaction:
                    try:
                        resource_instance.commit()
                    except:
                        pmnc.log.error("resource instance {0:s} failed to commit in transaction {1:s}: "
                                       "{2:s}".format(resource_instance.name, self, exc_string())) # this is a severe problem
                        resource_instance.expire()
                        return "failure"
                    else:
                        pmnc.log.debug("resource instance {0:s} committed in transaction "
                                       "{1:s}".format(resource_instance.name, self))
                        return "commit"
                else:
                    try:
                        resource_instance.rollback()
                    except:
                        pmnc.log.warning("resource instance {0:s} failed to rollback in transaction {1:s}: "
                                         "{2:s}".format(resource_instance.name, self, exc_string())) # this is not a big deal
                        resource_instance.expire()
                        return "failure"
                    else:
                        pmnc.log.debug("resource instance {0:s} rolled back in transaction "
                                       "{1:s}".format(resource_instance.name, self))
                        return "rollback"

            finally:
                if resource_instance:
                    pmnc.log.debug("resource instance {0:s} is being released, {1:s}".\
                                   format(resource_instance.name, self._resource_ttl(resource_instance)))
                    resource_pool.release(resource_instance)

        except:
            pmnc.log.error(exc_string()) # this should not normally happen, but do
            raise                        # not allow such exception to be silenced
Example #23
0
 def set(self, key: str, value):
     try:
         self._txn = pmnc.state.explicit_transaction(self.source_module_name, self._txn, self._set, key, value)[0]
     except:
         ResourceError.rethrow(recoverable=True, terminal=False)
Example #24
0
 def delete(self, key: str):
     try:
         self._txn = pmnc.state.explicit_transaction(self.source_module_name, self._txn, self._delete, key)[0]
     except:
         ResourceError.rethrow(recoverable=True, terminal=False)
    def _execute_sql(self, sql, params):

        try:
            sql, params = self._convert_to_qmarks(sql, params)
            param_list = ", ".join(map(lambda t_s_v: "{0:s}({1:s})".\
                                       format(t_s_v[0], isinstance(t_s_v[2], str)
                                                        and "'{0:s}'".format(t_s_v[2])
                                                        or str(t_s_v[2])), params))
        except:
            ResourceError.rethrow(recoverable = True, terminal = False)

        pmnc.log.info(">> {0:s}".format(sql))
        if param_list:
            if pmnc.log.debug:
                pmnc.log.debug("-- {0:s} -- ({1:s})".format(sql, param_list))

        records = []
        try:

            command = com_client.Dispatch("ADODB.Command")
            command.CommandText = sql
            command.CommandType = 1 # adCmdText

            for i, (param_type, param_size, param_value) in enumerate(params):
                param = command.CreateParameter(None, ADODataTypes[param_type], 1, # adParamInput
                                                param_size, param_value)
                if param_type in ("adDecimal", "adNumeric"):
                    param.Precision = self.precision
                    param.NumericScale = self.scale
                command.Parameters.Append(param)

            command.ActiveConnection = self._connection
            command.Prepared = True

            recordset = command.Execute()[0]

            if recordset.State == 1: # adStateOpen
                try:
                    while not recordset.EOF:
                        records.append({ field.Name: TypeValueWrapper((field.Type, field.Value))
                                         for field in recordset.Fields })
                        recordset.MoveNext()
                finally:
                    recordset.Close()
                pmnc.log.info("<< OK, {0:d} record(s)".format(len(records)))
            else:
                pmnc.log.info("<< OK")

        except com_error:
            tb, code, state, description = self._extract_adodb_error()
            state_brace = " [{0:s}]".format(state) if state is not None else ""
            pmnc.log.warning("<< {0:s}{1:s} !! ADODB_Error(\"{2:d}:{3:s} {4:s}\") in {5:s}".\
                             format(sql, " -- ({0:s})".format(param_list) if param_list else "",
                                    code, state_brace, description, trace_string()))
            SQLResourceError.rethrow(
                    code = code, state = state, description = description,
                    recoverable = True, terminal = state[:2] not in self._safe_states)
        except:
            pmnc.log.warning("<< {0:s}{1:s} !! {2:s}".\
                             format(sql, " -- ({0:s})".format(param_list)
                                    if param_list else "", exc_string()))
            ResourceError.rethrow(recoverable = True)
        else:
            return records