Ejemplo n.º 1
0
    def WriteData(self, data):
        # return if no data is received to write
        if (0 == len(data)):
            WriteBehindLog(
                "Warning: in connector received empty batch to write")
            return

        if not self.session:
            self.session = self.connection.Connect()

        # in case of exactly once get last id written
        shardId = None
        try:
            # Get the entry corresponding to shard id in exactly once table
            if ((self.exactlyOnceTableName is not None)
                    and isinstance(self.connection, RedisConnection)):
                shardId = 'shard-%s' % hashtag()
                res = self.session.execute_command('HGET',
                                                   self.exactlyOnceTableName,
                                                   shardId)
                if res is not None:
                    self.exactlyOnceLastId = str(res)
                else:
                    self.shouldCompareId = False

        except Exception as e:
            self.session = None  #Next time we will connect to database
            self.exactlyOnceLastId = None
            self.shouldCompareId = True if self.exactlyOnceTableName is not None else False
            msg = "Exception occur while getting shard id for exactly once. Exception : {}".format(
                e)
            WriteBehindLog(msg)
            raise Exception(msg) from None

        pipe = self.session.pipeline()
        try:
            # data is list of dictionaries
            # iterate over one by one and extract a dictionary and process it
            lastStreamId = None
            for d in data:
                d_val = d['value']  # get value of key 'value' from dictionary

                lastStreamId = d.pop(
                    'id', None)  # pop the stream id out of the record
                if self.shouldCompareId and CompareIds(self.exactlyOnceLastId,
                                                       lastStreamId) >= 0:
                    WriteBehindLog(
                        'Skip {} as it was already written to the backend'.
                        format(lastStreamId))
                    continue

                self.shouldCompareId = False

                # check operation permission, what gets replicated
                op = d_val.pop(OP_KEY,
                               None)  # pop the operation key out of the record
                if op not in self.supportedOperations:
                    msg = 'Got unknown operation'
                    raise Exception(msg) from None

                pk = d_val.pop(SIMPLE_HASH_BACKEND_PK)
                newKey = '{}:{}'.format(self.new_prefix, pk)

                if op != OPERATION_UPDATE_REPLICATE:
                    # pipeline key to delete
                    pipe.delete(newKey)
                else:
                    # pipeline key and field-value mapping to set
                    pipe.hset(newKey, mapping=d_val)

                # make entry for exactly once. In case of Redis cluster exception will be raised already
                if ((self.exactlyOnceTableName is not None)
                        and isinstance(self.connection, RedisConnection)):
                    l_exact_once_val = {shardId: lastStreamId}
                    pipe.hset(self.exactlyOnceTableName,
                              mapping=l_exact_once_val)

            #execute pipeline ommands
            pipe.execute()

        except Exception as e:
            self.session.close()
            self.session = None  # next time we will reconnect to the database
            self.exactlyOnceLastId = None
            self.shouldCompareId = True if self.exactlyOnceTableName is not None else False
            msg = "Got exception when writing to DB, Exception : {}".format(e)
            WriteBehindLog(msg)
            raise Exception(msg) from None
Ejemplo n.º 2
0
    def WriteData(self, data):
        if len(data) == 0:
            WriteBehindLog('Warning, got an empty batch')
            return
        query = None

        try:
            if not self.conn:
                from sqlalchemy.sql import text
                self.sqlText = text
                self.conn = self.connection.Connect()
                if self.exactlyOnceTableName is not None:
                    shardId = 'shard-%s' % hashtag()
                    result = self.conn.execute(
                        self.sqlText(
                            'select val from %s where id=:id' %
                            self.exactlyOnceTableName, {'id': shardId}))
                    res = result.first()
                    if res is not None:
                        self.exactlyOnceLastId = str(res['val'])
                    else:
                        self.shouldCompareId = False
        except Exception as e:
            self.conn = None  # next time we will reconnect to the database
            self.exactlyOnceLastId = None
            self.shouldCompareId = True if self.exactlyOnceTableName is not None else False
            msg = 'Failed connecting to SQL database, error="%s"' % str(e)
            WriteBehindLog(msg)
            raise Exception(msg) from None

        idsToAck = []

        trans = self.conn.begin()
        try:
            batch = []
            isAddBatch = True if data[0]['value'][
                OP_KEY] == OPERATION_UPDATE_REPLICATE else False
            query = self.addQuery if isAddBatch else self.delQuery
            lastStreamId = None
            for d in data:
                x = d['value']
                lastStreamId = d.pop(
                    'id', None
                )  # pop the stream id out of the record, we do not need it.
                if self.shouldCompareId and CompareIds(self.exactlyOnceLastId,
                                                       lastStreamId) >= 0:
                    WriteBehindLog(
                        'Skip %s as it was already writen to the backend' %
                        lastStreamId)
                    continue

                op = x.pop(OP_KEY, None)
                if op not in self.supportedOperations:
                    msg = 'Got unknown operation'
                    WriteBehindLog(msg)
                    raise Exception(msg) from None

                self.shouldCompareId = False
                if op != OPERATION_UPDATE_REPLICATE:  # we have only key name, it means that the key was deleted
                    if isAddBatch:
                        self.conn.execute(self.sqlText(query), batch)
                        batch = []
                        isAddBatch = False
                        query = self.delQuery
                    batch.append(x)
                else:
                    if not isAddBatch:
                        self.conn.execute(self.sqlText(query), batch)
                        batch = []
                        isAddBatch = True
                        query = self.addQuery
                    batch.append(x)
            if len(batch) > 0:
                self.conn.execute(self.sqlText(query), batch)
                if self.exactlyOnceTableName is not None:
                    self.conn.execute(self.sqlText(self.exactlyOnceQuery), {
                        'id': shardId,
                        'val': lastStreamId
                    })
            trans.commit()
        except Exception as e:
            try:
                trans.rollback()
            except Exception as e:
                WriteBehindLog('Failed rollback transaction')
            self.conn = None  # next time we will reconnect to the database
            self.exactlyOnceLastId = None
            self.shouldCompareId = True if self.exactlyOnceTableName is not None else False
            msg = 'Got exception when writing to DB, query="%s", error="%s".' % (
                (query if query else 'None'), str(e))
            WriteBehindLog(msg)
            raise Exception(msg) from None
