New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow migration of entity between shards #755
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
misk-hibernate/src/main/kotlin/misk/hibernate/CowritesDetector.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package misk.hibernate | ||
|
||
interface CowritesDetector { | ||
|
||
fun pushSuppressChecks() | ||
fun popSuppressChecks() | ||
|
||
companion object { | ||
val NONE: CowritesDetector = object : CowritesDetector { | ||
override fun pushSuppressChecks() {} | ||
|
||
override fun popSuppressChecks() {} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
misk-hibernate/src/main/kotlin/misk/hibernate/EntityGroupTransactionOrder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package misk.hibernate | ||
|
||
/** | ||
* Vitess multi shard transactions are guaranteed to be committed in the order that updates are | ||
* issued. So if you have entity groups A and B, you issue an update against A followed by an | ||
* update to B, then the transaction against the shard of A will be fully committed before the | ||
* transaction against the shard of B. You can use this fact to make cross shard transactions safe | ||
* by committing clean up tasks to the earlier shards. | ||
*/ | ||
interface EntityGroupTransactionOrder { | ||
/** | ||
* Issues a "spurious"/empty update on the entity group root to enforce a transaction to be | ||
* started on that entity group. | ||
*/ | ||
fun <P: DbRoot<P>> start(session: Session, entityGroup: P) | ||
|
||
/** | ||
* Checks that the transaction of the "leader" entity group will commit before the transaction of | ||
* the "follower" entity group. | ||
*/ | ||
fun <P: DbRoot<P>> assertOrder(session: Session, leader: Id<P>, follower: Id<P>) | ||
|
||
/** | ||
* Suppress checks. | ||
* | ||
* Should be used like this to suppress checks of code that we deliberately do not need to be | ||
* safe: | ||
* <pre> | ||
* transactionOrder.pushSuppressChecks(); | ||
* try { | ||
* // unsafe code | ||
* } finally { | ||
* transactionOrder.popSuppressChecks(); | ||
* } | ||
</pre> * | ||
*/ | ||
fun pushSuppressChecks() | ||
|
||
/** | ||
* Enable checks again. | ||
*/ | ||
fun popSuppressChecks() | ||
} | ||
|
11 changes: 11 additions & 0 deletions
11
misk-hibernate/src/main/kotlin/misk/hibernate/EntityGroups.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package misk.hibernate | ||
|
||
class EntityGroups { | ||
fun entityGroupId(entity: Any): Id<*>? { | ||
return when (entity) { | ||
is DbRoot<*> -> entity.id | ||
is DbChild<*, *> -> entity.rootId | ||
else -> null | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
misk-hibernate/src/main/kotlin/misk/hibernate/PersistenceMetadata.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package misk.hibernate | ||
|
||
import com.google.common.collect.ImmutableSet | ||
import com.google.inject.ImplementedBy | ||
|
||
/** Persistence related metadata */ | ||
@ImplementedBy(PersistenceMetadataImpl::class) | ||
interface PersistenceMetadata { | ||
/** Gets the table name for the given class */ | ||
fun <T: DbEntity<T>> getTableName(entityType: T): String | ||
|
||
/** Returns all of the columns of `entityType`. */ | ||
fun <T: DbEntity<T>> getColumnNames(entityType: T): ImmutableSet<String> | ||
|
||
/** | ||
* Gets the column names for the given class and property name. Multiple names | ||
* can be returned since single properties can be mapped to multiple columns. | ||
*/ | ||
fun <T: DbEntity<T>> getColumnNames(entityType: T, propertyName: String): Array<String> | ||
} |
59 changes: 59 additions & 0 deletions
59
misk-hibernate/src/main/kotlin/misk/hibernate/PersistenceMetadataImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package misk.hibernate | ||
|
||
import com.google.common.collect.ImmutableSet | ||
import javax.inject.Inject | ||
import org.hibernate.SessionFactory | ||
import org.hibernate.persister.entity.AbstractEntityPersister | ||
|
||
import com.google.common.base.Preconditions.checkState | ||
|
||
internal class PersistenceMetadataImpl @Inject constructor( | ||
private val sessionFactory: SessionFactory | ||
) : PersistenceMetadata { | ||
|
||
override fun <T: DbEntity<T>> getTableName(entityType: T): String { | ||
return hibernateMetadataForClass(entityType).tableName | ||
} | ||
|
||
override fun <T: DbEntity<T>> getColumnNames( | ||
entityType: T | ||
): ImmutableSet<String> { | ||
val result = ImmutableSet.builder<String>() | ||
val classMetadata = hibernateMetadataForClass(entityType) | ||
|
||
for (column in classMetadata.identifierColumnNames) { | ||
result.add(column) | ||
} | ||
|
||
val propertyNames = classMetadata.propertyNames | ||
|
||
for (i in propertyNames.indices) { | ||
result.add(*classMetadata.getPropertyColumnNames(i)) | ||
} | ||
|
||
return result.build() | ||
} | ||
|
||
override fun <T: DbEntity<T>> getColumnNames( | ||
entityType: T, | ||
propertyName: String | ||
): Array<String> { | ||
return hibernateMetadataForClass(entityType).getPropertyColumnNames(propertyName) | ||
} | ||
|
||
private fun <T: DbEntity<T>> hibernateMetadataForClass( | ||
entityType: T | ||
): AbstractEntityPersister { | ||
val hibernateMetadata = sessionFactory.getClassMetadata(entityType::class.qualifiedName) | ||
|
||
checkState(hibernateMetadata != null, | ||
"${entityType::class.qualifiedName} does not map to a known entity type" | ||
) | ||
|
||
checkState(hibernateMetadata is AbstractEntityPersister, | ||
"${entityType::class.qualifiedName} does not map to a persistent class" | ||
) | ||
|
||
return hibernateMetadata as AbstractEntityPersister | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
misk-hibernate/src/main/kotlin/misk/hibernate/ShardMigrator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package misk.hibernate | ||
|
||
import javax.inject.Inject | ||
|
||
/** | ||
* This class changes the parent id of an entity group child (the customer id, for example). | ||
* | ||
* This may result in the entity group child migrating between shards as the child will always | ||
* end up on the same shard as the parent. | ||
*/ | ||
class ShardMigrator { | ||
@Inject private lateinit var transacter: Transacter | ||
@Inject private lateinit var transactionOrderListener: EntityGroupTransactionOrder | ||
|
||
fun <P : DbRoot<P>, C : DbChild<P, C>> migrate( | ||
child: C, | ||
oldParentId: Id<P>, | ||
newParentId: Id<P> | ||
): C { | ||
return transacter.transaction { | ||
transactionOrderListener!!.assertOrder(it, newParentId, oldParentId) | ||
updateParent(it, child, newParentId) | ||
} | ||
} | ||
|
||
private fun <P : DbRoot<P>, C : DbChild<P, C>> updateParent( | ||
session: Session, | ||
child: C, | ||
newParentId: Id<P> | ||
): C { | ||
return transacter.transaction { | ||
val newChild = child.migrate(this, it, newParentId) | ||
session.delete(child) | ||
session.flush() | ||
session.save(newChild) | ||
newChild | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm having a hard time following how this works since this does not have an impl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, please ignore this PR for now .. implementation coming!