package com.facebook.infrastructure.db;
import com.facebook.infrastructure.io.*;
import com.facebook.infrastructure.config.DatabaseDescriptor;
import com.facebook.infrastructure.utils.LogUtil;
import com.facebook.infrastructure.utils.CountingBloomFilter;
import java.io.IOException;
import java.io.File;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import org.apache.log4j.Logger;
/*
* This class represents the metadata of this Table. The metadata
* is basically the column family name and the ID associated with
* this column family. We use this ID in the Commit Log header to
* determine when a log file that has been rolled can be deleted.
*/
class TableMetadata
{
private static Logger logger_ = Logger.getLogger(Table.class);
/* Name of the column family */
public final static String cfName_ = "TableMetadata";
/*
* Name of one of the columns. The other columns are the individual
* column families in the system.
*/
public static final String cardinality_ = "PrimaryCardinality";
private static ICompactSerializer<TableMetadata> serializer_;
static
{
serializer_ = new TableMetadataSerializer();
}
private static TableMetadata tableMetadata_;
/* Use the following writer/reader to write/read to Metadata table */
private static IFileWriter writer_;
private static IFileReader reader_;
public static TableMetadata instance() throws IOException
{
if ( tableMetadata_ == null )
{
String file = getFileName();
writer_ = SequenceFile.writer(file);
reader_ = SequenceFile.reader(file);
TableMetadata.load();
if ( tableMetadata_ == null )
tableMetadata_ = new TableMetadata();
}
return tableMetadata_;
}
static ICompactSerializer<TableMetadata> serializer()
{
return serializer_;
}
private static void load() throws IOException
{
String file = TableMetadata.getFileName();
File f = new File(file);
if ( f.exists() )
{
DataOutputBuffer bufOut = new DataOutputBuffer();
DataInputBuffer bufIn = new DataInputBuffer();
if ( reader_ == null )
{
reader_ = SequenceFile.reader(file);
}
while ( !reader_.isEOF() )
{
/* Read the metadata info. */
reader_.next(bufOut);
bufIn.reset(bufOut.getData(), bufOut.getLength());
/* The key is the table name */
String key = bufIn.readUTF();
/* read the size of the data we ignore this value */
bufIn.readInt();
tableMetadata_ = TableMetadata.serializer().deserialize(bufIn);
break;
}
}
}
/* The mapping between column family and the column type. */
private Map<String, String> cfTypeMap_ = new HashMap<String, String>();
private Map<String, Integer> cfIdMap_ = new HashMap<String, Integer>();
private Map<Integer, String> idCfMap_ = new HashMap<Integer, String>();
private static String getFileName()
{
String table = DatabaseDescriptor.getTables().get(0);
return DatabaseDescriptor.getMetadataDirectory() + System.getProperty("file.separator") + table + "-Metadata.db";
}
public void add(String cf, int id)
{
add(cf, id, "Standard");
}
public void add(String cf, int id, String type)
{
cfIdMap_.put(cf, id);
idCfMap_.put(id, cf);
cfTypeMap_.put(cf, type);
}
boolean isEmpty()
{
return cfIdMap_.isEmpty();
}
int getColumnFamilyId(String columnFamily)
{
return cfIdMap_.get(columnFamily);
}
String getColumnFamilyName(int id)
{
return idCfMap_.get(id);
}
String getColumnFamilyType(String cfName)
{
return cfTypeMap_.get(cfName);
}
void setColumnFamilyType(String cfName, String type)
{
cfTypeMap_.put(cfName, type);
}
Set<String> getColumnFamilies()
{
return cfIdMap_.keySet();
}
int size()
{
return cfIdMap_.size();
}
boolean isValidColumnFamily(String cfName)
{
return cfIdMap_.containsKey(cfName);
}
CountingBloomFilter cardinality()
{
return null;
}
void apply() throws IOException
{
String table = DatabaseDescriptor.getTables().get(0);
DataOutputBuffer bufOut = new DataOutputBuffer();
TableMetadata.serializer_.serialize(this, bufOut);
try
{
writer_.append(table, bufOut);
}
catch ( IOException ex )
{
writer_.seek(0L);
logger_.debug(LogUtil.throwableToString(ex));
}
}
public void reset() throws IOException
{
writer_.seek(0L);
apply();
}
public String toString()
{
StringBuilder sb = new StringBuilder("");
Set<String> cfNames = cfIdMap_.keySet();
for ( String cfName : cfNames )
{
sb.append(cfName);
sb.append("---->");
sb.append(cfIdMap_.get(cfName));
sb.append(System.getProperty("line.separator"));
}
return sb.toString();
}
static class TableMetadataSerializer implements ICompactSerializer<TableMetadata>
{
public void serialize(TableMetadata tmetadata, DataOutputStream dos) throws IOException
{
int size = tmetadata.cfIdMap_.size();
dos.writeInt(size);
Set<String> cfNames = tmetadata.cfIdMap_.keySet();
for ( String cfName : cfNames )
{
dos.writeUTF(cfName);
dos.writeInt( tmetadata.cfIdMap_.get(cfName).intValue() );
dos.writeUTF(tmetadata.getColumnFamilyType(cfName));
}
}
public TableMetadata deserialize(DataInputStream dis) throws IOException
{
TableMetadata tmetadata = new TableMetadata();
int size = dis.readInt();
for( int i = 0; i < size; ++i )
{
String cfName = dis.readUTF();
int id = dis.readInt();
String type = dis.readUTF();
tmetadata.add(cfName, id, type);
}
return tmetadata;
}
}
}