in entity-store/src/main/kotlin/jetbrains/exodus/entitystore/PersistentEntityStoreRefactorings.kt [288:439]
fun refactorAddMissedLinks() {
store.executeInReadonlyTransaction { txn ->
txn as PersistentStoreTransaction
for (entityType in store.getEntityTypes(txn)) {
logInfo("Refactoring restoring missed links in [$entityType]")
runReadonlyTransactionSafeForEntityType(entityType) {
val missedLinks = ArrayList<Pair<ByteIterable, ByteIterable>>()
val entityTypeId = store.getEntityTypeId(txn, entityType, false)
val linksTable = store.getLinksTable(txn, entityTypeId)
val envTxn = txn.environmentTransaction
val missedLinkTypes = IntHashSet()
linksTable.getFirstIndexCursor(envTxn).use { cursor ->
while (cursor.next) {
val first = cursor.key
val second = cursor.value
var linkValue: LinkValue? = null
try {
linkValue = LinkValue.entryToLinkValue(second)
} catch (ignore: Exception) {
}
if (linkValue != null) {
if (!linksTable.contains2(envTxn, first, second)) {
var propertyKey: PropertyKey? = null
try {
propertyKey = PropertyKey.entryToPropertyKey(first)
} catch (ignore: Exception) {
}
try {
txn.getEntity(linkValue.entityId)
} catch (e: Exception) {
linkValue = null
}
if (linkValue != null) {
try {
store.getEntityType(txn, linkValue.entityId.typeId)
} catch (e: Exception) {
linkValue = null
}
}
if (propertyKey != null && linkValue != null) {
val targetEntityId = linkValue.entityId
missedLinkTypes.add(targetEntityId.typeId)
missedLinks.add(ArrayByteIterable(first) to ArrayByteIterable(second))
}
}
}
}
}
if (missedLinks.isNotEmpty()) {
store.environment.executeInExclusiveTransaction { txn ->
for (missedLink in missedLinks) {
val propertyKey = PropertyKey.entryToPropertyKey(missedLink.first)
linksTable.put(
txn, propertyKey.entityLocalId, missedLink.second, true,
propertyKey.propertyId
)
}
}
val redundantLinkTypeNames = HashSet<String>(missedLinkTypes.size)
for (typeId in missedLinkTypes) {
redundantLinkTypeNames.add(store.getEntityType(txn, typeId))
}
logInfo(
missedLinks.size.toString() + " links missing in second " +
"table found for [" + entityType + " ] and targets: $redundantLinkTypeNames and fixed"
)
missedLinks.clear()
missedLinkTypes.clear()
}
linksTable.getSecondIndexCursor(envTxn).use { cursor ->
while (cursor.next) {
val second = cursor.key
val first = cursor.value
var linkValue: LinkValue? = null
try {
linkValue = LinkValue.entryToLinkValue(second)
} catch (ignore: Exception) {
}
if (linkValue != null) {
if (!linksTable.contains(envTxn, first, second)) {
var propertyKey: PropertyKey? = null
try {
propertyKey = PropertyKey.entryToPropertyKey(first)
} catch (ignore: Exception) {
}
try {
txn.getEntity(linkValue!!.entityId)
} catch (e: Exception) {
linkValue = null
}
if (linkValue != null) {
try {
store.getEntityType(txn, linkValue!!.entityId.typeId)
} catch (e: Exception) {
linkValue = null
}
}
if (propertyKey != null && linkValue != null) {
val targetEntityId = linkValue!!.entityId
missedLinks.add(ArrayByteIterable(first) to ArrayByteIterable(second))
missedLinkTypes.add(targetEntityId.typeId)
}
}
}
}
}
if (missedLinks.isNotEmpty()) {
store.environment.executeInExclusiveTransaction { txn ->
for (missedLink in missedLinks) {
val propertyKey = PropertyKey.entryToPropertyKey(missedLink.first)
linksTable.put(
txn, propertyKey.entityLocalId, missedLink.second, true,
propertyKey.propertyId
)
}
}
val redundantLinkTypeNames = HashSet<String>(missedLinkTypes.size)
for (typeId in missedLinkTypes) {
redundantLinkTypeNames.add(store.getEntityType(txn, typeId))
}
logInfo(
"${missedLinks.size} links missing in first table found for [$entityType] " +
"and targets: $redundantLinkTypeNames and fixed"
)
}
}
}
}
}