删除包含Sqlite的目录时,64位Windows 7递归目录删除失败
我有一个测试用例(更大应用程序的剥离版本),当试图删除目录或文件时,它会在Windows7机器上偶尔失败。它使用的是本机Windows API。 测试执行以下步骤--删除包含Sqlite的目录时,64位Windows 7递归目录删除失败,sqlite,fileapi,Sqlite,Fileapi,我有一个测试用例(更大应用程序的剥离版本),当试图删除目录或文件时,它会在Windows7机器上偶尔失败。它使用的是本机Windows API。 测试执行以下步骤-- 创建目录 在步骤#1创建的目录中创建sqlite3 db 在数据库中创建一个表 关闭数据库 如果存在任何数据库日志文件,请将其删除 删除数据库文件 删除目录 若您跳过步骤#1,那个么测试将正常运行。 若您在步骤4和步骤5之间添加延迟,那个么测试将正常运行 #include <windows.h> #include &l
#include <windows.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <direct.h>
#include <sqlite3.h>
#include <io.h>
using namespace std;
bool sleep_for_sometime = false;
bool create_table = false;
bool runTest()
{
char cwdpath[1024] = {'\0'};
if (_getcwd(cwdpath, 1023) == NULL) return false;
string testpath(cwdpath);
testpath += "/test_dir";
_mkdir(testpath.c_str());
string dbpath = testpath + "/test.db";
sqlite3 *db = NULL;
if (sqlite3_open(dbpath.c_str(), &db) != SQLITE_OK) return false;
// Create table.
if (create_table) {
string sql = "CREATE TABLE COMPANY(" \
"ID INT PRIMARY KEY NOT NULL," \
"NAME TEXT NOT NULL," \
"AGE INT NOT NULL)";
char *zErrMsg = 0;
if (sqlite3_exec(db, sql.c_str(), NULL, 0, &zErrMsg) != SQLITE_OK) {
sqlite3_close(db);
cerr << "Could not create table: " << zErrMsg << endl;
return false;
}
}
sqlite3_close(db);
if (sleep_for_sometime) {
Sleep(100);
}
string journal_file = dbpath + "-journal";
string journal_error = journal_file + " failed";
if (_access(journal_file.c_str(), 06) == 0) {
if (_unlink(journal_file.c_str()) != 0) {
perror(journal_error.c_str());
return false;
}
cout << "journal file --" << journal_file << endl;
}
string db_error = dbpath + " failed";
if (_unlink(dbpath.c_str()) != 0) {
perror(db_error.c_str());
return false;
}
string dir_error = testpath + " failed";
if (_rmdir(testpath.c_str()) != 0) {
perror(dir_error.c_str());
return false;
}
return true;
}
int main(int argc, char **argv)
{
cout << "Usage: ./projtest 1 1" << endl;
cout << "------If you pass two parameter, then always create table and sleep for some time." << endl;
cout << "Usage: ./projtest 1" << endl;
cout << "------If you pass one parameter, then always create table, but don't sleep." << endl;
cout << "Usage: ./projtest" << endl;
cout << "------If you don't pass any parameter, then don't create table and don't sleep." << endl;
if (argc == 3) {
sleep_for_sometime = true;
create_table = true;
} else if (argc == 2) {
create_table = true;
sleep_for_sometime = false;
} else {
create_table = false;
sleep_for_sometime = false;
}
for (int i = 0; i < 500 ; i++) {
if (! runTest()) {
cerr << "Err in runTest trial --" << i+1 << endl;
return 1;
}
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
bool sleep_for_time=假;
bool create_table=false;
bool运行测试()
{
char cwdpath[1024]={'\0'};
if(_getcwd(cwdpath,1023)==NULL)返回false;
字符串测试路径(cwdpath);
testpath+=“/test_dir”;
_mkdir(testpath.c_str());
字符串dbpath=testpath+“/test.db”;
sqlite3*db=NULL;
if(sqlite3_open(dbpath.c_str(),&db)!=SQLITE_OK)返回false;
//创建表。
if(创建_表){
string sql=“创建表公司(”\
ID INT主键不为空\
名称文本不为空\
“年龄整数不为空)”;
char*zErrMsg=0;
if(sqlite3_exec(db,sql.c_str(),NULL,0和zErrMsg)!=SQLITE_OK){
sqlite3_关闭(db);
cerr可能是活动的filelock sqllite在第4步和第5步之间强加了未及时清除的权限。
记住,与硬盘相比,内存中的代码以闪存速度运行。
硬盘上的SQLLite进程指令可能仍在忙着将数据写入文件,在日志中输入条目,然后释放文件处理程序,而您的代码已经在忙着将其删除
因此,在SQLLite完成并处理的同时,硬盘仍在记录数据和清除锁的工作列表
也许您可以实现一个while循环,检查文件是否被锁定,然后耐心地等待释放锁,或者标记文件以备将来删除,并每50毫秒重新检查一次
编辑
补充说明
问题是这里有两个问题。硬盘速度和CPU速度。在正常程序代码中,当您将写入指令推送到硬盘时,它会被放入驱动程序/驱动器本身的队列中进行写入,并且驱动程序/硬盘会逐个关闭que(ish)
程序将收到一条消息,表明操作已完成,以便继续执行。为什么程序必须等待一两毫秒才能继续正确运行?因为硬盘驱动器速度慢,并且有自己的读写优先级。它可以这样做,但不完全是现在导致它正在读一个文件或者什么的
因此,虽然文件可以自由编辑的写入操作仍在要写入的队列中,但它已经发送了一个删除请求,但该文件尚未标记为可写,因为该操作仍在队列中。错误来自于此。此代码是单线程的,那么为什么要关闭sqlite3_()在完成所有操作之前返回。其次,。表示同步已满(2),SQLite数据库引擎将使用VFS的xSync方法,以确保在继续之前将所有内容安全地写入磁盘表面。因此,在所有内容都写入磁盘之前,控件不应返回。我补充了一点说明。可能是文件本身已完全写入,但原理相同不要应用于已应用的文件锁。我在以下情况中也观察到类似问题。DeleteFile('xyz');fopen('xyz','w'))
。此处文件打开失败,权限被拒绝。它并不总是可复制的,但很多时候是可复制的。问题与此处基本相同。最好将硬盘驱动器指令和程序视为单独的进程。当程序向驱动器进程发出删除指令时,驱动器进程将添加到queue,完成作业,然后锁定文件,将文件标记为已删除的FS注册表,然后清除锁定。如果在应用删除锁定后过早尝试打开文件,则权限将被拒绝。这是一件好事。您应该无法写入标记为删除的文件。请使用时间戳名称来解决此问题