Skip to content

Commit 9152bab

Browse files
committed
exmdb: cure double notification of content table additions
Under these conditions combined: * MAPI client has a content table open on a folder * The MAPI content table has a sort order defined (this causes a UNIQUE index to be added to the sqlite table) * Message delivery executes an OP_MOVE rule to the same folder * Twostep Rule Processor is used then the following log message is observed: ``` sqlite3_exec(tables.sqlite3) "INSERT INTO t8 (inst_id, prev_id, row_type, depth, inst_num, idx) VALUES (2097156, 1, 2, 0, 0, 2)": UNIQUE constraint failed: t8.inst_id (19) at [...]" ``` maps to [/usr/src/debug/gromox-2.46.20.bac7ae5-lp156.2.1.x86_64 exch/exmdb/db_engine.hpp:208 exch/exmdb/db_engine.cpp:2122 void db_conn::notify_new_mail last line exch/exmdb/store2.cpp:68 (discriminator 6) include/exmdb_dispatch.cpp:962 ] When a *categorized* sort order is set, the message is slightly different: ``` sqlite3_step(tables.sqlite3) "INSERT INTO t29 (inst_id, row_type, row_stat, parent_id, depth, count, unread, inst_num, value, extremum, prev_id) VALUES (2097158, 2, NULL, 1, 1, NULL, NULL, 0, NULL, 0, -1)": UNIQUE constraint failed: t29.inst_id (19) ``` (no backtrace) cttbl_add_row is called from both notify_new_mail and notify_message_movecopy. [Onestep Rule Processor does not exhibit the problem because it uses cu_copy_message rather than exmdb_server::movecopy_messages, not generating notifications.] The fix here appears to be to use the transport_new_mail EXRPC instead of notify_new_mail, to eschew the extra call to cttbl_add_row. In addition, deliver_message (which runs in any case) should emit the message_created notification ahead of the OP_MOVE. References: DESK-3519
1 parent 7263fd1 commit 9152bab

File tree

5 files changed

+43
-26
lines changed

5 files changed

+43
-26
lines changed

doc/changelog.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ Fixes:
2020
* midb, imap: make EXPUNGE synchronous so that old UIDs don't reappear in
2121
a subsequent FETCH
2222
* midb: respect setting \Deleted, \Answered, \Flagged during APPEND
23-
23+
* exmdb: resolve a case of "INSERT INTO t... UNIQUE constraint failed" log
24+
message appearing when the Twostep Rule Processor and a Move rule is
25+
encountered and a MAPI client has a Content Table with Sort Order open.
2426

2527

2628
Gromox 2.46 (2025-05-28)

exch/exmdb/db_engine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ void db_base::get_dbs(const char* dir, sqlite3 *&main, sqlite3 *&eph)
553553
* @brief Initialize and unlock database
554554
*
555555
* Perform database initializations that should not be run for each connection:
556-
* - Remove residue ephemeral db
556+
* - Remove residual ephemeral tables db from last process
557557
* - Perform schema upgrade
558558
*
559559
* @param dir User or domain base directory

exch/exmdb/message.cpp

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2929,9 +2929,9 @@ static ec_error_t op_move_same(const rulexec_in &rp,
29292929
rex.message_id = dst_mid;
29302930
if (exmdb_server::is_private() && rp.digest.has_value() &&
29312931
common_util_get_mid_string(rp.sqlite, dst_mid, &pmid_string) &&
2932-
pmid_string != nullptr) {
2932+
pmid_string != nullptr)
29332933
(*rex.digest)["file"] = pmid_string;
2934-
}
2934+
29352935
auto ec = message_rule_new_message(std::move(rex), seen);
29362936
if (ec != ecSuccess)
29372937
return ec;
@@ -3786,26 +3786,21 @@ BOOL exmdb_server::deliver_message(const char *dir, const char *from_address,
37863786
return FALSE;
37873787
}
37883788

