My C application uses SQLite 3.36. I am using WAL mode for my DB. But on inserting ~50K records with 7 columns, the WAL file grows up to 1.5 GB.
I have disabled auto checkpointing and doing manual checkpointing after all insertions.
I already went through many articles which blame checkpointing for the huge WAL size.
But,I guess checkpointing is not the issue here because other tables exist in the same DB where the record count is more than 50k but the WAL file size remains in MBs on insertion.
Before insertion, I am doing deletion but in that case, table contains hardly 2-3 records so WAL size is not impacted much (Confirmed by debugging the code).
During debugging I observed, the WAL size increasing very fast in for loop used for insertion (See below code). Loop completed within seconds.
Below is the code - (Added comments for a few local methods and macros )
Note- Code is running fine without any error and on checkpointing, I am getting desired records in the original DB. No other read operation going on this table during the execution of this routine.
Kindly, help me to know what I am doing wrong here which is causing the WAL file to grow up to 1.5GB.
Is insert after delete causing some issues?
int generatefMap(struct ixdb* xdb)
{
struct fmap* fmap;
uint64_t max_id, size;
int status = 0;
sqlite3_stmt* stmt = NULL;
int stmt_id = 0;
int retry_count = 0;
char* sql = NULL;
max_id = 0;
fmap = NULL;
status = ixdb_largest_id(xdb, &max_id);
if (status != 0 || max_id == 0) {
if (status == E_NOTFOUND) {
status = 0;
}
else {
return E_INVALID;
}
}
sql = "DELETE FROM fmap; ";
status = sqlite3_exec(xdb->dbh->db, sql, NULL, NULL, NULL);
if (status != 0) {
return status;
}
size = (max_id + 1) * sizeof(struct fnode);
fmap = (struct fmap*)mem_alloc(sizeof(struct fmap)); // #define mem_alloc(size) calloc(1, (size))
if (fmap == NULL) {
status = E_MEM;
return status;
}
fmap->hash = (struct fnode*)mem_alloc((size_t)size);// #define mem_alloc(size) calloc(1, (size))
if (fmap->hash == NULL) {
free(fmap);
status = E_MEM;
return status;
}
fmap->size = size;
fmap->max_id = max_id;
status = __fmap_gen(fmap, xdb); //Gives fmap by selecting/querying data from other table in same DB
if (status != 0) {
free(fmap->hash);
free(fmap);
return status;
}
//Insert into DB
stmt_id = XDB_FMAP_INSERT; //INSERT OR REPLACE INTO fmap(id,pid,xt,size,xtime,ytime,selected) values (:id,:pid,:xt,:size,:xtime,:ytime,:selected);
stmt = get_prepared_stmt(xdb, stmt_id); // This will get me prepared statement for above query
for (uint64_t i = 0; i < max_id + 1; ++i) {
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
sqlite3_bind_int64(stmt, 1, (uint64_t)(i + 1));
sqlite3_bind_int64(stmt, 2, fmap->hash[i].pid);
sqlite3_bind_int64(stmt, 3, fmap->hash[i].xtid);
sqlite3_bind_int64(stmt, 4, fmap->hash[i].size);
sqlite3_bind_int64(stmt, 5, fmap->hash[i].xtime);
sqlite3_bind_int64(stmt, 6, fmap->hash[i].ytime);
sqlite3_bind_int64(stmt, 7, fmap->hash[i].selected);
retry:
status = sqlite3_step(stmt);
if (status == SQLITE_BUSY || status == SQLITE_IOERR_BLOCKED) {
printf("sqlite_step returned: %d . Hence retrying ", status);
++retry_count;
if (retry_count <= ATTEMPTS) { //#define ATTEMPTS 5
sleep(SLEEP); //#define SLEEP 1
goto retry;
}
printf("Maximum number of retries(%d) exhausted|stmt=%s|err=%d", ATTEMPTS, sqlite3_expanded_sql(stmt), status);
goto err;
}
else if (status != SQLITE_DONE) {
printf("\nsqlite3_step() failed with error[%d].\n", status);
status = ERR_SQLITE;
goto err;
}
status = 0;
}
if (stmt) {
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
}
err:
if (fmap->hash) {
free(fmap->hash);
fmap->hash = NULL;
}
if (fmap) {
free(fmap);
fmap = NULL;
}
return status;
}
Related
I have made an sqlite3 database that saves entries that sensors create. I am checking on leaks with valgrind, now I was wondering how to 'simulate' a broken SQL server. I am using this function:
rc = sqlite3_prepare_v2(conn, sql, -1, &res, 0);
This function works correctly, is there a way to simulate it failing? Setting rc to another value manually is an option, but doesn't make sense since a database does get created while the program thinks it doesn't.
I will add the code bellow, although I don't think this is necessary for this question.
This is the insert function that inserts a sensor into the database. This is where I want to test what happens when the prepare function fails.
void *insert_sensor(void *argument) {
storagemgr_insert_argument_t *storagemgr_insert_argument = (storagemgr_insert_argument_t *) argument;
DBCONN *conn = storagemgr_insert_argument->db_connection;
sqlite3_stmt *res = NULL;
uint16_t sensor_id_read;
double temperature_value_read;
time_t timestamp_read;
sensor_data_t data;
int buffer_working_check;
data.id = 0;
data.value = 0;
data.ts = 0;
buffer_working_check = 1;
while (connmgr_loopt_bool == 1 || buffer_working_check == 0) { //connmgr aan -> moet blijven lopen, connmgr uit maar nog data beschikbaar -> moet blijven lopen
pthread_mutex_lock(&lock);
// printf("gelockt in storagemgr\n");
buffer_working_check = sbuffer_read(shared_buffer, &data, 0, 1);
pthread_mutex_unlock(&lock);
int failed_tries = 0;
if (data.id != 0 && buffer_working_check != -1 && buffer_working_check != 1) {
res = NULL;
sensor_id_read = data.id;
temperature_value_read = data.value;
timestamp_read = data.ts;
while(failed_tries<3) {
char *sql = "INSERT INTO "TO_STRING(TABLE_NAME)" (sensor_id, sensor_value, timestamp) VALUES (#sensor_id, #sensor_value, #timestamp)";
rc = sqlite3_prepare_v2(conn, sql, -1, &res, 0);
if (rc == SQLITE_OK) {
int idx1 = sqlite3_bind_parameter_index(res, "#sensor_id");
sqlite3_bind_int(res, idx1, sensor_id_read);
int idx2 = sqlite3_bind_parameter_index(res, "#sensor_value");
sqlite3_bind_double(res, idx2, temperature_value_read);
int idx = sqlite3_bind_parameter_index(res, "#timestamp");
sqlite3_bind_int(res, idx, timestamp_read);
break;
}
else {
write_to_fifo("Insert to the SQL server failed, trying again. ", 4);
failed_tries++;
// char *err_msg = 0;
//
// fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(conn));
// sqlite3_free(err_msg);
// sqlite3_close(conn);
// return NULL;
}
sleep(2);
}
}
if (0<failed_tries && failed_tries <= 2) { //het mag =2, want als het =2 en de db faalt dan wordt het eerst geincrementeert naar 3
write_to_fifo("Connection to SQL server re-established. ", 5);
}
if(failed_tries>2) {
db_connection_failed_bool = 1;
sqlite3_close(conn);
write_to_fifo("Connection to SQL server lost. ", 6);
break;
}
if (res != NULL) {
sqlite3_step(res);
sqlite3_finalize(res);
res = NULL;
}
}
return NULL;
}
If you want to keep the code pure, you could always pass the insert function an invalid file path or invalid file name. If you are trying to test the recovery loop, and still want it to remain pure, you can pass the invalid file path and have the recovery loop try to build the path. SQLite won’t build a database in a folder that doesn’t exist when using sqlite3_prepare_v2.
So I have a this program in windows that relies on each other. And I have a loop that checks a certain condition and spawns GTime_mod.exe if the condition is true. As you can see in my code below it has an aux variable coming from a database, the variables default value is 1. Now if GTime_mod.exe is executed the and then when the user were able to give the right username and password, the value of aux will change to 0. Then when the user logout aux will change to 1 again. Now my problem is, I wan't the aux value to change to 1 again besides logging-out. Because there are cases when the **[case 1]** user will just press (X) button to close the program. Or the **[case 2]** user might stop the program by pressing Ctrl + C. And lastly **[case 3]** the user might close the program via task manager. Can anyone please help me or give me a suggestion on how to tackle this problem, your help will be highly appreciated.
int main(void){
sqlite3 *db;
time_t now;
struct tm *local;
int er;
char *sqlCom;
char *errMsg = 0;
hr_mn high,low;
int sdur = 0;
int opt = 0;
int cond = 0;
int aux = 0;
er = sqlite3_open("GTime.db",&db);
if(er != SQLITE_OK) sqlite3_close(db),Err(sqlite3_errmsg(db));
er = sqlite3_exec(db,"SELECT * FROM TIMELIM WHERE ROWID = 1;",hrmn,&low,&errMsg);
if(er != SQLITE_OK) sqlite3_close(db),Err(errMsg);
er = sqlite3_exec(db,"SELECT * FROM TIMELIM WHERE ROWID = 2;",hrmn,&high,&errMsg);
if(er != SQLITE_OK) sqlite3_close(db),Err(errMsg);
er = sqlite3_exec(db,"SELECT * FROM TIMELIM WHERE ROWID = 3;",hrmn,&aux,&errMsg);
if(er != SQLITE_OK) sqlite3_close(db),Err(errMsg);
time(&now);
local = localtime(&now);
sdur = 30 - (local->tm_sec <= 30 ? local->tm_sec : (local->tm_sec - 30));
do{
cond = (local->tm_hour >= low.hrs && local->tm_min < low.min) ||
(local->tm_hour <= high.hrs && local->tm_min < high.min);
if(!cond && aux){
spawnl(P_WAIT,"C:\\WINDOWS\\System32\\shutdown.exe","C:\\WINDOWS\\System32\\shutdown.exe","/r /f /t 60 /c \" \"",NULL);
opt = MessageBoxA( NULL, "System is shutting down", "GTime", MB_OKCANCEL|MB_ICONSTOP|MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_TOPMOST );
if(opt == 2){
spawnl(P_WAIT,"GTime_mod.exe","GTime_mod.exe",NULL,NULL);
}else
exit(0);
time(&now);
local = localtime(&now);
sleep(30 - (local->tm_sec <= 30 ? local->tm_sec : (local->tm_sec - 30)));
}else
sleep(sdur);
time(&now);
local = localtime(&now);
er = sqlite3_exec(db,"SELECT * FROM TIMELIM WHERE ROWID = 1;",hrmn,&low,&errMsg);
if(er != SQLITE_OK) sqlite3_close(db),Err(errMsg);
er = sqlite3_exec(db,"SELECT * FROM TIMELIM WHERE ROWID = 2;",hrmn,&high,&errMsg);
if(er != SQLITE_OK) sqlite3_close(db),Err(errMsg);
er = sqlite3_exec(db,"SELECT * FROM TIMELIM WHERE ROWID = 3;",hrmn,&aux,&errMsg);
if(er != SQLITE_OK) sqlite3_close(db),Err(errMsg);
sdur = 30;
}while(1);
return 0;
}
[Edit]
As for me case 1 is the highest priority to be solved as it is the most likely scenario
From reading the spawnl documentaion you can get the exit value by using the P_WAIT flag.
So you just need to check that response value:
int exit_val;
[...]
exit_val = spawnl( P_WAIT, "GTime_mod.exe","GTime_mod.exe", NULL, NULL);
if ( exit_val == 1 )
{
// manage exit
}
Move the code that changes the value back to 1 to a function, and register the function with atexit so it is always called when exiting the program.
I need a code example. I'd like to see how we can enumerate columns names in table. (It's essential for me to use esent.dll/esent.lib and C language)
I tried to use attached code (found a guide but it doesn't work as I expect).
JET_COLUMNLIST column_info;
JET_RETRIEVECOLUMN j_rc[4];
err = JetGetTableColumnInfo(sessionID, curr_table.tableID, NULL, &column_info, sizeof(JET_COLUMNLIST), JET_ColInfoList);
j_rc[0].columnid = column_info.columnidcolumnname;
j_rc[0].cbData = sizeof(char)*JET_cbNameMost;
j_rc[0].itagSequence = 1;
j_rc[0].grbit = 0;
char buf[JET_cbNameMost] = { 0 };
j_rc[0].pvData = buf;
printf("\nRetrieving columns information:\n");
printf("Row\tId\tType\tName:\n");
unsigned long columns_qnt = 0;
for (err = JetMove(sessionID, curr_table.tableID, JET_MoveFirst, 0);
JET_errSuccess == err;
err = JetMove(sessionID, curr_table.tableID, JET_MoveNext, 0))
{
err = JetRetrieveColumns(sessionID, curr_table.tableID, j_rc, 4);
columns_qnt++;
printf("%u\t%s\n", columns_qnt, buf);
memset(buf, 0, JET_cbNameMost);
}
Please show an example. If you know good guides for ESE C programming or just some resources with describing of how it works, please share it with me. (Despite I googled a lot, don't be shy to share obvious for you resourses)
Inside table "MSysObjects" (which exists in every ESE database as service table) are 2 interisting for us columns: "Type" and "Name".
JetOpenTable(sessionID, dbid, "MSysObjects", NULL, NULL, JET_bitTableSequential, &tableID);
JET_COLUMNBASE j_cb_name, j_cb_type, j_cb_coltype;
JetGetColumnInfo(sessionID, dbid, "MSysObjects", "Name", &j_cb_name, sizeof(JET_COLUMNBASE), JET_ColInfoBase);
JetGetColumnInfo(sessionID, dbid, "MSysObjects", "Type", &j_cb_type, sizeof(JET_COLUMNBASE), JET_ColInfoBase);
JET_RETRIEVECOLUMN j_rc[2];
Here we fill structure JET_RETRIEVECOLUMN to get this 2 columns by JetRetrieveColumns
j_rc[0].columnid = j_cb_name.columnid;
j_rc[0].cbData = 1024;
j_rc[0].itagSequence = 1;
j_rc[0].grbit = NULL;
char buf[1024] = { 0 };
j_rc[0].pvData = buf;
j_rc[1].columnid = j_cb_type.columnid;
j_rc[1].cbData = sizeof(unsigned short);
j_rc[1].itagSequence = 1;
j_rc[1].grbit = NULL;
unsigned short type;
j_rc[1].pvData = &type;
for (err = JetMove(sessionID, root_tableID, JET_MoveFirst, 0);
JET_errSuccess == err;
err = JetMove(sessionID, root_tableID, JET_MoveNext, 0))
{
JetRetrieveColumns(sessionID, root_tableID, j_rc, 2);
We got them here. If type == 1 it means, that record we got is describing a table and if type == 2, then it's describing a column . (There are also other types) There is strict order, first you will get record with type 1 (table) then you will get records with type 2 that describes columns of that table (in that moment buf keeps column name), then you can get records with other types (except type == 1) that refers to that table. And finally you will get record with type 1, that means that next information we get is about another table.
}
Feel free to say that my english is awful and I wrote some junk, I'll try to explain in other way then:)
If you just want a list of column names for a particular table without using MSysObjects, here's my approach. The temporary table created by "JetGetTableColumnInfo" contains only the column ID and column Name, so it's pretty fast:
JET_ERR GetEseTableColumnNames(JET_SESID hEseSession, JET_TABLEID hEseTable)
{ JET_ERR rc;
JET_COLUMNLIST cl { };
/* Sort order for the temporary table is column name order */
rc = ::JetGetTableColumnInfo(hEseSession, hEseTable, nullptr, &cl, sizeof(cl), JET_ColInfoList | JET_ColInfoGrbitMinimalInfo);
/* Temporary table ("cl.tableid") is opened and positioned on first record */
if (rc == JET_errSuccess && cl.cRecord > 0)
{ wchar_t wszColumnName[MAX_ESE_OBJECT_NAME + 1]; // ESE doesn't play well with std::strings
unsigned long cbActual;
for (uint32_t i = 0; i < cl.cRecord; ++i)
{
rc = ::JetRetrieveColumn(hEseSession, cl.tableid, cl.columnidcolumnname, wszColumnName, sizeof(wszColumnName), &cbActual, 0, nullptr);
if (rc == JET_errSuccess)
{
/* ESE does not null terminate strings */
wszColumnName[cbActual / sizeof(wchar_t)] = L'\0';
//********
// Okay, so do something with the column name here
//********
/* Next record in temporary table */
if (i < cl.cRecord - 1)
::JetMove(hEseSession, cl.tableid, JET_MoveNext, 0);
}
else
break;
}
}
/* Close the temporary table */
::JetCloseTable(hEseSession, cl.tableid);
return rc;
}
I know other folks use MSysObjects to short-cut the process, but this works fine for me. And yes, my code looks old fashioned - I'm stuck in Hungarian!
It's possible to print wpa passphrase in hostapd (by editing the code)?
This is the conf of hostapd (we use TKIP) :
wpa=1
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
wpa_passphrase=passphrase
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
In the file hostpad/src/ap/wpa_auth.c, we have lots of information about the connection :
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_ptk PTK;
int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
unsigned int pmk_len;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
sm->update_snonce = FALSE;
/* WPA with IEEE 802.1X: use the derived PMK from EAP
* WPA-PSK: iterate through possible PSKs and select the one matching
* the packet */
for (;;) {
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk);
if (pmk == NULL)
break;
psk_found = 1;
pmk_len = PMK_LEN;
} else {
pmk = sm->PMK;
pmk_len = sm->pmk_len;
}
wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
ok = 1;
break;
}
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
break;
}
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
if (psk_found)
wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
return;
}
#ifdef CONFIG_IEEE80211R
// ....
#endif /* CONFIG_IEEE80211R */
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
/* PSK may have changed from the previous choice, so update
* state machine data based on whatever PSK was selected here.
*/
os_memcpy(sm->PMK, pmk, PMK_LEN);
sm->pmk_len = PMK_LEN;
}
sm->MICVerified = TRUE;
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
}
My knowledge in networks are limited, and I do not understand very well WPA protocol. There is an article interesting on the question here, but the situation is a little bit different because we are in the case of an attack "man in the middle".
I recently inherited a code base that uses quicktime, I've noticed when importing moves using the function below it works most of the time, but then it will occasionally crash. It's weird when it crashes because it work 10 times in a row and then after it would crash the application.
I am using winapi in C for my application.
IDE: Visual Studio 8
OS: Windows 7
Quicktime version: Latest
This is from the Quicktime API Docs:
PutMovieIntoTypedHandle
Takes a movie, or a single track from within that movie, and converts it into a handle of a specified type.
OSErr PutMovieIntoTypedHandle (
Movie theMovie,
Track targetTrack,
OSType handleType,
Handle publicMovie,
TimeValue start,
TimeValue dur,
long flags,
ComponentInstance userComp
);
The Code:
Track newTrack;
FSSpec audioFile;
Movie audioFileMovie;
Track audioFileTrack;
Media audioFileMedia;
TimeValue audioTrackDuration;
long trackCount;
short audioRefNum;
TimeScale audioTimeScale;
OSErr err;
SoundDescriptionHandle outDesc, inDesc;
ComponentInstance soundComp =0;
SndListResource * slr;
SoundHeader * sh;
Handle soundData = NewHandle(0);
long i,sampleOffset,actualSamples, sampleCount;
//Create dataRef from audioFilePath
if((err = NativePathNameToFSSpec(audioFilePath, &audioFile, kErrorIfFileNotFound)) != noErr) {
if(err != fnfErr) {
printf("NativePathNameToFSSpec failed. Error: %d\n", err);
return 0;
}
}
if(noErr != OpenMovieFile(&audioFile, &audioRefNum, fsRdPerm)){
fprintf(stderr, "Couldn't open movie file\n");
return 0;
}
NewMovieFromFile(&audioFileMovie, audioRefNum, NULL, (StringPtr)NULL, newMovieActive, NULL);
if (audioRefNum != 0)
CloseMovieFile(audioRefNum);
//see how many tracks there are in the audioFileMovie
trackCount = GetMovieTrackCount(audioFileMovie);
//Obtain audio track from audio movie
audioFileTrack = GetMovieIndTrack(audioFileMovie, 1);
//Obtain audio media from audioFileTrack so that we can figure out how long it is
audioFileMedia = GetTrackMedia(audioFileTrack);
audioTrackDuration = GetMediaDuration(audioFileMedia);
audioTimeScale = GetMediaTimeScale(audioFileMedia);
soundComp = OpenDefaultComponent('spit', 'snd ');
if(!soundComp)
{
return 1;
}
inDesc=(SoundDescriptionHandle)NewHandle(0);
outDesc=nil;
GetMediaSampleDescription(GetTrackMedia(audioFileTrack),1,(SampleDescriptionHandle)inDesc);
outDesc = (SoundDescriptionHandle) NewHandleClear(sizeof(SoundDescription));
if(!outDesc)
{
CloseComponent(soundComp);
return 1;
}
outDesc[0]->descSize = sizeof(SoundDescription);
outDesc[0]->dataFormat = k8BitOffsetBinaryFormat;
outDesc[0]->numChannels = 1;
outDesc[0]->sampleSize = 8;
outDesc[0]->sampleRate = inDesc[0]->sampleRate;
MovieExportSetSampleDescription(soundComp, (SampleDescriptionHandle)outDesc, 'soun');
DisposeHandle((Handle)inDesc);
DisposeHandle((Handle)outDesc);
if( audioFileMovie && soundData && soundComp )
{
MessageBox(NULL, "Entering \"PutMovieIntoTypedHandle\".\n", "Checkpoint" ,MB_OK);
OSErr result = PutMovieIntoTypedHandle(audioFileMovie,0, 'snd ', soundData, 0, // frameTime,
GetMovieDuration(audioFileMovie), 0, soundComp);
MessageBox(NULL, "Made it passed \"PutMovieIntoTypedHandle\".\n", "Checkpoint" ,MB_OK);
}
else
{
return 1;
}