View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.master;
20  
21  import java.io.IOException;
22  import java.util.NavigableSet;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.classification.InterfaceAudience;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.fs.FileStatus;
29  import org.apache.hadoop.fs.FileSystem;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.HRegionInfo;
32  import org.apache.hadoop.hbase.HTableDescriptor;
33  import org.apache.hadoop.hbase.NamespaceDescriptor;
34  import org.apache.hadoop.hbase.TableName;
35  import org.apache.hadoop.hbase.ZKNamespaceManager;
36  import org.apache.hadoop.hbase.catalog.MetaReader;
37  import org.apache.hadoop.hbase.client.Delete;
38  import org.apache.hadoop.hbase.client.Get;
39  import org.apache.hadoop.hbase.client.HTable;
40  import org.apache.hadoop.hbase.client.Put;
41  import org.apache.hadoop.hbase.client.Result;
42  import org.apache.hadoop.hbase.client.ResultScanner;
43  import org.apache.hadoop.hbase.constraint.ConstraintException;
44  import org.apache.hadoop.hbase.master.handler.CreateTableHandler;
45  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
46  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
47  import org.apache.hadoop.hbase.util.Bytes;
48  
49  import com.google.common.collect.Sets;
50  import org.apache.hadoop.hbase.util.FSUtils;
51  
52  /**
53   * This is a helper class used to manage the namespace
54   * metadata that is stored in TableName.NAMESPACE_TABLE_NAME
55   * It also mirrors updates to the ZK store by forwarding updates to
56   * {@link org.apache.hadoop.hbase.ZKNamespaceManager}
57   */
58  @InterfaceAudience.Private
59  public class TableNamespaceManager {
60    private static final Log LOG = LogFactory.getLog(TableNamespaceManager.class);
61  
62    private Configuration conf;
63    private MasterServices masterServices;
64    private HTable table;
65    private ZKNamespaceManager zkNamespaceManager;
66  
67    public TableNamespaceManager(MasterServices masterServices) throws IOException {
68      this.masterServices = masterServices;
69      this.conf = masterServices.getConfiguration();
70    }
71  
72    public void start() throws IOException {
73      TableName tableName = TableName.NAMESPACE_TABLE_NAME;
74      try {
75        if (!MetaReader.tableExists(masterServices.getCatalogTracker(),
76            tableName)) {
77          LOG.info("Namespace table not found. Creating...");
78          createNamespaceTable(masterServices);
79        }
80      } catch (InterruptedException e) {
81        throw new IOException("Wait for namespace table assignment interrupted", e);
82      }
83      table = new HTable(conf, tableName);
84      zkNamespaceManager = new ZKNamespaceManager(masterServices.getZooKeeper());
85      zkNamespaceManager.start();
86  
87      if (get(NamespaceDescriptor.DEFAULT_NAMESPACE.getName()) == null) {
88        create(NamespaceDescriptor.DEFAULT_NAMESPACE);
89      }
90      if (get(NamespaceDescriptor.SYSTEM_NAMESPACE.getName()) == null) {
91        create(NamespaceDescriptor.SYSTEM_NAMESPACE);
92      }
93  
94      ResultScanner scanner = table.getScanner(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES);
95      try {
96        for(Result result : scanner) {
97          NamespaceDescriptor ns =
98              ProtobufUtil.toNamespaceDescriptor(
99                  HBaseProtos.NamespaceDescriptor.parseFrom(
100                     result.getColumnLatest(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
101                         HTableDescriptor.NAMESPACE_COL_DESC_BYTES).getValue()));
102         zkNamespaceManager.update(ns);
103       }
104     } finally {
105       scanner.close();
106     }
107   }
108 
109 
110   public synchronized NamespaceDescriptor get(String name) throws IOException {
111     Result res = table.get(new Get(Bytes.toBytes(name)));
112     if (res.isEmpty()) {
113       return null;
114     }
115     return
116         ProtobufUtil.toNamespaceDescriptor(
117             HBaseProtos.NamespaceDescriptor.parseFrom(
118                 res.getColumnLatest(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
119                     HTableDescriptor.NAMESPACE_COL_DESC_BYTES).getValue()));
120   }
121 
122   public synchronized void create(NamespaceDescriptor ns) throws IOException {
123     if (get(ns.getName()) != null) {
124       throw new ConstraintException("Namespace "+ns.getName()+" already exists");
125     }
126     FileSystem fs = masterServices.getMasterFileSystem().getFileSystem();
127     fs.mkdirs(FSUtils.getNamespaceDir(
128         masterServices.getMasterFileSystem().getRootDir(), ns.getName()));
129     upsert(ns);
130   }
131 
132   public synchronized void update(NamespaceDescriptor ns) throws IOException {
133     if (get(ns.getName()) == null) {
134       throw new ConstraintException("Namespace "+ns.getName()+" does not exist");
135     }
136     upsert(ns);
137   }
138 
139   private void upsert(NamespaceDescriptor ns) throws IOException {
140     Put p = new Put(Bytes.toBytes(ns.getName()));
141     p.add(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
142         HTableDescriptor.NAMESPACE_COL_DESC_BYTES,
143         ProtobufUtil.toProtoNamespaceDescriptor(ns).toByteArray());
144     table.put(p);
145     try {
146       zkNamespaceManager.update(ns);
147     } catch(IOException ex) {
148       String msg = "Failed to update namespace information in ZK. Aborting.";
149       LOG.fatal(msg, ex);
150       masterServices.abort(msg, ex);
151     }
152   }
153 
154   public synchronized void remove(String name) throws IOException {
155     if (NamespaceDescriptor.RESERVED_NAMESPACES.contains(name)) {
156       throw new ConstraintException("Reserved namespace "+name+" cannot be removed.");
157     }
158     int tableCount = masterServices.listTableDescriptorsByNamespace(name).size();
159     if (tableCount > 0) {
160       throw new ConstraintException("Only empty namespaces can be removed. " +
161           "Namespace "+name+" has "+tableCount+" tables");
162     }
163     Delete d = new Delete(Bytes.toBytes(name));
164     table.delete(d);
165     //don't abort if cleanup isn't complete
166     //it will be replaced on new namespace creation
167     zkNamespaceManager.remove(name);
168     FileSystem fs = masterServices.getMasterFileSystem().getFileSystem();
169     for(FileStatus status :
170             fs.listStatus(FSUtils.getNamespaceDir(
171                 masterServices.getMasterFileSystem().getRootDir(), name))) {
172       if (!HConstants.HBASE_NON_TABLE_DIRS.contains(status.getPath().getName())) {
173         throw new IOException("Namespace directory contains table dir: "+status.getPath());
174       }
175     }
176     if (!fs.delete(FSUtils.getNamespaceDir(
177         masterServices.getMasterFileSystem().getRootDir(), name), true)) {
178       throw new IOException("Failed to remove namespace: "+name);
179     }
180   }
181 
182   public synchronized NavigableSet<NamespaceDescriptor> list() throws IOException {
183     NavigableSet<NamespaceDescriptor> ret =
184         Sets.newTreeSet(NamespaceDescriptor.NAMESPACE_DESCRIPTOR_COMPARATOR);
185     ResultScanner scanner = table.getScanner(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES);
186     try {
187       for(Result r : scanner) {
188           ret.add(ProtobufUtil.toNamespaceDescriptor(
189               HBaseProtos.NamespaceDescriptor.parseFrom(
190                 r.getColumnLatest(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
191                     HTableDescriptor.NAMESPACE_COL_DESC_BYTES).getValue())));
192       }
193     } finally {
194       scanner.close();
195     }
196     return ret;
197   }
198 
199   private void createNamespaceTable(MasterServices masterServices) throws IOException, InterruptedException {
200     HRegionInfo newRegions[] = new HRegionInfo[]{
201         new HRegionInfo(HTableDescriptor.NAMESPACE_TABLEDESC.getTableName(), null, null)};
202 
203     //we need to create the table this way to bypass
204     //checkInitialized
205     masterServices.getExecutorService()
206         .submit(new CreateTableHandler(masterServices,
207             masterServices.getMasterFileSystem(),
208             HTableDescriptor.NAMESPACE_TABLEDESC,
209             masterServices.getConfiguration(),
210             newRegions,
211             masterServices).prepare());
212     //wait for region to be online
213     int tries = conf.getInt("hbase.master.namespace.init.timeout", 600);
214     while(masterServices.getAssignmentManager()
215         .getRegionStates().getRegionServerOfRegion(newRegions[0]) == null &&
216         tries > 0) {
217       Thread.sleep(100);
218       tries--;
219     }
220     if (tries <= 0) {
221       throw new IOException("Failed to create namespace table.");
222     }
223   }
224 }