WeebWare / Ranobe-Honyaku

A novel translation platform.
MIT License
8 stars 2 forks source link

Chapter/Volume Ordering (suggestion) #9

Open cloudiirain opened 7 years ago

cloudiirain commented 7 years ago

Overview

Within a series, chapters and volumes need to be ordered. Furthermore, the ordering should be relatively flexible and easy to do (meaning, it shouldn't take a billion ajax requests to reorder chapters).

Note: Important reminder! Web novels don't have volumes! But they may be organized in arcs!

I'll give example:

Series: My Little Sister Can't Program

Volume 1 (order=0)

Bonus Chapter not contained within a volume (order=2) Another bonus chapter that came in a drama CD (order=3)

Volume EX BONUS (order=4)

Basically I'm suggesting that volumes have an order value assigned, and chapters have an order value assigned programmatically by us.

Zero-based ordering occurs at two levels: a root level ordering, and a volume-level ordering. Volume order always refers to the root level. Chapter order refers to volume-level ordering, unless it has no associated volume in which case the order refers to the root level ordering.

API implementation

Since it would be absurd to send an AJAX request to update every single chapter/volume in a series when something is inserted/moved, we need to write our own implementation. My suggested pseudocode is roughly as follows:

When a volume or chapter is saved (via AJAX/API endpoint), check the submitted order value. If something already exists at that position, insert the new chapter at that position, and sequentially update the order/position/index of all the other chapters with a higher or equal value.

If nothing exists at the position, assign the lowest unused order value.

When a volume or chapter is deleted (via AJAX/API endpoint), update the order values of everything after this volume/chapter.

Feedback?

I'm aware that this type of implementation might be subject to race conditions if many re-ordering/insert requests within a volume are happening at once. To avoid race conditions (and unwieldy computations on the server), we may want to implement a separate mechanism for bulk insert or bulk update.

However, I don't know of a better way to do this.

Fuyukai commented 7 years ago

Because Flask and lol not async codedatabase locks, those race conditions are incredibly easy to avoid if you check the positions before updating.

cloudiirain commented 7 years ago

Thanks for the feedback!

I know Flask isn't async and postgres does use database locks, but was unsure how Flask-SQLalchemy translates in terms of database locks.

For instance, if I do something like:

chapter_list = [Chapter.query.somekindofquery()]
for chapter in chapter_list:
    chapter.order = chapter.order + 1
db.session.commit()

Does a lock get placed on the current record one at a time, or does the lock get placed on all of the records being committed? Versus, for example:

chapter_list = [Chapter.query.somekindofquery()]
for chapter in chapter_list:
    chapter.order = chapter.order + 1
    db.session.commit()

Probably doesn't mean anything and is never probably going to happen... just wanted to be conscious of writing code that won't corrupt the stored data because of some odd situation (like someone running the db in a terminal session or running a script that bypasses our ordering logic or something).

In the above code example, I think it may be better to do something like:

chapter_list = [Chapter.query.somekindofquery()]
i = some_init_value
for chapter in chapter_list.sort():
    if not chapter.order == i - 1:
          # abort this commit if the chapter order value isn't what you expect it to be
          # or attempt to recover/fix this corrupted data
    chapter.order = i
    i = i + 1
db.session.commit()

...or are all of these precautions unnecessary?

danieltanfh95 commented 7 years ago

I think it would be easier if we just lock the volume while someone is editing it. Race conditions will appear when two users update two different chapters, but same order number at the same time. It's saner to allow all new chapters to be appended the end of the chapter list, and then only allow one person to push one change to the server at one time for volume reordering and organization.

I.E. When someone submits a change for the volume, the page first calls to the server to check if what is shown is the same as the one in the database. If yes, push the change. If not, reloads the page and reminds the user that the page has been changed.

Submit change -> checks hash from the server for that volume/chapter with the current one -> same then submits change / not same then reloads page and notify user that page has changed.

While reloading, like the original is [vol1,vol4,vol3] and if one submits [vol1, vol3, vo4], but the server has changed to [vol1,vol2,vol4], the change is preserved to follow the element right after the submitted element, i.e. the page reloaded will show [vol1,vol2,vol3,vol4].