2014-11-03 59 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