ballsy study optimisation: set shapes without updating the whole chapter
Featuring backtrack recursion \o/ Falls back to logged full update in case of failure (?!) TODO: same thing for comments, adding/deleting nodes.pull/2876/head
parent
6401491d01
commit
0166d68d5c
|
@ -78,6 +78,12 @@ object BSONHandlers {
|
|||
|
||||
private implicit val FenBSONHandler = stringAnyValHandler[FEN](_.value, FEN.apply)
|
||||
|
||||
implicit val ShapesBSONHandler: BSONHandler[BSONArray, Shapes] =
|
||||
isoHandler[Shapes, List[Shape], BSONArray](
|
||||
(s: Shapes) => s.value.distinct,
|
||||
Shapes(_)
|
||||
)
|
||||
|
||||
import lila.tree.Node.{ Comment, Comments }
|
||||
private implicit val CommentIdBSONHandler = stringAnyValHandler[Comment.Id](_.value, Comment.Id.apply)
|
||||
private implicit val CommentTextBSONHandler = stringAnyValHandler[Comment.Text](_.value, Comment.Text.apply)
|
||||
|
@ -105,9 +111,6 @@ object BSONHandlers {
|
|||
private def readComments(r: Reader) =
|
||||
Comments(r.getsD[Comment]("co").filter(_.text.value.nonEmpty))
|
||||
|
||||
private def readShapes(r: Reader) =
|
||||
Shapes(r.getsD[Shape]("h"))
|
||||
|
||||
private implicit def CrazyDataBSONHandler: BSON[Crazyhouse.Data] = new BSON[Crazyhouse.Data] {
|
||||
private def writePocket(p: Crazyhouse.Pocket) = p.roles.map(_.forsyth).mkString
|
||||
private def readPocket(p: String) = Crazyhouse.Pocket(p.flatMap(chess.Role.forsyth)(scala.collection.breakOut))
|
||||
|
@ -139,7 +142,7 @@ object BSONHandlers {
|
|||
move = WithSan(r.get[Uci]("u"), r.str("s")),
|
||||
fen = r.get[FEN]("f"),
|
||||
check = r boolD "c",
|
||||
shapes = readShapes(r),
|
||||
shapes = r.getO[Shapes]("h") | Shapes.empty,
|
||||
comments = readComments(r),
|
||||
glyphs = r.getO[Glyphs]("g") | Glyphs.empty,
|
||||
crazyData = r.getO[Crazyhouse.Data]("z"),
|
||||
|
@ -167,7 +170,7 @@ object BSONHandlers {
|
|||
ply = r int "p",
|
||||
fen = r.get[FEN]("f"),
|
||||
check = r boolD "c",
|
||||
shapes = readShapes(r),
|
||||
shapes = r.getO[Shapes]("h") | Shapes.empty,
|
||||
comments = readComments(r),
|
||||
glyphs = r.getO[Glyphs]("g") | Glyphs.empty,
|
||||
clock = r.getO[Centis]("l"),
|
||||
|
|
|
@ -59,6 +59,27 @@ final class ChapterRepo(coll: Coll) {
|
|||
def setTagsFor(chapter: Chapter) =
|
||||
coll.updateField($id(chapter.id), "tags", chapter.tags).void
|
||||
|
||||
def setShapes(chapter: Chapter, path: Path, shapes: lila.tree.Node.Shapes): Option[Funit] =
|
||||
pathToField(chapter, path) map { field =>
|
||||
val shapesField = s"$field.h"
|
||||
if (shapes.value.isEmpty) coll.unsetField($id(chapter.id), shapesField).void
|
||||
else coll.updateField($id(chapter.id), shapesField, shapes).void
|
||||
}
|
||||
|
||||
// root.n[0].n[0].n[1].n[0].n[2]
|
||||
private def pathToField(chapter: Chapter, path: Path): Option[String] =
|
||||
pathToIndexes(chapter.root.children, path) map { indexes =>
|
||||
s"root.n.${indexes.mkString(".n.")}"
|
||||
}
|
||||
|
||||
// List(0, 0, 1, 0, 2)
|
||||
private def pathToIndexes(children: Node.Children, path: Path): Option[List[Int]] =
|
||||
path.split.fold(List.empty[Int].some) {
|
||||
case (head, tail) => children.getNodeAndIndex(head) flatMap {
|
||||
case (node, index) => pathToIndexes(node.children, tail).map(rest => index :: rest)
|
||||
}
|
||||
}
|
||||
|
||||
private[study] def idNamesByStudyIds(studyIds: Seq[Study.Id]): Fu[Map[Study.Id, Vector[Chapter.IdName]]] =
|
||||
coll.find(
|
||||
$doc("studyId" $in studyIds),
|
||||
|
|
|
@ -130,6 +130,11 @@ object Node {
|
|||
|
||||
def get(id: UciCharPair): Option[Node] = nodes.find(_.id == id)
|
||||
|
||||
def getNodeAndIndex(id: UciCharPair): Option[(Node, Int)] =
|
||||
nodes.zipWithIndex.collectFirst {
|
||||
case pair if pair._1.id == id => pair
|
||||
}
|
||||
|
||||
def has(id: UciCharPair): Boolean = nodes.exists(_.id == id)
|
||||
|
||||
def updateWith(id: UciCharPair, op: Node => Option[Node]): Option[Children] =
|
||||
|
|
|
@ -251,7 +251,10 @@ final class StudyApi(
|
|||
chapter.setShapes(shapes, position.path) match {
|
||||
case Some(newChapter) =>
|
||||
studyRepo.updateNow(study)
|
||||
chapterRepo.update(newChapter) >>-
|
||||
chapterRepo.setShapes(newChapter, position.path, shapes) | {
|
||||
logger.warn(s"Failed to setShapes $studyId $position")
|
||||
chapterRepo update newChapter
|
||||
} >>-
|
||||
sendTo(study, Socket.SetShapes(position, shapes, uid))
|
||||
case None => fufail(s"Invalid setShapes $position $shapes") >>- reloadUid(study, uid)
|
||||
}
|
||||
|
|
|
@ -109,6 +109,9 @@ object Node {
|
|||
def list = value
|
||||
def ++(shapes: Shapes) = Shapes(value ::: shapes.value)
|
||||
}
|
||||
object Shapes {
|
||||
val empty = Shapes(Nil)
|
||||
}
|
||||
|
||||
case class Comment(id: Comment.Id, text: Comment.Text, by: Comment.Author) {
|
||||
def removeMeta = text.removeMeta map { t =>
|
||||
|
|
Loading…
Reference in New Issue