/**
* Copyright (C) 2009-2015 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.server;
import com.foundationdb.ais.model.PrimaryKey;
import com.foundationdb.ais.model.Table;
import com.foundationdb.qp.virtualadapter.VirtualScanFactory;
import com.foundationdb.server.service.session.Session;
import com.foundationdb.server.store.MemoryTransaction;
import com.foundationdb.server.store.MemoryTransactionService;
import com.foundationdb.server.store.format.MemoryStorageDescription;
import java.util.HashMap;
import java.util.Map;
import static com.foundationdb.server.store.MemoryStore.join;
import static com.foundationdb.server.store.MemoryStore.packLong;
import static com.foundationdb.server.store.MemoryStore.packUUID;
import static com.foundationdb.server.store.MemoryStore.unpackLong;
public class MemoryTableStatusCache implements TableStatusCache
{
private final Map<Integer,VirtualTableStatus> virtualTableStatusMap = new HashMap<>();
private final MemoryTransactionService txnService;
private final byte[] statusPrefix;
public MemoryTableStatusCache(MemoryTransactionService txnService, byte[] statusPrefix) {
this.txnService = txnService;
this.statusPrefix = statusPrefix;
}
public byte[] getStatusPrefix() {
return statusPrefix;
}
//
// TableStatusCache
//
@Override
public TableStatus createTableStatus(Table table) {
return new MemoryTableStatus(table);
}
@Override
public synchronized TableStatus getOrCreateVirtualTableStatus(int tableID, VirtualScanFactory factory) {
VirtualTableStatus status = virtualTableStatusMap.get(tableID);
if(status == null) {
status = new VirtualTableStatus(tableID, factory);
virtualTableStatusMap.put(tableID, status);
}
return status;
}
@Override
public void detachAIS() {
// None
}
@Override
public void clearTableStatus(Session session, Table table) {
TableStatus status = table.tableStatus();
if(status instanceof VirtualTableStatus) {
synchronized(virtualTableStatusMap) {
virtualTableStatusMap.remove(table.getTableId());
}
} else {
MemoryTableStatus tmStatus = (MemoryTableStatus)status;
MemoryTransaction txn = txnService.getTransaction(session);
txn.clear(tmStatus.statusKey);
}
}
//
// Internal
//
private class MemoryTableStatus implements TableStatus
{
private final int tableID;
private final byte[] statusKey;
private MemoryTableStatus(Table table) {
this.tableID = table.getTableId();
// packLong(tableID) seems like a good option but ALTER keeps same ID => doubles row count
PrimaryKey pk = table.getPrimaryKeyIncludingInternal();
assert pk != null : table;
MemoryStorageDescription sd = (MemoryStorageDescription)pk.getIndex().getStorageDescription();
this.statusKey = join(statusPrefix, sd.getUUIDBytes());
}
@Override
public void rowDeleted(Session session) {
rowsWritten(session, -1);
}
@Override
public void rowsWritten(Session session, long count) {
setRowCount(session, getRowCount(session) + count);
}
@Override
public void truncate(Session session) {
setRowCount(session, 0);
}
@Override
public long getRowCount(Session session) {
MemoryTransaction txn = txnService.getTransaction(session);
byte[] value = txn.get(statusKey);
return (value == null) ? 0 : unpackLong(value);
}
@Override
public long getApproximateRowCount(Session session) {
MemoryTransaction txn = txnService.getTransaction(session);
byte[] value = txn.getUncommitted(statusKey);
return (value == null) ? 0 : unpackLong(value);
}
@Override
public int getTableID() {
return tableID;
}
@Override
public void setRowCount(Session session, long rowCount) {
MemoryTransaction txn = txnService.getTransaction(session);
txn.set(statusKey, packLong(rowCount));
}
}
}