View Javadoc
1   /*
2    * Copyright 2021 TiKV Project Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  
18  package org.tikv.common.catalog;
19  
20  import static org.tikv.common.codec.MetaCodec.KEY_DBs;
21  
22  import com.fasterxml.jackson.core.JsonParseException;
23  import com.fasterxml.jackson.databind.JsonMappingException;
24  import com.fasterxml.jackson.databind.ObjectMapper;
25  import com.google.common.collect.ImmutableList;
26  import com.google.protobuf.ByteString;
27  import java.nio.charset.StandardCharsets;
28  import java.util.List;
29  import java.util.Objects;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  import org.tikv.common.Snapshot;
33  import org.tikv.common.codec.CodecDataInput;
34  import org.tikv.common.codec.KeyUtils;
35  import org.tikv.common.codec.MetaCodec;
36  import org.tikv.common.exception.TiClientInternalException;
37  import org.tikv.common.meta.TiDBInfo;
38  import org.tikv.common.meta.TiTableInfo;
39  import org.tikv.common.util.Pair;
40  
41  public class CatalogTransaction {
42    protected static final Logger logger = LoggerFactory.getLogger(CatalogTransaction.class);
43    private final Snapshot snapshot;
44  
45    CatalogTransaction(Snapshot snapshot) {
46      this.snapshot = snapshot;
47    }
48  
49    public static <T> T parseFromJson(ByteString json, Class<T> cls) {
50      Objects.requireNonNull(json, "json is null");
51      Objects.requireNonNull(cls, "cls is null");
52  
53      logger.debug(String.format("Parse Json %s : %s", cls.getSimpleName(), json.toStringUtf8()));
54      ObjectMapper mapper = new ObjectMapper();
55      try {
56        return mapper.readValue(json.toStringUtf8(), cls);
57      } catch (JsonParseException | JsonMappingException e) {
58        String errMsg =
59            String.format(
60                "Invalid JSON value for Type %s: %s\n", cls.getSimpleName(), json.toStringUtf8());
61        throw new TiClientInternalException(errMsg, e);
62      } catch (Exception e1) {
63        throw new TiClientInternalException("Error parsing Json", e1);
64      }
65    }
66  
67    long getLatestSchemaVersion() {
68      ByteString versionBytes = MetaCodec.bytesGet(MetaCodec.KEY_SCHEMA_VERSION, this.snapshot);
69      CodecDataInput cdi = new CodecDataInput(versionBytes.toByteArray());
70      return Long.parseLong(new String(cdi.toByteArray(), StandardCharsets.UTF_8));
71    }
72  
73    public List<TiDBInfo> getDatabases() {
74      List<Pair<ByteString, ByteString>> fields =
75          MetaCodec.hashGetFields(MetaCodec.KEY_DBs, this.snapshot);
76      ImmutableList.Builder<TiDBInfo> builder = ImmutableList.builder();
77      for (Pair<ByteString, ByteString> pair : fields) {
78        builder.add(parseFromJson(pair.second, TiDBInfo.class));
79      }
80      return builder.build();
81    }
82  
83    TiDBInfo getDatabase(long id) {
84      ByteString dbKey = MetaCodec.encodeDatabaseID(id);
85      ByteString json = MetaCodec.hashGet(KEY_DBs, dbKey, this.snapshot);
86      if (json == null || json.isEmpty()) {
87        return null;
88      }
89      return parseFromJson(json, TiDBInfo.class);
90    }
91  
92    List<TiTableInfo> getTables(long dbId) {
93      ByteString dbKey = MetaCodec.encodeDatabaseID(dbId);
94      List<Pair<ByteString, ByteString>> fields = MetaCodec.hashGetFields(dbKey, this.snapshot);
95      ImmutableList.Builder<TiTableInfo> builder = ImmutableList.builder();
96      for (Pair<ByteString, ByteString> pair : fields) {
97        if (KeyUtils.hasPrefix(pair.first, ByteString.copyFromUtf8(MetaCodec.KEY_TABLE))) {
98          try {
99            TiTableInfo tableInfo = parseFromJson(pair.second, TiTableInfo.class);
100           if (!tableInfo.isSequence()) {
101             builder.add(tableInfo);
102           }
103         } catch (TiClientInternalException e) {
104           logger.warn("fail to parse table from json!", e);
105         }
106       }
107     }
108     return builder.build();
109   }
110 }