Support scheduled message in MessageId::get_next_message_id. Add get_next_yet_unsent_scheduled_message_id.

GitOrigin-RevId: dfe0c0b13c6312525564eba9f10f390f5ad09778
This commit is contained in:
levlam 2019-12-02 23:29:08 +03:00
parent 57eb92060b
commit f3dfaa6c29
4 changed files with 88 additions and 22 deletions

View File

@ -11,12 +11,12 @@
namespace td { namespace td {
MessageId::MessageId(ScheduledServerMessageId server_message_id, int32 send_date) { MessageId::MessageId(ScheduledServerMessageId server_message_id, int32 send_date, bool force) {
if (send_date <= (1 << 30)) { if (send_date <= (1 << 30)) {
LOG(ERROR) << "Scheduled message send date " << send_date << " is in the past"; LOG(ERROR) << "Scheduled message send date " << send_date << " is in the past";
return; return;
} }
if (!server_message_id.is_valid()) { if (!server_message_id.is_valid() && !force) {
LOG(ERROR) << "Scheduled message ID " << server_message_id.get() << " is invalid"; LOG(ERROR) << "Scheduled message ID " << server_message_id.get() << " is invalid";
return; return;
} }
@ -46,6 +46,20 @@ MessageType MessageId::get_type() const {
if (id <= 0 || id > max().get()) { if (id <= 0 || id > max().get()) {
return MessageType::None; return MessageType::None;
} }
if (is_scheduled()) {
switch (id & TYPE_MASK) {
case SCHEDULED_MASK | TYPE_YET_UNSENT:
return MessageType::YetUnsent;
case SCHEDULED_MASK | TYPE_LOCAL:
return MessageType::Local;
case SCHEDULED_MASK:
return MessageType::Server;
default:
return MessageType::None;
}
}
if ((id & FULL_TYPE_MASK) == 0) { if ((id & FULL_TYPE_MASK) == 0) {
return MessageType::Server; return MessageType::Server;
} }
@ -65,14 +79,37 @@ ServerMessageId MessageId::get_server_message_id_force() const {
} }
MessageId MessageId::get_next_message_id(MessageType type) const { MessageId MessageId::get_next_message_id(MessageType type) const {
CHECK(!is_scheduled()); if (is_scheduled()) {
CHECK(is_valid_scheduled());
auto current_type = get_type();
if (static_cast<int32>(current_type) < static_cast<int32>(type)) {
return MessageId(id - static_cast<int32>(current_type) + static_cast<int32>(type));
}
int64 base_id = (id & ~TYPE_MASK) + TYPE_MASK + 1 + SCHEDULED_MASK;
switch (type) {
case MessageType::Server:
return MessageId(base_id);
case MessageType::YetUnsent:
return MessageId(base_id + TYPE_YET_UNSENT);
case MessageType::Local:
return MessageId(base_id + TYPE_LOCAL);
case MessageType::None:
default:
UNREACHABLE();
return MessageId();
}
}
switch (type) { switch (type) {
case MessageType::Server: case MessageType::Server:
if (is_server()) {
return MessageId(ServerMessageId(get_server_message_id().get() + 1));
}
return get_next_server_message_id(); return get_next_server_message_id();
case MessageType::Local:
return MessageId(((id + TYPE_MASK + 1 - TYPE_LOCAL) & ~TYPE_MASK) + TYPE_LOCAL);
case MessageType::YetUnsent: case MessageType::YetUnsent:
return MessageId(((id + TYPE_MASK + 1 - TYPE_YET_UNSENT) & ~TYPE_MASK) + TYPE_YET_UNSENT); return MessageId(((id + TYPE_MASK + 1 - TYPE_YET_UNSENT) & ~TYPE_MASK) + TYPE_YET_UNSENT);
case MessageType::Local:
return MessageId(((id + TYPE_MASK + 1 - TYPE_LOCAL) & ~TYPE_MASK) + TYPE_LOCAL);
case MessageType::None: case MessageType::None:
default: default:
UNREACHABLE(); UNREACHABLE();

View File

@ -18,7 +18,7 @@
namespace td { namespace td {
enum class MessageType : int32 { None, Server, Local, YetUnsent }; enum class MessageType : int32 { None, Server, YetUnsent, Local };
class MessageId { class MessageId {
int64 id = 0; int64 id = 0;
@ -55,7 +55,7 @@ class MessageId {
: id(static_cast<int64>(server_message_id.get()) << SERVER_ID_SHIFT) { : id(static_cast<int64>(server_message_id.get()) << SERVER_ID_SHIFT) {
} }
MessageId(ScheduledServerMessageId server_message_id, int32 send_date); MessageId(ScheduledServerMessageId server_message_id, int32 send_date, bool force = false);
explicit constexpr MessageId(int64 message_id) : id(message_id) { explicit constexpr MessageId(int64 message_id) : id(message_id) {
} }
@ -131,6 +131,11 @@ class MessageId {
return get_scheduled_server_message_id_force(); return get_scheduled_server_message_id_force();
} }
int32 get_scheduled_message_date() const {
CHECK(is_valid_scheduled());
return static_cast<int32>(id >> 21) + (1 << 30);
}
bool operator==(const MessageId &other) const { bool operator==(const MessageId &other) const {
return id == other.id; return id == other.id;
} }

View File

@ -16901,7 +16901,8 @@ MessagesManager::Message *MessagesManager::get_message_to_send(Dialog *d, Messag
int32 schedule_date = 0; int32 schedule_date = 0;
bool is_scheduled = schedule_date != 0; bool is_scheduled = schedule_date != 0;
CHECK(d != nullptr); CHECK(d != nullptr);
MessageId message_id = get_next_yet_unsent_message_id(d); // TODO support sending scheduled messages MessageId message_id =
is_scheduled ? get_next_yet_unsent_scheduled_message_id(d, schedule_date) : get_next_yet_unsent_message_id(d);
DialogId dialog_id = d->dialog_id; DialogId dialog_id = d->dialog_id;
LOG(INFO) << "Create " << message_id << " in " << dialog_id; LOG(INFO) << "Create " << message_id << " in " << dialog_id;
@ -22309,6 +22310,20 @@ MessageId MessagesManager::get_next_local_message_id(Dialog *d) {
return get_next_message_id(d, MessageType::Local); return get_next_message_id(d, MessageType::Local);
} }
MessageId MessagesManager::get_next_yet_unsent_scheduled_message_id(const Dialog *d, int32 date) {
CHECK(date > 0);
auto it = MessagesConstIterator(d, MessageId(ScheduledServerMessageId(), date + 1, true));
int32 prev_date = 0;
if (*it != nullptr) {
prev_date = (*it)->message_id.get_scheduled_message_date();
}
if (prev_date < date) {
return MessageId(ScheduledServerMessageId(1), date).get_next_message_id(MessageType::YetUnsent);
}
CHECK(*it != nullptr);
return (*it)->message_id.get_next_message_id(MessageType::YetUnsent);
}
void MessagesManager::fail_send_message(FullMessageId full_message_id, int error_code, const string &error_message) { void MessagesManager::fail_send_message(FullMessageId full_message_id, int error_code, const string &error_message) {
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog(dialog_id); Dialog *d = get_dialog(dialog_id);
@ -22331,9 +22346,9 @@ void MessagesManager::fail_send_message(FullMessageId full_message_id, int error
// dump_debug_message_op(d, 5); // dump_debug_message_op(d, 5);
} }
MessageId new_message_id; MessageId new_message_id =
old_message_id.get_next_message_id(MessageType::Local); // trying to not change message place
if (!old_message_id.is_scheduled()) { if (!old_message_id.is_scheduled()) {
new_message_id = old_message_id.get_next_message_id(MessageType::Local); // trying to not change message place
if (get_message_force(d, new_message_id, "fail_send_message") != nullptr || if (get_message_force(d, new_message_id, "fail_send_message") != nullptr ||
d->deleted_message_ids.count(new_message_id) || new_message_id <= d->last_clear_history_message_id) { d->deleted_message_ids.count(new_message_id) || new_message_id <= d->last_clear_history_message_id) {
new_message_id = get_next_local_message_id(d); new_message_id = get_next_local_message_id(d);
@ -22341,11 +22356,9 @@ void MessagesManager::fail_send_message(FullMessageId full_message_id, int error
d->last_assigned_message_id = new_message_id; d->last_assigned_message_id = new_message_id;
} }
} else { } else {
new_message_id = MessageId(old_message_id.get() + 1); // trying to not change message place while (get_message_force(d, new_message_id, "fail_send_message") != nullptr ||
if (get_message_force(d, new_message_id, "fail_send_message") != nullptr || d->deleted_message_ids.count(new_message_id)) {
d->deleted_message_ids.count(new_message_id)) { new_message_id = new_message_id.get_next_message_id(MessageType::Local);
// TODO
// new_message_id = get_next_scheduled_local_message_id(d);
} }
} }
@ -25780,11 +25793,11 @@ void MessagesManager::do_delete_message_logevent(const DeleteMessageLogEvent &lo
void MessagesManager::attach_message_to_previous(Dialog *d, MessageId message_id, const char *source) { void MessagesManager::attach_message_to_previous(Dialog *d, MessageId message_id, const char *source) {
CHECK(d != nullptr); CHECK(d != nullptr);
CHECK(message_id.is_valid());
MessagesIterator it(d, message_id); MessagesIterator it(d, message_id);
Message *m = *it; Message *m = *it;
CHECK(m != nullptr); CHECK(m != nullptr);
CHECK(m->message_id == message_id); CHECK(m->message_id == message_id);
CHECK(m->message_id.is_valid());
LOG_CHECK(m->have_previous) << d->dialog_id << " " << message_id << " " << source; LOG_CHECK(m->have_previous) << d->dialog_id << " " << message_id << " " << source;
--it; --it;
LOG_CHECK(*it != nullptr) << d->dialog_id << " " << message_id << " " << source; LOG_CHECK(*it != nullptr) << d->dialog_id << " " << message_id << " " << source;
@ -25798,11 +25811,11 @@ void MessagesManager::attach_message_to_previous(Dialog *d, MessageId message_id
void MessagesManager::attach_message_to_next(Dialog *d, MessageId message_id, const char *source) { void MessagesManager::attach_message_to_next(Dialog *d, MessageId message_id, const char *source) {
CHECK(d != nullptr); CHECK(d != nullptr);
CHECK(message_id.is_valid());
MessagesIterator it(d, message_id); MessagesIterator it(d, message_id);
Message *m = *it; Message *m = *it;
CHECK(m != nullptr); CHECK(m != nullptr);
CHECK(m->message_id == message_id); CHECK(m->message_id == message_id);
CHECK(m->message_id.is_valid());
LOG_CHECK(m->have_next) << d->dialog_id << " " << message_id << " " << source; LOG_CHECK(m->have_next) << d->dialog_id << " " << message_id << " " << source;
++it; ++it;
LOG_CHECK(*it != nullptr) << d->dialog_id << " " << message_id << " " << source; LOG_CHECK(*it != nullptr) << d->dialog_id << " " << message_id << " " << source;
@ -28064,7 +28077,8 @@ MessagesManager::Message *MessagesManager::continue_send_message(DialogId dialog
auto now = G()->unix_time(); auto now = G()->unix_time();
bool is_scheduled = m->message_id.is_scheduled(); bool is_scheduled = m->message_id.is_scheduled();
m->message_id = get_next_yet_unsent_message_id(d); // TODO support sending scheduled messages m->message_id =
is_scheduled ? get_next_yet_unsent_scheduled_message_id(d, m->date) : get_next_yet_unsent_message_id(d);
m->random_y = get_random_y(m->message_id); m->random_y = get_random_y(m->message_id);
if (!is_scheduled) { if (!is_scheduled) {
m->date = now; m->date = now;
@ -28271,9 +28285,13 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
} }
auto now = G()->unix_time(); auto now = G()->unix_time();
for (auto &m : messages) { for (auto &m : messages) {
m->message_id = get_next_yet_unsent_message_id(to_dialog); // TODO support sending scheduled messages bool is_scheduled = m->message_id.is_scheduled();
m->message_id = is_scheduled ? get_next_yet_unsent_scheduled_message_id(to_dialog, m->date)
: get_next_yet_unsent_message_id(to_dialog);
m->random_y = get_random_y(m->message_id); m->random_y = get_random_y(m->message_id);
m->date = now; if (!is_scheduled) {
m->date = now;
}
m->content = dup_message_content(td_, to_dialog_id, m->content.get(), true); m->content = dup_message_content(td_, to_dialog_id, m->content.get(), true);
m->have_previous = true; m->have_previous = true;
m->have_next = true; m->have_next = true;

View File

@ -1311,7 +1311,9 @@ class MessagesManager : public Actor {
public: public:
MessagesIterator() = default; MessagesIterator() = default;
MessagesIterator(Dialog *d, MessageId message_id) : MessagesIteratorBase(d->messages.get(), message_id) { MessagesIterator(Dialog *d, MessageId message_id)
: MessagesIteratorBase(message_id.is_scheduled() ? d->scheduled_messages.get() : d->messages.get(),
message_id) {
} }
Message *operator*() const { Message *operator*() const {
@ -1323,7 +1325,9 @@ class MessagesManager : public Actor {
public: public:
MessagesConstIterator() = default; MessagesConstIterator() = default;
MessagesConstIterator(const Dialog *d, MessageId message_id) : MessagesIteratorBase(d->messages.get(), message_id) { MessagesConstIterator(const Dialog *d, MessageId message_id)
: MessagesIteratorBase(message_id.is_scheduled() ? d->scheduled_messages.get() : d->messages.get(),
message_id) {
} }
const Message *operator*() const { const Message *operator*() const {
@ -2271,6 +2275,8 @@ class MessagesManager : public Actor {
static MessageId get_next_yet_unsent_message_id(Dialog *d); static MessageId get_next_yet_unsent_message_id(Dialog *d);
static MessageId get_next_yet_unsent_scheduled_message_id(const Dialog *d, int32 date);
bool add_recently_found_dialog_internal(DialogId dialog_id); bool add_recently_found_dialog_internal(DialogId dialog_id);
bool remove_recently_found_dialog_internal(DialogId dialog_id); bool remove_recently_found_dialog_internal(DialogId dialog_id);