Skip to content
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

#80: Minimal compatibility: Return YDB SDK's YdbTransaction from YOJ's YdbRepositoryTransaction #87

Merged
merged 1 commit into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tech.ydb.yoj.repository.ydb;

import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Iterables;
import io.grpc.Context;
Expand All @@ -8,6 +9,8 @@
import lombok.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.ydb.common.transaction.TxMode;
import tech.ydb.common.transaction.YdbTransaction;
import tech.ydb.core.Result;
import tech.ydb.core.Status;
import tech.ydb.core.StatusCode;
Expand All @@ -27,6 +30,7 @@
import tech.ydb.table.values.StructValue;
import tech.ydb.table.values.TupleValue;
import tech.ydb.table.values.Value;
import tech.ydb.yoj.ExperimentalApi;
import tech.ydb.yoj.repository.BaseDb;
import tech.ydb.yoj.repository.db.Entity;
import tech.ydb.yoj.repository.db.IsolationLevel;
Expand Down Expand Up @@ -59,10 +63,12 @@
import tech.ydb.yoj.repository.ydb.table.YdbTable;
import tech.ydb.yoj.util.lang.Interrupts;

import javax.annotation.Nullable;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -575,4 +581,42 @@ public String toString() {
}
});
}

/**
* @return YDB SDK {@link YdbTransaction} wrapping this {@code YdbRepositoryTransaction}
*/
@ExperimentalApi(issue = "https://github.com/ydb-platform/yoj-project/issues/80")
public YdbTransaction toSdkTransaction() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an option: we could add RepositoryTransaction.toNativeTransacton to avoid explicit casting.

Anyway, changes are approved.

return new YdbTransaction() {
@Nullable
@Override
public String getId() {
return txId;
}

@Override
public TxMode getTxMode() {
return switch (options.getIsolationLevel()) {
case SERIALIZABLE_READ_WRITE -> TxMode.SERIALIZABLE_RW;
case ONLINE_CONSISTENT_READ_ONLY -> TxMode.ONLINE_RO;
case ONLINE_INCONSISTENT_READ_ONLY -> TxMode.ONLINE_INCONSISTENT_RO;
case STALE_CONSISTENT_READ_ONLY -> TxMode.STALE_RO;
case SNAPSHOT -> TxMode.SNAPSHOT_RO;
// TxMode.NONE corresponds to DDL statements, and we have no DDL statements in YOJ transactions
};
}

@Override
public String getSessionId() {
Preconditions.checkState(!isBadSession, "No active YDB session (tx closed by YDB side)");
Preconditions.checkState(session != null, "No active YDB session");
return session.getId();
}

@Override
public CompletableFuture<Status> getStatusFuture() {
throw new UnsupportedOperationException();
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import tech.ydb.common.transaction.TxMode;
import tech.ydb.core.grpc.YdbHeaders;
import tech.ydb.core.utils.Version;
import tech.ydb.proto.OperationProtos;
Expand Down Expand Up @@ -96,6 +97,7 @@
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.junit.Assert.assertEquals;
import static tech.ydb.yoj.repository.db.EntityExpressions.newFilterBuilder;
import static tech.ydb.yoj.repository.db.EntityExpressions.newOrderBuilder;
Expand Down Expand Up @@ -963,6 +965,53 @@ public void creatingRepositoryDoesNotConnect() {
repository.shutdown();
}

@Test
public void ydbTransactionCompatibility() {
db.tx(() -> {
// No db tx or session yet!
var sdkTx = ((YdbRepositoryTransaction<?>) Tx.Current.get().getRepositoryTransaction()).toSdkTransaction();
assertThatIllegalStateException().isThrownBy(sdkTx::getSessionId);
assertThat(sdkTx.getId()).isNull();
assertThat(sdkTx.getTxMode()).isEqualTo(TxMode.SERIALIZABLE_RW);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(sdkTx::getStatusFuture);

// Perform any read - session and tx ID appear
db.projects().countAll();
sdkTx = ((YdbRepositoryTransaction<?>) Tx.Current.get().getRepositoryTransaction()).toSdkTransaction();
assertThat(sdkTx.getSessionId()).isNotNull();
assertThat(sdkTx.getId()).isNotNull();
assertThat(sdkTx.getTxMode()).isEqualTo(TxMode.SERIALIZABLE_RW);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(sdkTx::getStatusFuture);
});

for (var entry : Map.of(
IsolationLevel.ONLINE_CONSISTENT_READ_ONLY, TxMode.ONLINE_RO,
IsolationLevel.ONLINE_INCONSISTENT_READ_ONLY, TxMode.ONLINE_INCONSISTENT_RO,
IsolationLevel.STALE_CONSISTENT_READ_ONLY, TxMode.STALE_RO,
IsolationLevel.SNAPSHOT, TxMode.SNAPSHOT_RO
).entrySet()) {
var isolationLevel = entry.getKey();
var txMode = entry.getValue();

db.readOnly().withStatementIsolationLevel(isolationLevel).run(() -> {
// No db tx or session yet!
var sdkTx = ((YdbRepositoryTransaction<?>) Tx.Current.get().getRepositoryTransaction()).toSdkTransaction();
assertThatIllegalStateException().isThrownBy(sdkTx::getSessionId);
assertThat(sdkTx.getId()).isNull();
assertThat(sdkTx.getTxMode()).isEqualTo(txMode);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(sdkTx::getStatusFuture);

// Perform any read - session and tx ID appear
db.projects().countAll();
sdkTx = ((YdbRepositoryTransaction<?>) Tx.Current.get().getRepositoryTransaction()).toSdkTransaction();
assertThat(sdkTx.getSessionId()).isNotNull();
assertThat(sdkTx.getId()).isNull(); // Read transactions have no ID (that's what YDB returns, folks!)
assertThat(sdkTx.getTxMode()).isEqualTo(txMode);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(sdkTx::getStatusFuture);
});
}
}

@AllArgsConstructor
private static class DelegateSchemeServiceImplBase extends SchemeServiceGrpc.SchemeServiceImplBase {
@Delegate
Expand Down