🎨 Store shells instead of full posts in in-memory database
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / database / memory / MemoryDatabase.kt
index e943b38..e2281ac 100644 (file)
@@ -21,7 +21,8 @@ import com.google.common.base.Preconditions.checkNotNull
 import com.google.common.collect.HashMultimap
 import com.google.common.collect.Multimap
 import com.google.common.collect.TreeMultimap
-import com.google.common.util.concurrent.*
+import com.google.common.util.concurrent.AbstractService
+import com.google.common.util.concurrent.RateLimiter
 import com.google.inject.Inject
 import com.google.inject.Singleton
 import net.pterodactylus.sone.data.Album
@@ -41,10 +42,13 @@ import net.pterodactylus.sone.database.ImageBuilder
 import net.pterodactylus.sone.database.PostBuilder
 import net.pterodactylus.sone.database.PostDatabase
 import net.pterodactylus.sone.database.PostReplyBuilder
-import net.pterodactylus.sone.utils.*
+import net.pterodactylus.sone.utils.ifTrue
+import net.pterodactylus.sone.utils.unit
 import net.pterodactylus.util.config.Configuration
 import net.pterodactylus.util.config.ConfigurationException
 import java.util.concurrent.locks.ReentrantReadWriteLock
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock
 import kotlin.concurrent.withLock
 
 /**
@@ -54,14 +58,14 @@ import kotlin.concurrent.withLock
 class MemoryDatabase @Inject constructor(private val configuration: Configuration) : AbstractService(), Database {
 
        private val lock = ReentrantReadWriteLock()
-       private val readLock by lazy { lock.readLock()!! }
-       private val writeLock by lazy { lock.writeLock()!! }
+       private val readLock: ReadLock by lazy { lock.readLock() }
+       private val writeLock: WriteLock by lazy { lock.writeLock() }
        private val configurationLoader = ConfigurationLoader(configuration)
        private val allSones = mutableMapOf<String, Sone>()
-       private val allPosts = mutableMapOf<String, Post>()
-       private val sonePosts: Multimap<String, Post> = HashMultimap.create<String, Post>()
+       private val allPosts = mutableMapOf<String, MemoryPost.Shell>()
+       private val sonePosts: Multimap<String, MemoryPost.Shell> = HashMultimap.create<String, MemoryPost.Shell>()
        private val knownPosts = mutableSetOf<String>()
-       private val allPostReplies = mutableMapOf<String, PostReply>()
+       private val allPostReplies = mutableMapOf<String, MemoryPostReply.Shell>()
        private val sonePostReplies: Multimap<String, PostReply> = TreeMultimap.create<String, PostReply>(Comparator { leftString, rightString -> leftString.compareTo(rightString) }, newestReplyFirst)
        private val knownPostReplies = mutableSetOf<String>()
        private val allAlbums = mutableMapOf<String, Album>()
@@ -115,13 +119,13 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
                        removeSone(sone)
 
                        allSones[sone.id] = sone
-                       sonePosts.putAll(sone.id, sone.posts)
-                       for (post in sone.posts) {
+                       sonePosts.putAll(sone.id, sone.posts.map(Post::toShell))
+                       for (post in sone.posts.map(Post::toShell)) {
                                allPosts[post.id] = post
                        }
                        sonePostReplies.putAll(sone.id, sone.replies)
                        for (postReply in sone.replies) {
-                               allPostReplies[postReply.id] = postReply
+                               allPostReplies[postReply.id] = postReply.toShell()
                        }
                        sone.allAlbums.let { albums ->
                                soneAlbums.putAll(sone.id, albums)
@@ -189,17 +193,17 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
        override fun getFollowingTime(friendSoneId: String) =
                        memoryFriendDatabase.getFollowingTime(friendSoneId)
 
-       override fun getPost(postId: String) =
-                       readLock.withLock { allPosts[postId] }
+       override fun getPost(postId: String): Post? =
+                       readLock.withLock { allPosts[postId]?.build(newPostBuilder()) }
 
        override fun getPosts(soneId: String): Collection<Post> =
-                       sonePosts[soneId].toSet()
+                       sonePosts[soneId].map { it.build(newPostBuilder()) }.toSet()
 
        override fun getDirectedPosts(recipientId: String) =
                        readLock.withLock {
-                               allPosts.values.filter {
-                                       it.recipientId.orNull() == recipientId
-                               }
+                               allPosts.values
+                                               .filter { it.recipientId == recipientId }
+                                               .map { it.build(newPostBuilder()) }
                        }
 
        override fun newPostBuilder(): PostBuilder = MemoryPostBuilder(this, this)
@@ -207,8 +211,10 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
        override fun storePost(post: Post) {
                checkNotNull(post, "post must not be null")
                writeLock.withLock {
-                       allPosts[post.id] = post
-                       sonePosts[post.sone.id].add(post)
+                       post.toShell().also { shell ->
+                               allPosts[post.id] = shell
+                               sonePosts[post.sone.id].add(shell)
+                       }
                }
        }
 
@@ -216,17 +222,20 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
                checkNotNull(post, "post must not be null")
                writeLock.withLock {
                        allPosts.remove(post.id)
-                       sonePosts[post.sone.id].remove(post)
+                       sonePosts[post.sone.id].remove(post.toShell())
                        post.sone.removePost(post)
                }
        }
 
-       override fun getPostReply(id: String) = readLock.withLock { allPostReplies[id] }
+       override fun getPostReply(id: String) = readLock.withLock {
+               allPostReplies[id]?.build(newPostReplyBuilder())
+       }
 
        override fun getReplies(postId: String) =
                        readLock.withLock {
                                allPostReplies.values
                                                .filter { it.postId == postId }
+                                               .map { it.build(newPostReplyBuilder()) }
                                                .sortedWith(newestReplyFirst.reversed())
                        }
 
@@ -235,7 +244,7 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
 
        override fun storePostReply(postReply: PostReply) =
                        writeLock.withLock {
-                               allPostReplies[postReply.id] = postReply
+                               allPostReplies[postReply.id] = postReply.toShell()
                        }
 
        override fun removePostReply(postReply: PostReply) =
@@ -284,7 +293,7 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
        override fun isPostBookmarked(post: Post) =
                        memoryBookmarkDatabase.isPostBookmarked(post)
 
-       protected fun isPostKnown(post: Post) = readLock.withLock { post.id in knownPosts }
+       internal fun isPostKnown(post: Post) = readLock.withLock { post.id in knownPosts }
 
        fun setPostKnown(post: Post, known: Boolean): Unit =
                        writeLock.withLock {
@@ -295,14 +304,11 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
                                saveKnownPosts()
                        }
 
-       protected fun isPostReplyKnown(postReply: PostReply) = readLock.withLock { postReply.id in knownPostReplies }
+       internal fun isPostReplyKnown(postReply: PostReply) = readLock.withLock { postReply.id in knownPostReplies }
 
-       fun setPostReplyKnown(postReply: PostReply, known: Boolean): Unit =
+       override fun setPostReplyKnown(postReply: PostReply): Unit =
                        writeLock.withLock {
-                               if (known)
-                                       knownPostReplies.add(postReply.id)
-                               else
-                                       knownPostReplies.remove(postReply.id)
+                               knownPostReplies.add(postReply.id)
                                saveKnownPostReplies()
                        }