/**
* Copyright 2015-2017 The OpenZipkin Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package zipkin.storage.mysql;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Executor;
import javax.sql.DataSource;
import org.jooq.ExecuteListenerProvider;
import org.jooq.conf.Settings;
import zipkin.internal.Lazy;
import zipkin.internal.Nullable;
import zipkin.storage.AsyncSpanConsumer;
import zipkin.storage.AsyncSpanStore;
import zipkin.storage.SpanStore;
import zipkin.storage.StorageComponent;
import static zipkin.internal.Util.checkNotNull;
import static zipkin.storage.StorageAdapters.blockingToAsync;
import static zipkin.storage.mysql.internal.generated.tables.ZipkinAnnotations.ZIPKIN_ANNOTATIONS;
import static zipkin.storage.mysql.internal.generated.tables.ZipkinDependencies.ZIPKIN_DEPENDENCIES;
import static zipkin.storage.mysql.internal.generated.tables.ZipkinSpans.ZIPKIN_SPANS;
public final class MySQLStorage implements StorageComponent {
public static Builder builder() {
return new Builder();
}
public final static class Builder implements StorageComponent.Builder {
boolean strictTraceId = true;
private DataSource datasource;
private Settings settings = new Settings().withRenderSchema(false);
private ExecuteListenerProvider listenerProvider;
private Executor executor;
/** {@inheritDoc} */
@Override public Builder strictTraceId(boolean strictTraceId) {
this.strictTraceId = strictTraceId;
return this;
}
public Builder datasource(DataSource datasource) {
this.datasource = checkNotNull(datasource, "datasource");
return this;
}
public Builder settings(Settings settings) {
this.settings = checkNotNull(settings, "settings");
return this;
}
public Builder listenerProvider(@Nullable ExecuteListenerProvider listenerProvider) {
this.listenerProvider = listenerProvider;
return this;
}
public Builder executor(Executor executor) {
this.executor = checkNotNull(executor, "executor");
return this;
}
@Override public MySQLStorage build() {
return new MySQLStorage(this);
}
Builder() {
}
}
static {
System.setProperty("org.jooq.no-logo", "true");
}
private final DataSource datasource;
private final Executor executor;
private final DSLContexts context;
final Lazy<Schema> schema;
final boolean strictTraceId;
MySQLStorage(MySQLStorage.Builder builder) {
this.datasource = checkNotNull(builder.datasource, "datasource");
this.executor = checkNotNull(builder.executor, "executor");
this.context = new DSLContexts(builder.settings, builder.listenerProvider);
this.schema = new Lazy<Schema>() {
@Override protected Schema compute() {
return new Schema(datasource, context);
}
};
this.strictTraceId = builder.strictTraceId;
}
/** Returns the session in use by this storage component. */
public DataSource datasource() {
return datasource;
}
@Override public SpanStore spanStore() {
return new MySQLSpanStore(datasource, context, schema.get(), strictTraceId);
}
@Override public AsyncSpanStore asyncSpanStore() {
return blockingToAsync(spanStore(), executor);
}
@Override public AsyncSpanConsumer asyncSpanConsumer() {
MySQLSpanConsumer spanConsumer = new MySQLSpanConsumer(datasource, context, schema.get());
return blockingToAsync(spanConsumer, executor);
}
@Override public CheckResult check() {
try (Connection conn = datasource.getConnection()) {
context.get(conn).select(ZIPKIN_SPANS.TRACE_ID).from(ZIPKIN_SPANS).limit(1).execute();
} catch (SQLException | RuntimeException e) {
return CheckResult.failed(e);
}
return CheckResult.OK;
}
@Override public void close() {
// didn't open the DataSource or executor
}
/** Visible for testing */
void clear() {
try (Connection conn = datasource.getConnection()) {
context.get(conn).truncate(ZIPKIN_SPANS).execute();
context.get(conn).truncate(ZIPKIN_ANNOTATIONS).execute();
context.get(conn).truncate(ZIPKIN_DEPENDENCIES).execute();
} catch (SQLException | RuntimeException e) {
throw new AssertionError(e);
}
}
}