Ejemplo n.º 3
0
    def WriteData(self, data):
        if len(data) == 0:
            WriteBehindLog('Warning, got an empty batch')
            return
        query = None

        try:
            if not self.session:
                self.session = self.connection.Connect()
                if self.exactlyOnceTableName is not None:
                    shardId = 'shard-%s' % hashtag()
                    result = self.session.execute('select val from %s where id=?' % self.exactlyOnceTableName, shardId)
                    res = result.first()
                    if res is not None:
                        self.exactlyOnceLastId = str(res['val'])
                    else:
                        self.shouldCompareId = False
        except Exception as e:
            self.session = None # next time we will reconnect to the database
            self.exactlyOnceLastId = None
            self.shouldCompareId = True if self.exactlyOnceTableName is not None else False
            msg = 'Failed connecting to Cassandra database, error="%s"' % str(e)
            WriteBehindLog(msg)
            raise Exception(msg) from None

        idsToAck = []

        try:
            from cassandra.cluster import BatchStatement
            batch = BatchStatement()
            isAddBatch = True if data[0]['value'][OP_KEY] == OPERATION_UPDATE_REPLICATE else False
            query = self.addQuery if isAddBatch else self.delQuery
            stmt = self.session.prepare(query)
            lastStreamId = None
            for d in data:
                x = d['value']
                lastStreamId = d.pop('id', None) # pop the stream id out of the record, we do not need it
                if self.shouldCompareId and CompareIds(self.exactlyOnceLastId, lastStreamId) >= 0:
                    WriteBehindLog('Skip %s as it was already writen to the backend' % lastStreamId)
                    continue

                op = x.pop(OP_KEY, None)
                if op not in self.supportedOperations:
                    msg = 'Got unknown operation'
                    WriteBehindLog(msg)
                    raise Exception(msg) from None

                self.shouldCompareId = False
                if op != OPERATION_UPDATE_REPLICATE:
                    if isAddBatch:
                        self.session.execute(batch)
                        batch = BatchStatement()
                        isAddBatch = False
                        query = self.delQuery
                else:
                    if not isAddBatch:
                        self.session.execute(batch)
                        batch = BatchStatement()
                        isAddBatch = True
                        query = self.addQuery
                stmt = self.session.prepare(query)
                batch.add(stmt.bind(x))
            if len(batch) > 0:
                self.session.execute(batch)
                if self.exactlyOnceTableName is not None:
                    stmt = self.session.prepare(self.exactlyOnceQuery)
                    self.session.execute(stmt, {'id':shardId, 'val':lastStreamId})
        except Exception as e:
            self.session = None # next time we will reconnect to the database
            self.exactlyOnceLastId = None
            self.shouldCompareId = True if self.exactlyOnceTableName is not None else False
            msg = 'Got exception when writing to DB, query="%s", error="%s".' % ((query if query else 'None'), str(e))
            WriteBehindLog(msg)
            raise Exception(msg) from None
Ejemplo n.º 4
0
 def GetStreamName(tableName):
     return '_%s-stream-%s-{%s}' % (tableName, uid, hashtag())