Skip to content

Commit 73d941d

Browse files
committed
midb: change M-COPY from a read-write cycle to server-side copy
References: GXH-107
1 parent b5886b2 commit 73d941d

File tree

1 file changed

+31
-108
lines changed

1 file changed

+31
-108
lines changed

exch/midb/mail_engine.cpp

Lines changed: 31 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -2414,24 +2414,8 @@ static int mail_engine_mdele(int argc, char **argv, int sockd)
24142414
*/
24152415
static int mail_engine_mcopy(int argc, char **argv, int sockd) try
24162416
{
2417-
uint32_t tmp_flags;
2418-
uint64_t change_num;
2419-
uint64_t message_id;
2420-
char sql_string[1024];
2421-
24222417
if (strlen(argv[4]) >= 1024)
24232418
return MIDB_E_PARAMETER_ERROR;
2424-
auto eml_src = argv[1] + "/eml/"s + argv[3];
2425-
size_t slurp_size = 0;
2426-
std::unique_ptr<char[], stdlib_delete> pbuff(HX_slurp_file(eml_src.c_str(), &slurp_size));
2427-
if (pbuff == nullptr) {
2428-
mlog(LV_ERR, "E-2074: Opening %s for reading failed: %s", eml_src.c_str(), strerror(errno));
2429-
return errno == ENOMEM ? MIDB_E_NO_MEMORY : MIDB_E_DISK_ERROR;
2430-
}
2431-
2432-
MAIL imail;
2433-
if (!imail.load_from_str_move(pbuff.get(), slurp_size))
2434-
return MIDB_E_IMAIL_RETRIEVE;
24352419
auto pidb = mail_engine_get_idb(argv[1]);
24362420
if (pidb == nullptr)
24372421
return MIDB_E_HASHTABLE_FULL;
@@ -2452,103 +2436,42 @@ static int mail_engine_mcopy(int argc, char **argv, int sockd) try
24522436
if (pstmt.step() != SQLITE_ROW ||
24532437
pstmt.col_uint64(CTM_FOLDERID) != src_fid)
24542438
return MIDB_E_NO_MESSAGE;
2455-
2456-
std::string flags_buff = "(";
2457-
if (pstmt.col_uint64(CTM_REPLIED) != 0)
2458-
flags_buff += 'A';
2459-
if (pstmt.col_uint64(CTM_FLAGGED) != 0)
2460-
flags_buff += 'F';
2461-
if (pstmt.col_uint64(CTM_FWD) != 0)
2462-
flags_buff += 'W';
2463-
flags_buff += ')';
2464-
auto b_unsent = pstmt.col_uint64(CTM_UNSENT) != 0;
2465-
uint8_t b_read = pstmt.col_uint64(CTM_READ) != 0;
2466-
uint64_t nt_time = pstmt.col_int64(CTM_RCVDTIME);
2439+
uint64_t src_mid = pstmt.col_uint64(CTM_MSGID), message_id = 0;
24672440
pstmt.finalize();
2468-
unsigned int user_id = 0;
2469-
if (!system_services_get_user_ids(pidb->username.c_str(), &user_id, nullptr, nullptr))
2470-
return MIDB_E_SSGETID;
2471-
sql_meta_result mres;
2472-
auto mret = system_services_meta(pidb->username.c_str(),
2473-
WANTPRIV_METAONLY, mres);
2474-
auto charset = mret == 0 ? lang_to_charset(mres.lang.c_str()) : nullptr;
2475-
if (*znul(charset) == '\0')
2476-
charset = g_default_charset;
2477-
auto tmzone = mret == 0 ? mres.timezone.c_str() : nullptr;
2478-
if (*znul(tmzone) == '\0')
2479-
tmzone = GROMOX_FALLBACK_TIMEZONE;
2480-
auto pmsgctnt = oxcmail_import(charset, tmzone, &imail,
2481-
common_util_alloc, common_util_get_propids_create);
2482-
imail.clear();
2483-
pbuff.reset();
2484-
if (pmsgctnt == nullptr)
2485-
return MIDB_E_OXCMAIL_IMPORT;
2486-
auto cl_msg = make_scope_exit([&]() { message_content_free(pmsgctnt); });
2487-
if (pmsgctnt->proplist.set(PR_MESSAGE_DELIVERY_TIME, &nt_time) != 0)
2488-
return MIDB_E_NO_MEMORY;
2489-
static_assert(std::is_same_v<decltype(b_read), uint8_t>);
2490-
if (b_read && pmsgctnt->proplist.set(PR_READ, &b_read) != 0)
2491-
return MIDB_E_NO_MEMORY;
2492-
if (0 != b_unsent) {
2493-
tmp_flags = MSGFLAG_UNSENT;
2494-
if (pmsgctnt->proplist.set(PR_MESSAGE_FLAGS, &tmp_flags) != 0)
2495-
return MIDB_E_NO_MEMORY;
2496-
}
24972441
if (!exmdb_client::allocate_message_id(argv[1],
2498-
rop_util_make_eid_ex(1, dst_fid), &message_id) ||
2499-
!exmdb_client::allocate_cn(argv[1], &change_num))
2442+
rop_util_make_eid_ex(1, dst_fid), &message_id))
25002443
return MIDB_E_MDB_ALLOCID;
25012444

