kopia lustrzana https://github.com/twitter/the-algorithm
151 wiersze
4.7 KiB
Scala
151 wiersze
4.7 KiB
Scala
package com.twitter.tweetypie.storage
|
|
|
|
import com.twitter.finagle.stats.StatsReceiver
|
|
import com.twitter.stitch.Stitch
|
|
import com.twitter.storage.client.manhattan.kv.DeniedManhattanException
|
|
import com.twitter.tweetypie.storage.Response.TweetResponseCode
|
|
import com.twitter.tweetypie.storage.TweetUtils._
|
|
import com.twitter.tweetypie.storage_internal.thriftscala.StoredTweet
|
|
import com.twitter.tweetypie.thriftscala.DeletedTweet
|
|
import scala.util.control.NonFatal
|
|
|
|
sealed trait DeleteState
|
|
object DeleteState {
|
|
|
|
/**
|
|
* This tweet is deleted but has not been permanently deleted from Manhattan. Tweets in this state
|
|
* may be undeleted.
|
|
*/
|
|
case object SoftDeleted extends DeleteState
|
|
|
|
/**
|
|
* This tweet is deleted after being bounced for violating the Twitter Rules but has not been
|
|
* permanently deleted from Manhattan. Tweets in this state may NOT be undeleted.
|
|
*/
|
|
case object BounceDeleted extends DeleteState
|
|
|
|
/**
|
|
* This tweet has been permanently deleted from Manhattan.
|
|
*/
|
|
case object HardDeleted extends DeleteState
|
|
|
|
/**
|
|
* There is no data in Manhattan to distinguish this tweet id from one that never existed.
|
|
*/
|
|
case object NotFound extends DeleteState
|
|
|
|
/**
|
|
* This tweet exists and is not in a deleted state.
|
|
*/
|
|
case object NotDeleted extends DeleteState
|
|
}
|
|
|
|
case class DeletedTweetResponse(
|
|
tweetId: TweetId,
|
|
overallResponse: TweetResponseCode,
|
|
deleteState: DeleteState,
|
|
tweet: Option[DeletedTweet])
|
|
|
|
object GetDeletedTweetsHandler {
|
|
def apply(
|
|
read: ManhattanOperations.Read,
|
|
stats: StatsReceiver
|
|
): TweetStorageClient.GetDeletedTweets =
|
|
(unfilteredTweetIds: Seq[TweetId]) => {
|
|
val tweetIds = unfilteredTweetIds.filter(_ > 0)
|
|
|
|
Stats.addWidthStat("getDeletedTweets", "tweetIds", tweetIds.size, stats)
|
|
|
|
val stitches = tweetIds.map { tweetId =>
|
|
read(tweetId)
|
|
.map { mhRecords =>
|
|
val storedTweet = buildStoredTweet(tweetId, mhRecords)
|
|
|
|
TweetStateRecord.mostRecent(mhRecords) match {
|
|
case Some(m: TweetStateRecord.SoftDeleted) => softDeleted(m, storedTweet)
|
|
case Some(m: TweetStateRecord.BounceDeleted) => bounceDeleted(m, storedTweet)
|
|
case Some(m: TweetStateRecord.HardDeleted) => hardDeleted(m, storedTweet)
|
|
case _ if storedTweet.getFieldBlobs(expectedFields).isEmpty => notFound(tweetId)
|
|
case _ => notDeleted(tweetId, storedTweet)
|
|
}
|
|
}
|
|
.handle {
|
|
case _: DeniedManhattanException =>
|
|
DeletedTweetResponse(
|
|
tweetId,
|
|
TweetResponseCode.OverCapacity,
|
|
DeleteState.NotFound,
|
|
None
|
|
)
|
|
|
|
case NonFatal(ex) =>
|
|
TweetUtils.log.warning(
|
|
ex,
|
|
s"Unhandled exception in GetDeletedTweetsHandler for tweetId: $tweetId"
|
|
)
|
|
DeletedTweetResponse(tweetId, TweetResponseCode.Failure, DeleteState.NotFound, None)
|
|
}
|
|
}
|
|
|
|
Stitch.collect(stitches)
|
|
}
|
|
|
|
private def notFound(tweetId: TweetId) =
|
|
DeletedTweetResponse(
|
|
tweetId = tweetId,
|
|
overallResponse = TweetResponseCode.Success,
|
|
deleteState = DeleteState.NotFound,
|
|
tweet = None
|
|
)
|
|
|
|
private def softDeleted(record: TweetStateRecord.SoftDeleted, storedTweet: StoredTweet) =
|
|
DeletedTweetResponse(
|
|
record.tweetId,
|
|
TweetResponseCode.Success,
|
|
DeleteState.SoftDeleted,
|
|
Some(
|
|
StorageConversions
|
|
.toDeletedTweet(storedTweet)
|
|
.copy(deletedAtMsec = Some(record.createdAt))
|
|
)
|
|
)
|
|
|
|
private def bounceDeleted(record: TweetStateRecord.BounceDeleted, storedTweet: StoredTweet) =
|
|
DeletedTweetResponse(
|
|
record.tweetId,
|
|
TweetResponseCode.Success,
|
|
DeleteState.BounceDeleted,
|
|
Some(
|
|
StorageConversions
|
|
.toDeletedTweet(storedTweet)
|
|
.copy(deletedAtMsec = Some(record.createdAt))
|
|
)
|
|
)
|
|
|
|
private def hardDeleted(record: TweetStateRecord.HardDeleted, storedTweet: StoredTweet) =
|
|
DeletedTweetResponse(
|
|
record.tweetId,
|
|
TweetResponseCode.Success,
|
|
DeleteState.HardDeleted,
|
|
Some(
|
|
StorageConversions
|
|
.toDeletedTweet(storedTweet)
|
|
.copy(
|
|
hardDeletedAtMsec = Some(record.createdAt),
|
|
deletedAtMsec = Some(record.deletedAt)
|
|
)
|
|
)
|
|
)
|
|
|
|
/**
|
|
* notDeleted returns a tweet to simplify tweetypie.handler.UndeleteTweetHandler
|
|
*/
|
|
private def notDeleted(tweetId: TweetId, storedTweet: StoredTweet) =
|
|
DeletedTweetResponse(
|
|
tweetId = tweetId,
|
|
overallResponse = TweetResponseCode.Success,
|
|
deleteState = DeleteState.NotDeleted,
|
|
tweet = Some(StorageConversions.toDeletedTweet(storedTweet))
|
|
)
|
|
}
|