2014-11-03 85 views
0

我正在使用R和一些外部软件执行数千次计算。 为了跟踪这一点,我在SQLite3数据库的R中构建了一个管道。 为了完成任务,我将其设置为允许计算集群上的多个节点运行R脚本。 当然,我们需要保持原子化,所以我正在积极开始交易。SQLite事务失败

为了避免崩溃的脚本试图让数据库锁的时候,我已经试图开始一个事务,如果失败,等待,然后将下面的代码重试:

dbBeginTransaction <- function(dbconn, state='DEFERRED', timeout=5, retries=10) { 
    state <- toupper(state) 
    if (!state %in% c('DEFERRED','IMMEDIATE','EXCLUSIVE')) stop('Attempt at illegal transaction.') 
    res <- NULL 
    exit <- FALSE 
    for (i in 1:retries) { 
    try(
     res <- dbSendQuery(dbconn, paste('BEGIN',state,'TRANSACTION;')) 
     , silent=TRUE 
    ) 
    # res is null if above query fails. 
    err <- dbGetException(dbconn) 
    if (err$errorNum == 0) { ## OK 
     #return(TRUE) 
     exit <- TRUE 
     break 
    } else if (err$errorNum == 5) { ## Database locked. 
     if (i == retries+1) { 
     cat('Database still locked after',i,'attempts.\n',file=stderr()) 
     #return(FALSE) 
     exit <- FALSE 
     break 
     } else { 
     Sys.sleep(timeout) 
     } 
    } else { 
     ## errorNum == 1 ## Already within transaction. 
     cat(err$errorMsg, '\n', file = stderr()) 
     #return(FALSE) 
     exit <- FALSE 
     break 
    } 
    } 
    invisible(exit) 
} 


    ## Usage: 
    insert_results <- function(results) { 
    ## Some preparing of results 
    if (dbBeginTransaction(conn, 'EXCLUSIVE') == FALSE) return(FALSE) 
    dbSendPreparedQuery(conn, 'INSERT INTO results (...) VALUES (...);', results) 
    dbCommit(conn) 
    } 

    ## After a computation: 
    results <- magic() 
    if (!insert_results(results)) stop('Could not save results') 

当调试,它的工作原理应该如此。但每一个现在,然后我得到这个奇怪的错误,并且脚本崩溃:

Error in sqliteSendQuery(conn, statement, bind.data) : 
    rsqlite_query_send: could not execute: database is locked 
Calls: dbSendPreparedQuery ... dbSendPreparedQuery -> .local -> sqliteSendQuery -> .Call 
Execution halted 

我无法捉摸发生了什么,我还没有重现错误。 错误很明显,但我会认为我的例程阻止了它。

有关为什么会发生这种情况的任何想法?

我在linux下运行R,由所见:

> sessionInfo() 
R version 3.1.2 (2014-10-31) 
Platform: x86_64-unknown-linux-gnu (64-bit) 

locale: 
[1] LC_CTYPE=en_US  LC_NUMERIC=C   LC_TIME=en_US 
[4] LC_COLLATE=en_US  LC_MONETARY=en_US LC_MESSAGES=en_US 
[7] LC_PAPER=en_US  LC_NAME=C   LC_ADDRESS=C 
[10] LC_TELEPHONE=C  LC_MEASUREMENT=en_US LC_IDENTIFICATION=C 

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base 

other attached packages: 
[1] RSQLite_1.0.0 DBI_0.3.1 
+0

为什么你不只是使用[PRAGMA busy_timeout]前添加dbBegin(CON) (http://www.sqlite.org/pragma.html#pragma_busy_timeout)? – 2014-11-04 08:09:32

+0

因为我显然没有彻底阅读文档。 :)据我所知,这绕过了我的dbBeginTransaction例程? – MrGumble 2014-11-04 11:21:03

+0

更新:使用PRAGMA解决了这个问题,我将代码转储功能投入使用。 – MrGumble 2015-01-15 14:24:56

回答

-2

今天今天在办公室遇到了这个问题。这是我的同事的建议:可以通过确保每次执行数据库连接并对dbCommit(con)进行某种数据库更改来解决此问题。新的代码应该是这样的:

