state_account_settings_runtime.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. #include "../account/settings/settings_delta.h"
  2. #include "runtime.h"
  3. #include "storage/internal.h"
  4. namespace sunrise::state {
  5. /** Builds a complete checked settings candidate without changing authoritative State. */
  6. SettingsUpdateDisposition prepare_settings_update(const account::settings::SettingsDelta& delta,
  7. PendingSettingsUpdate& mutation) noexcept {
  8. mutation = {};
  9. const AccountState current = account_snapshot();
  10. if (!account::valid(current)) {
  11. return SettingsUpdateDisposition::rejected;
  12. }
  13. account::settings::AccountSettings after{};
  14. bool changed = false;
  15. if (!account::settings::apply_delta(delta, current.settings, after, changed)) {
  16. return SettingsUpdateDisposition::rejected;
  17. }
  18. if (!changed) {
  19. return SettingsUpdateDisposition::acceptedNoChange;
  20. }
  21. mutation.beforeSettings = current.settings;
  22. mutation.afterSettings = after;
  23. mutation.accountSoid = current.primarySoid;
  24. mutation.prepared = true;
  25. return SettingsUpdateDisposition::preparedMutation;
  26. }
  27. /** Commits a prepared settings image only while its account and settings view remain current. */
  28. bool commit_settings_update(PendingSettingsUpdate& mutation) noexcept {
  29. const PendingSettingsUpdate prepared = mutation;
  30. mutation = {};
  31. if (!prepared.prepared || prepared.accountSoid == 0
  32. || prepared.beforeSettings == prepared.afterSettings
  33. || !account::settings::valid(prepared.beforeSettings)
  34. || !account::settings::valid(prepared.afterSettings)) {
  35. return false;
  36. }
  37. AcquireSRWLockExclusive(&runtime::storage::g_stateLock);
  38. AccountState candidate = runtime::storage::g_state.account;
  39. bool committed = false;
  40. if (candidate.primarySoid == prepared.accountSoid) {
  41. if (candidate.settings == prepared.afterSettings) {
  42. // A second identical transaction may observe the first one's completed after-image.
  43. committed = account::valid(candidate);
  44. } else if (candidate.settings == prepared.beforeSettings) {
  45. candidate.settings = prepared.afterSettings;
  46. if (account::valid(candidate)) {
  47. runtime::storage::g_state.account = candidate;
  48. committed = true;
  49. }
  50. }
  51. }
  52. ReleaseSRWLockExclusive(&runtime::storage::g_stateLock);
  53. return committed;
  54. }
  55. } // namespace sunrise::state