2502-
auto mid_string = std::to_string(time(nullptr)) + "." +
2503-
std::to_string(++g_sequence_id) + ".midb";
2504-
eml_src = argv[1] + "/eml/"s + argv[3];
2505-
auto eml_dst = argv[1] + "/eml/"s + mid_string;
2506-
if (link(eml_src.c_str(), eml_dst.c_str()) != 0)
2507-
mlog(LV_ERR, "E-2083: link %s %s: %s",
2508-
eml_src.c_str(), eml_dst.c_str(),
2509-
strerror(errno));
2510-
eml_src = argv[1] + "/ext/"s + argv[3];
2511-
eml_dst = argv[1] + "/ext/"s + mid_string;
2512-
if (link(eml_src.c_str(), eml_dst.c_str()) != 0)
2513-
mlog(LV_ERR, "E-2084: link %s %s: %s",
2514-
eml_src.c_str(), eml_dst.c_str(),
2515-
strerror(errno));
2516-
snprintf(sql_string, std::size(sql_string), "INSERT INTO mapping"
2517-
" (message_id, mid_string, flag_string) VALUES"
2518-
" (%llu, ?, ?)", LLU{rop_util_get_gc_value(message_id)});
2519-
pstmt = gx_sql_prep(pidb->psqlite, sql_string);
2520-
if (pstmt == nullptr)
2521-
return MIDB_E_SQLPREP;
2522-
sqlite3_bind_text(pstmt, 1, mid_string.c_str(), -1, SQLITE_STATIC);
2523-
sqlite3_bind_text(pstmt, 2, flags_buff.c_str(), -1, SQLITE_STATIC);
2524-
if (pstmt.step() != SQLITE_DONE)
2525-
return MIDB_E_SQLUNEXP;
2526-
pstmt.finalize();
2527-
std::string username = pidb->username;
2528-
pidb.reset();
2529-
if (pmsgctnt->proplist.set(PidTagMid, &message_id) != 0 ||
2530-
pmsgctnt->proplist.set(PidTagChangeNumber, &change_num) != 0)
2531-
return MIDB_E_NO_MEMORY;
2532-
auto pbin = cu_xid_to_bin({rop_util_make_user_guid(user_id), change_num});
2533-
if (pbin == nullptr ||
2534-
pmsgctnt->proplist.set(PR_CHANGE_KEY, pbin) != 0)
2535-
return MIDB_E_NO_MEMORY;
2536-
auto newval = common_util_pcl_append(NULL, pbin);
2537-
if (newval == nullptr ||
2538-
pmsgctnt->proplist.set(PR_PREDECESSOR_CHANGE_LIST, newval) != 0)
2539-
return MIDB_E_NO_MEMORY;
2540-
auto cpid = cset_to_cpid(charset);
2541-
if (cpid == CP_ACP)
2542-
cpid = static_cast<cpid_t>(1252);
2543-
ec_error_t e_result = ecRpcFailed;
2544-
if (!exmdb_client::write_message(argv[1], cpid,
2545-
rop_util_make_eid_ex(1, dst_fid), pmsgctnt, &e_result) ||
2546-
e_result != ecSuccess)
2445+
/*
2446+
* exmdb-level copy: this triggers an event and some other midb threads
2447+
* will instantiate the midb message (and decide mid_string)
2448+
*/
2449+
BOOL e_result = false;
2450+
if (!exmdb_client::movecopy_message(argv[1], CP_UTF8, rop_util_make_eid_ex(1, src_mid),
2451+
rop_util_make_eid_ex(1, dst_fid), message_id,
2452+
false, &e_result) || !e_result)
25472453
return MIDB_E_MDB_WRITEMESSAGE;
2548-
cl_msg.release();
2549-
message_content_free(pmsgctnt);
2550-
mid_string.insert(0, "TRUE ");
2551-
mid_string.append("\r\n");
2454+
2455+
pidb.reset(); /* release giant lock, let event get processed */
2456+
std::string mid_string;
2457+
for (unsigned int i = 0; i < 10; ++i) {
2458+
pidb = mail_engine_get_idb(argv[1]);
2459+
if (pidb == nullptr)
2460+
return MIDB_E_HASHTABLE_FULL;
2461+
pstmt = gx_sql_prep(pidb->psqlite, "SELECT mid_string FROM messages WHERE message_id=?");
2462+
if (pstmt == nullptr)
2463+
return MIDB_E_NO_MEMORY;
2464+
pstmt.bind_int64(1, rop_util_get_gc_value(message_id));
2465+
if (pstmt.step() == SQLITE_ROW) {
2466+
mid_string = "TRUE "s + pstmt.col_text(0) + "\r\n";
2467+
break;
2468+
}
2469+
pstmt.reset();
2470+
pidb.reset();
2471+
usleep(100000);
2472+
}
2473+
if (mid_string.empty())
2474+
mid_string = "FALSE\r\n";
25522475
return cmd_write(sockd, mid_string.c_str(), mid_string.size());
25532476
} catch (const std::bad_alloc &) {
25542477
mlog(LV_ERR, "E-1486: ENOMEM");

0 commit comments

Comments
 (0)