mirror of
https://github.com/matrix-construct/construct
synced 2024-11-01 11:29:05 +01:00
305 lines
6.1 KiB
C++
305 lines
6.1 KiB
C++
|
// Matrix Construct
|
||
|
//
|
||
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||
|
//
|
||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||
|
// purpose with or without fee is hereby granted, provided that the above
|
||
|
// copyright notice and this permission notice is present in all copies. The
|
||
|
// full license for this software is available in the LICENSE file.
|
||
|
|
||
|
ircd::m::room::state::space::space(const m::room &room)
|
||
|
:room
|
||
|
{
|
||
|
room
|
||
|
}
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::prefetch(const string_view &type)
|
||
|
const
|
||
|
{
|
||
|
return prefetch(type, string_view{});
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::prefetch(const string_view &type,
|
||
|
const string_view &state_key)
|
||
|
const
|
||
|
{
|
||
|
return prefetch(type, state_key, -1);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::prefetch(const string_view &type,
|
||
|
const string_view &state_key,
|
||
|
const int64_t &depth)
|
||
|
const
|
||
|
{
|
||
|
const int64_t &_depth
|
||
|
{
|
||
|
type? depth : 0L
|
||
|
};
|
||
|
|
||
|
char buf[dbs::ROOM_STATE_SPACE_KEY_MAX_SIZE];
|
||
|
const string_view &key
|
||
|
{
|
||
|
dbs::room_state_space_key(buf, room.room_id, type, state_key, _depth, 0UL)
|
||
|
};
|
||
|
|
||
|
return db::prefetch(dbs::room_state_space, key);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::has(const string_view &type)
|
||
|
const
|
||
|
{
|
||
|
return has(type, string_view{});
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::has(const string_view &type,
|
||
|
const string_view &state_key)
|
||
|
const
|
||
|
{
|
||
|
return has(type, state_key, -1);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::has(const string_view &type,
|
||
|
const string_view &state_key,
|
||
|
const int64_t &depth)
|
||
|
const
|
||
|
{
|
||
|
return !for_each(type, state_key, depth, []
|
||
|
(const auto &type, const auto &state_key, const auto &depth, const auto &event_idx)
|
||
|
{
|
||
|
return false;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
ircd::m::room::state::space::count()
|
||
|
const
|
||
|
{
|
||
|
return count(string_view{});
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
ircd::m::room::state::space::count(const string_view &type)
|
||
|
const
|
||
|
{
|
||
|
return count(type, string_view{});
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
ircd::m::room::state::space::count(const string_view &type,
|
||
|
const string_view &state_key)
|
||
|
const
|
||
|
{
|
||
|
return count(type, state_key, -1L);
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
ircd::m::room::state::space::count(const string_view &type,
|
||
|
const string_view &state_key,
|
||
|
const int64_t &depth)
|
||
|
const
|
||
|
{
|
||
|
size_t ret(0);
|
||
|
for_each(type, state_key, depth, [&ret]
|
||
|
(const auto &type, const auto &state_key, const auto &depth, const auto &event_idx)
|
||
|
{
|
||
|
++ret;
|
||
|
return true;
|
||
|
});
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::for_each(const closure &closure)
|
||
|
const
|
||
|
{
|
||
|
return for_each(string_view{}, string_view{}, -1L, closure);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::for_each(const string_view &type,
|
||
|
const closure &closure)
|
||
|
const
|
||
|
{
|
||
|
return for_each(type, string_view{}, -1L, closure);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::for_each(const string_view &type,
|
||
|
const string_view &state_key,
|
||
|
const closure &closure)
|
||
|
const
|
||
|
{
|
||
|
return for_each(type, state_key, -1L, closure);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::room::state::space::for_each(const string_view &type,
|
||
|
const string_view &state_key,
|
||
|
const int64_t &depth,
|
||
|
const closure &closure)
|
||
|
const
|
||
|
{
|
||
|
const int64_t &_depth
|
||
|
{
|
||
|
type? depth : 0L
|
||
|
};
|
||
|
|
||
|
char buf[dbs::ROOM_STATE_SPACE_KEY_MAX_SIZE];
|
||
|
const string_view &key
|
||
|
{
|
||
|
dbs::room_state_space_key(buf, room.room_id, type, state_key, _depth, 0UL)
|
||
|
};
|
||
|
|
||
|
auto it
|
||
|
{
|
||
|
dbs::room_state_space.begin(key)
|
||
|
};
|
||
|
|
||
|
for(; it; ++it)
|
||
|
{
|
||
|
const auto &[_type, _state_key, _depth, _event_idx]
|
||
|
{
|
||
|
dbs::room_state_space_key(it->first)
|
||
|
};
|
||
|
|
||
|
if(type && type != _type)
|
||
|
break;
|
||
|
|
||
|
if(state_key && state_key != _state_key)
|
||
|
break;
|
||
|
|
||
|
if(depth >= 0 && depth != _depth)
|
||
|
break;
|
||
|
|
||
|
if(!closure(_type, _state_key, _depth, _event_idx))
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// room::state::space::rebuild
|
||
|
//
|
||
|
|
||
|
ircd::m::room::state::space::rebuild::rebuild(const room::id &room_id)
|
||
|
{
|
||
|
db::txn txn
|
||
|
{
|
||
|
*m::dbs::events
|
||
|
};
|
||
|
|
||
|
m::room::events it
|
||
|
{
|
||
|
room_id, uint64_t(0)
|
||
|
};
|
||
|
|
||
|
if(!it)
|
||
|
return;
|
||
|
|
||
|
const bool check_auth
|
||
|
{
|
||
|
!m::internal(room_id)
|
||
|
};
|
||
|
|
||
|
size_t state_count(0), messages_count(0), state_deleted(0);
|
||
|
for(; it; ++it, ++messages_count) try
|
||
|
{
|
||
|
const m::event::idx &event_idx
|
||
|
{
|
||
|
it.event_idx()
|
||
|
};
|
||
|
|
||
|
if(!state::is(std::nothrow, event_idx))
|
||
|
continue;
|
||
|
|
||
|
++state_count;
|
||
|
const m::event &event{*it};
|
||
|
const auto &[pass_static, reason_static]
|
||
|
{
|
||
|
check_auth?
|
||
|
room::auth::check_static(event):
|
||
|
room::auth::passfail{true, {}}
|
||
|
};
|
||
|
|
||
|
if(!pass_static)
|
||
|
log::dwarning
|
||
|
{
|
||
|
log, "%s in %s erased from state space (static) :%s",
|
||
|
string_view{event.event_id},
|
||
|
string_view{room_id},
|
||
|
what(reason_static),
|
||
|
};
|
||
|
|
||
|
const auto &[pass_relative, reason_relative]
|
||
|
{
|
||
|
!check_auth?
|
||
|
room::auth::passfail{true, {}}:
|
||
|
pass_static?
|
||
|
room::auth::check_relative(event):
|
||
|
room::auth::passfail{false, {}},
|
||
|
};
|
||
|
|
||
|
if(pass_static && !pass_relative)
|
||
|
log::dwarning
|
||
|
{
|
||
|
log, "%s in %s erased from state space (relative) :%s",
|
||
|
string_view{event.event_id},
|
||
|
string_view{room_id},
|
||
|
what(reason_relative),
|
||
|
};
|
||
|
|
||
|
dbs::write_opts opts;
|
||
|
opts.event_idx = event_idx;
|
||
|
|
||
|
opts.appendix.reset();
|
||
|
opts.appendix.set(dbs::appendix::ROOM_STATE_SPACE);
|
||
|
|
||
|
opts.op = pass_static && pass_relative? db::op::SET : db::op::DELETE;
|
||
|
state_deleted += opts.op == db::op::DELETE;
|
||
|
|
||
|
dbs::write(txn, event, opts);
|
||
|
}
|
||
|
catch(const ctx::interrupted &e)
|
||
|
{
|
||
|
log::dwarning
|
||
|
{
|
||
|
log, "room::state::space::rebuild :%s",
|
||
|
e.what()
|
||
|
};
|
||
|
|
||
|
throw;
|
||
|
}
|
||
|
catch(const std::exception &e)
|
||
|
{
|
||
|
log::error
|
||
|
{
|
||
|
log, "room::state::space::rebuild :%s",
|
||
|
e.what()
|
||
|
};
|
||
|
}
|
||
|
|
||
|
log::info
|
||
|
{
|
||
|
log, "room::state::space::rebuild %s complete msgs:%zu state:%zu del:%zu transaction elems:%zu size:%s",
|
||
|
string_view{room_id},
|
||
|
messages_count,
|
||
|
state_count,
|
||
|
state_deleted,
|
||
|
txn.size(),
|
||
|
pretty(iec(txn.bytes()))
|
||
|
};
|
||
|
|
||
|
txn();
|
||
|
}
|