3789-
if (dlflags & DELIVERY_DO_NOTIF) {
3790-
auto dbase = pdb->lock_base_wr();
3791-
db_conn::NOTIFQ notifq;
3792-
for (const auto &mn : seen.msg) {
3793-
pdb->proc_dynamic_event(cpid, dynamic_event::new_msg,
3794-
mn.folder_id, mn.message_id, 0, *dbase, notifq);
3795-
if (message_id == mn.message_id)
3796-
pdb->notify_new_mail(mn.folder_id,
3797-
mn.message_id, *dbase, notifq);
3798-
else
3799-
pdb->notify_message_creation(mn.folder_id,
3800-
mn.message_id, *dbase, notifq);
3801-
}
3802-
if (sql_transact.commit() != SQLITE_OK)
3803-
return false;
3804-
dg_notify(std::move(notifq));
3805-
} else {
3806-
if (sql_transact.commit() != SQLITE_OK)
3807-
return false;
3789+
auto dbase = pdb->lock_base_wr();
3790+
db_conn::NOTIFQ notifq;
3791+
for (const auto &mn : seen.msg) {
3792+
pdb->proc_dynamic_event(cpid, dynamic_event::new_msg,
3793+
mn.folder_id, mn.message_id, 0, *dbase, notifq);
3794+
if (message_id == mn.message_id && dlflags & DELIVERY_DO_NOTIF)
3795+
pdb->notify_new_mail(mn.folder_id,
3796+
mn.message_id, *dbase, notifq);
3797+
else
3798+
pdb->notify_message_creation(mn.folder_id,
3799+
mn.message_id, *dbase, notifq);
38083800
}
3801+
if (sql_transact.commit() != SQLITE_OK)
3802+
return false;
3803+
dg_notify(std::move(notifq));
38093804
*new_folder_id = rop_util_make_eid_ex(1, fid_val);
38103805
*new_msg_id = rop_util_make_eid_ex(1, message_id);
38113806
*presult = static_cast<uint32_t>(partial ?

exch/exmdb/store2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ BOOL exmdb_server::notify_new_mail(const char *dir, uint64_t folder_id,
6464
auto pdb = db_engine_get_db(dir);
6565
if (!pdb)
6666
return false;
67-
/* notify_new_mail needs an externally managed transaction on main. */
67+
/* db_conn::notify_new_mail needs an externally managed transaction. So start one. */
6868
auto sql_trans = gx_sql_begin(pdb->psqlite, txn_mode::read);
6969
auto dbase = pdb->lock_base_wr();
7070
db_conn::NOTIFQ notifq;

lib/ruleproc.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ struct rxparam {
126126
ec_error_t is_oof(bool *out) const;
127127
ec_error_t load_std_rules(bool oof, std::vector<rule_node> &out) const;
128128
ec_error_t load_ext_rules(bool oof, std::vector<rule_node> &out) const;
129+
void notify();
129130

130131
const char *ev_from = nullptr, *ev_to = nullptr;
131132
message_node cur;
@@ -1325,11 +1326,30 @@ ec_error_t rxparam::run()
13251326
return err;
13261327
}
13271328

1328-
if (!exmdb_client->notify_new_mail(cur.dirc(), cur.fid, cur.mid))
1329-
mlog(LV_ERR, "ruleproc: newmail notification unsuccessful");
1329+
notify();
13301330
return ecSuccess;
13311331
}
13321332

1333+
void rxparam::notify()
1334+
{
1335+
static constexpr proptag_t tagdata[] = {PR_MESSAGE_FLAGS, PR_MESSAGE_CLASS};
1336+
static constexpr PROPTAG_ARRAY tags = {std::size(tagdata), deconst(tagdata)};
1337+
TPROPVAL_ARRAY vals{};
1338+
if (!exmdb_client->get_message_properties(cur.dirc(), nullptr, CP_UTF8,
1339+
cur.mid, &tags, &vals)) {
1340+
mlog(LV_ERR, "ruleproc: getprops FL/C failed");
1341+
return;
1342+
}
1343+
auto cls = vals.get<const char>(PR_MESSAGE_CLASS);
1344+
auto flags = vals.get<const uint32_t>(PR_MESSAGE_FLAGS);
1345+
if (cls == nullptr || flags == nullptr) {
1346+
mlog(LV_ERR, "ruleproc: msg %llxh oddly missing FL/C", static_cast<unsigned long long>(cur.mid));
1347+
return;
1348+
}
1349+
if (!exmdb_client->transport_new_mail(cur.dirc(), cur.fid, cur.mid, *flags, cls))
1350+
mlog(LV_ERR, "ruleproc: tnewmail notification unsuccessful");
1351+
}
1352+
13331353
static ec_error_t exmdb_local_rules_execute(const char *dir, const char *ev_from,
13341354
const char *ev_to, eid_t folder_id, eid_t msg_id, unsigned int flags) try
13351355
{

0 commit comments

Comments
 (0)