landed fixseen and got rid of all explicit LOCK TABLES operations (not needed in modern MySQL, especially with transaction semantics)

This commit is contained in:
2026-01-30 18:20:58 -07:00
parent f8e7816f62
commit a0d3f3715a
8 changed files with 87 additions and 76 deletions
+18
View File
@@ -184,6 +184,24 @@ func SetPseud(ctxt ui.AmContext) (string, any, error) {
return "redirect", fmt.Sprintf("/comm/%s/conf/%s/manage", comm.Alias, ctxt.GetScratch("currentAlias")), nil
}
/* ConfFixseen marks all messages in a conference as read.
* Parameters:
* ctxt - The AmContext for the request.
* Returns:
* Command string dictating what to be rendered.
* Data as a parameter for the command string.
* Standard Go error status.
*/
func ConfFixseen(ctxt ui.AmContext) (string, any, error) {
comm := ctxt.CurrentCommunity()
conf := ctxt.GetScratch("currentConference").(*database.Conference)
err := conf.Fixseen(ctxt.Ctx(), ctxt.CurrentUser())
if err != nil {
return ui.ErrorPage(ctxt, err)
}
return "redirect", fmt.Sprintf("/comm/%s/conf/%s/manage", comm.Alias, ctxt.GetScratch("currentAlias")), nil
}
/* AddToHotlist adds the current community and conference to the user's hotlist..
* Parameters:
* ctxt - The AmContext for the request.
+65
View File
@@ -347,6 +347,71 @@ func (c *Conference) UnreadMessages(ctx context.Context, u *User) (int32, error)
return rc, err
}
// fixseenData is a temporary structure used in assisting with Fixseen.
type fixseenData struct {
topicid int32
topmessage int32
insert bool
}
// Fixseen marks all messages in a conference as read.
func (c *Conference) Fixseen(ctx context.Context, u *User) error {
if u.IsAnon {
return nil
}
success := false
tx := amdb.MustBegin()
defer func() {
if !success {
tx.Rollback()
}
}()
// Get a count of topics beforehand.
row := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM topics WHERE confid = ?", c.ConfId)
count := 0
err := row.Scan(&count)
if err != nil {
return err
}
// Build the list of all topics.
rs, err := tx.QueryContext(ctx, `SELECT t.topicid, t.top_message, ISNULL(s.last_message) FROM topics t
LEFT JOIN topicsettings s ON t.topicid = s.topicid AND s.uid = ? WHERE t.confid = ?`, u.Uid, c.ConfId)
if err != nil {
return err
}
work := make([]fixseenData, 0, count)
for rs.Next() {
var d fixseenData
err = rs.Scan(&(d.topicid), &(d.topmessage), &(d.insert))
work = append(work, d)
}
// Adjust each topic in turn.
for _, d := range work {
if d.insert {
_, err = tx.ExecContext(ctx, "INSERT INTO topicsettings (topicid, uid, last_message, last_read) VALUES (?, ?, ?, NOW())", d.topicid, u.Uid, d.topmessage)
} else {
_, err = tx.ExecContext(ctx, "UPDATE topicsettings SET last_message = ?, last_read = NOW() WHERE topicid = ? AND uid = ?", d.topmessage, d.topicid, u.Uid)
}
if err != nil {
return err
}
}
// Also update last-read in conference.
if _, err = c.TouchRead(ctx, tx, u); err != nil {
return err
}
if err = tx.Commit(); err != nil {
return err
}
success = true
return nil
}
/* AmGetConference returns a conference given its ID.
* Parameters:
* ctx - Standard Go context value.
-41
View File
@@ -284,14 +284,6 @@ func (p *PostHeader) Scribble(ctx context.Context, u *User, ipaddr string) error
tx.Rollback()
}
}()
unlock := true
tx.ExecContext(ctx, "LOCK TABLES posts WRITE, postdata WRITE, postattach WRITE, postpublish WRITE;")
defer func() {
if unlock {
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Scribble on the post header.
scribblePseud := "<EM><B>(Scribbled)</B></EM>" // FUTURE: configurable option
_, err := tx.ExecContext(ctx, "UPDATE posts SET linecount = 0, hidden = 0, scribble_uid = ?, scribble_date = NOW(), pseud = ? WHERE postid = ?", u.Uid, scribblePseud, p.PostId)
@@ -318,9 +310,6 @@ func (p *PostHeader) Scribble(ctx context.Context, u *User, ipaddr string) error
return err
}
// Unlock tables and commit.
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
if err = tx.Commit(); err != nil {
return err
}
@@ -353,13 +342,6 @@ func (p *PostHeader) Nuke(ctx context.Context, u *User, ipaddr string) error {
tx.Rollback()
}
}()
unlock := true
tx.ExecContext(ctx, "LOCK TABLES posts WRITE, postdata WRITE, postattach WRITE, postdogear WRITE, postpublish WRITE, topics WRITE, topicsettings WRITE;")
defer func() {
if unlock {
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Delete all the references to this post.
_, err := tx.ExecContext(ctx, "DELETE FROM posts WHERE postid = ?", p.PostId)
@@ -399,9 +381,6 @@ func (p *PostHeader) Nuke(ctx context.Context, u *User, ipaddr string) error {
return err
}
// Unlock tables and commit.
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
if err = tx.Commit(); err != nil {
return err
}
@@ -486,13 +465,6 @@ func (p *PostHeader) MoveTo(ctx context.Context, target *Topic, u *User, ipaddr
tx.Rollback()
}
}()
unlock := true
tx.ExecContext(ctx, "LOCK TABLES confs WRITE, topics WRITE, posts WRITE, topicsettings WRITE;")
defer func() {
if unlock {
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Adjust post record in the database to make it part of the new topic.
_, err = tx.ExecContext(ctx, "UPDATE posts SET parent = 0, topicid = ?, num = ? WHERE postid = ?", target.TopicId, target.TopMessage+1, p.PostId)
@@ -534,9 +506,6 @@ func (p *PostHeader) MoveTo(ctx context.Context, target *Topic, u *User, ipaddr
return err
}
// Unlock tables and commit.
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
if err = tx.Commit(); err != nil {
return err
}
@@ -625,13 +594,6 @@ func AmNewPost(ctx context.Context, conf *Conference, topic *Topic, user *User,
tx.Rollback()
}
}()
unlock := true
tx.ExecContext(ctx, "LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, posts WRITE, postdata WRITE;")
defer func() {
if unlock {
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Add the post header information.
rs, err := tx.ExecContext(ctx, "INSERT INTO posts (topicid, num, linecount, creator_uid, posted, pseud) VALUES (?, ?, ?, ?, NOW(), ?)",
@@ -671,9 +633,6 @@ func AmNewPost(ctx context.Context, conf *Conference, topic *Topic, user *User,
topic.TopMessage = hdr.Num
topic.LastUpdate = hdr.Posted
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
// update the "last update" date of the conference and the "last posted" date in the conference settings
if err = conf.TouchUpdate(ctx, tx, hdr.Posted); err != nil {
return nil, err
+1 -23
View File
@@ -349,14 +349,6 @@ func (t *Topic) Delete(ctx context.Context, u *User, ipaddr string, background *
}
}()
unlock := true
tx.ExecContext(ctx, "LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, topicbozo WRITE;")
defer func() {
if unlock {
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
conf, err := AmGetConference(ctx, t.ConfId)
if err != nil {
return err
@@ -373,12 +365,9 @@ func (t *Topic) Delete(ctx context.Context, u *User, ipaddr string, background *
return err
}
err = conf.TouchUpdate(ctx, tx, time.Now())
if err != nil {
if err = conf.TouchUpdate(ctx, tx, time.Now()); err != nil {
return err
}
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
if err = tx.Commit(); err != nil {
return err
}
@@ -670,14 +659,6 @@ func AmNewTopic(ctx context.Context, conf *Conference, user *User, title string,
}
}()
unlock := true
tx.ExecContext(ctx, "LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, posts WRITE, postdata WRITE;")
defer func() {
if unlock {
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Insert the new topic into the database.
conf.Mutex.Lock()
rs, err := tx.ExecContext(ctx, "INSERT INTO topics (confid, num, creator_uid, createdate, lastupdate, name) VALUES (?, ?, ?, NOW(), NOW(), ?)",
@@ -732,9 +713,6 @@ func AmNewTopic(ctx context.Context, conf *Conference, user *User, title string,
return nil, err
}
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
// update the "last posted" date in the conference settings
_, err = conf.TouchPost(ctx, tx, user, topic.CreateDate)
if err != nil {
-10
View File
@@ -694,13 +694,6 @@ func AmCreateNewUser(ctx context.Context, username string, password string, remi
tx.Rollback()
}
}()
unlock := true
tx.ExecContext(ctx, "LOCK TABLES users WRITE, userprefs WRITE, propuser WRITE, commmember WRITE, sideboxes WRITE, confhotlist WRITE;")
defer func() {
if unlock {
tx.ExecContext(ctx, "UNLOCK TABLES;")
}
}()
// Test if the user name is already taken.
row := tx.QueryRowContext(ctx, "SELECT uid FROM users WHERE username = ?", username)
@@ -749,9 +742,6 @@ func AmCreateNewUser(ctx context.Context, username string, password string, remi
return nil, err
}
tx.ExecContext(ctx, "UNLOCK TABLES;")
unlock = false
if err = tx.Commit(); err != nil {
return nil, err
}
+1 -1
View File
@@ -54,7 +54,7 @@ _(italicized items can be deferred)_
- Find
- Manage:
- ~~Set pseud~~
- Fixseen
- ~~Fixseen~~
- ~~Send invite~~
- Change information
- Manage aliases
+1
View File
@@ -105,6 +105,7 @@ func setupEcho() *echo.Echo {
confGroup.POST("/new_topic", ui.AmWrap(NewTopic))
confGroup.GET("/manage", ui.AmWrap(ConfManage))
confGroup.POST("/pseud", ui.AmWrap(SetPseud))
confGroup.GET("/fixseen", ui.AmWrap(ConfFixseen))
confGroup.GET("/hotlist", ui.AmWrap(AddToHotlist))
confGroup.GET("/invite", ui.AmWrap(InviteToConference))
confGroup.GET("/r/:topic", ui.AmWrap(ReadPosts), ui.SetTopic)
+1 -1
View File
@@ -32,7 +32,7 @@
<!-- Fixseen link -->
<div class="mb-4">
<a class="text-blue-700 hover:text-blue-900 text-sm font-bold" href="/TODO/{{ urlStem }}/fixseen">Mark entire conference as read (fixseen)</a>
<a class="text-blue-700 hover:text-blue-900 text-sm font-bold" href="{{ urlStem }}/fixseen">Mark entire conference as read (fixseen)</a>
</div>
{{ if canInvite }}