dbBeginTransaction <- function(dbconn, state='DEFERRED', timeout=5, retries=10) { 
    state <- toupper(state) 
    if (!state %in% c('DEFERRED','IMMEDIATE','EXCLUSIVE')) stop('Attempt at illegal transaction.') 
    res <- NULL 
    exit <- FALSE 
    for (i in 1:retries) { 
    try(
     dbBegin(dbconn) 
     res <- dbSendQuery(dbconn, paste('BEGIN',state,'TRANSACTION;')) 
     , silent=TRUE 
    ) 
    # res is null if above query fails. 
    err <- dbGetException(dbconn) 
    if (err$errorNum == 0) { ## OK 
     #return(TRUE) 
     exit <- TRUE 
     break 
    } else if (err$errorNum == 5) { ## Database locked. 
     if (i == retries+1) { 
     cat('Database still locked after',i,'attempts.\n',file=stderr()) 
     #return(FALSE) 
     exit <- FALSE 
     break 
     } else { 
     Sys.sleep(timeout) 
     } 
    } else { 
     ## errorNum == 1 ## Already within transaction. 
     cat(err$errorMsg, '\n', file = stderr()) 
     #return(FALSE) 
     exit <- FALSE 
     break 
    } 
    } 
    invisible(exit) 
} 


    ## Usage: 
    insert_results <- function(results) { 
    ## Some preparing of results 
    if (dbBeginTransaction(conn, 'EXCLUSIVE') == FALSE) return(FALSE) 
    dbSendPreparedQuery(conn, 'INSERT INTO results (...) VALUES (...);', results) 
    dbCommit(conn) 
    } 

    ## After a computation: 
    results <- magic() 
    if (!insert_results(results)) stop('Could not save results') 

我解决了只是你的开始的任何交易与数据库

dbBeginTransaction <- function(dbconn, state='DEFERRED', timeout=5, retries=10) { 
    state <- toupper(state) 
    if (!state %in% c('DEFERRED','IMMEDIATE','EXCLUSIVE')) stop('Attempt at illegal transaction.') 
    res <- NULL 
    exit <- FALSE 
    for (i in 1:retries) { 
    try(
     res <- dbSendQuery(dbconn, paste('BEGIN',state,'TRANSACTION;')) 
     , silent=TRUE 
     dbCommit(dbconn) 
    ) 
    # res is null if above query fails. 
    err <- dbGetException(dbconn) 
    if (err$errorNum == 0) { ## OK 
     #return(TRUE) 
     exit <- TRUE 
     break 
    } else if (err$errorNum == 5) { ## Database locked. 
     if (i == retries+1) { 
     cat('Database still locked after',i,'attempts.\n',file=stderr()) 
     #return(FALSE) 
     exit <- FALSE 
     break 
     } else { 
     Sys.sleep(timeout) 
     } 
    } else { 
     ## errorNum == 1 ## Already within transaction. 
     cat(err$errorMsg, '\n', file = stderr()) 
     #return(FALSE) 
     exit <- FALSE 
     break 
    } 
    } 
    invisible(exit) 
} 


    ## Usage: 
    insert_results <- function(results) { 
    ## Some preparing of results 
    if (dbBeginTransaction(conn, 'EXCLUSIVE') == FALSE) return(FALSE) 
    dbSendPreparedQuery(conn, 'INSERT INTO results (...) VALUES (...);', results) 
    dbCommit(conn) 
    } 

    ## After a computation: 
    results <- magic() 
    if (!insert_results(results)) stop('Could not save results') 
+0

'dbBegin''开始一个事务;以下'BEGIN TRANSACTION;'查询会导致错误,因为您无法开始两个事务(“错误:无法在事务中启动事务”)。以下'dbCommit''结束交易,让我们开始交易 - 无交易。 – MrGumble 2015-01-15 14:24:12

+0

用'dbBegin'替换'dbBeginTransaction' dbBeginTransaction旧的也许可以。 – princelySid 2015-01-16 10:29:44

+0

我没有使用旧的''dbBeginTransaction'';我只引用我自己的dbBeginTransction函数。 – MrGumble 2015-01-16 11:18:51