e.mem_obj->memCache.index = -1;
e.mem_obj->memCache.io = MemObject::ioDone;
- map->closeForWriting(index, false);
+ map->closeForWriting(index);
CollapsedForwarding::Broadcast(e); // before we close our transient entry!
Store::Root().transientsCompleteWriting(e);
void
Transients::monitorIo(StoreEntry *e, const cache_key *key, const Store::IoStatus direction)
{
- assert(direction == Store::ioReading || direction == Store::ioWriting);
-
if (!e->hasTransients()) {
addEntry(e, key, direction);
- e->mem_obj->xitTable.io = direction;
+ assert(e->hasTransients());
}
- assert(e->hasTransients());
const auto index = e->mem_obj->xitTable.index;
if (const auto old = locals->at(index)) {
assert(old == e);
}
}
-/// creates a new Transients entry or throws
+/// creates a new Transients entry
void
Transients::addEntry(StoreEntry *e, const cache_key *key, const Store::IoStatus direction)
{
Ipc::StoreMapAnchor *slot = map->openForWriting(key, index);
Must(slot); // no writer collisions
- slot->set(*e, key);
+ // set ASAP in hope to unlock the slot if something throws
e->mem_obj->xitTable.index = index;
+ e->mem_obj->xitTable.io = Store::ioWriting;
+
+ slot->set(*e, key);
if (direction == Store::ioWriting) {
- // keep write lock; the caller will decide what to do with it
- map->startAppending(e->mem_obj->xitTable.index);
+ // allow reading and receive remote DELETE events, but do not switch to
+ // the reading lock because transientReaders() callers want true readers
+ map->startAppending(index);
} else {
+ assert(direction == Store::ioReading);
// keep the entry locked (for reading) to receive remote DELETE events
- map->closeForWriting(e->mem_obj->xitTable.index);
+ map->switchWritingToReading(index);
+ e->mem_obj->xitTable.io = Store::ioReading;
}
}
{
assert(e.hasTransients());
assert(isWriter(e));
- map->closeForWriting(e.mem_obj->xitTable.index, true);
+ map->switchWritingToReading(e.mem_obj->xitTable.index);
e.mem_obj->xitTable.io = Store::ioReading;
}
anchor.basics.swap_file_sz = le.size;
EBIT_SET(anchor.basics.flags, ENTRY_VALIDATED);
le.state(LoadingEntry::leLoaded);
- sd->map->closeForWriting(fileNo, false);
+ sd->map->closeForWriting(fileNo);
++counts.objcount;
}
if (sio.touchingStoreEntry()) {
sio.e->swap_file_sz = sio.writeableAnchor_->basics.swap_file_sz =
sio.offset_;
-
- // close, the entry gets the read lock
- map->closeForWriting(sio.swap_filen, true);
+ map->switchWritingToReading(sio.swap_filen);
+ // sio.e keeps the (now read) lock on the anchor
}
sio.writeableAnchor_ = NULL;
sio.splicingPoint = request->sidCurrent;
}
void
-Ipc::MemMap::closeForWriting(const sfileno fileno, bool lockForReading)
+Ipc::MemMap::closeForWriting(const sfileno fileno)
{
- debugs(54, 5, "closing slot at " << fileno << " for writing and "
- "openning for reading in map [" << path << ']');
+ debugs(54, 5, "stop writing slot at " << fileno <<
+ " in map [" << path << ']');
assert(valid(fileno));
Slot &s = shared->slots[fileno];
assert(s.writing());
- if (lockForReading)
- s.lock.switchExclusiveToShared();
- else
- s.lock.unlockExclusive();
+ s.lock.unlockExclusive();
+}
+
+void
+Ipc::MemMap::switchWritingToReading(const sfileno fileno)
+{
+ debugs(54, 5, "switching writing slot at " << fileno <<
+ " to reading in map [" << path << ']');
+ assert(valid(fileno));
+ Slot &s = shared->slots[fileno];
+ assert(s.writing());
+ s.lock.switchExclusiveToShared();
}
/// terminate writing the entry, freeing its slot for others to use
Slot *openForWritingAt(sfileno fileno, bool overwriteExisting = true);
/// successfully finish writing the entry
- void closeForWriting(const sfileno fileno, bool lockForReading = false);
+ void closeForWriting(const sfileno fileno);
+
+ /// stop writing the locked entry and start reading it
+ void switchWritingToReading(const sfileno fileno);
/// only works on locked entries; returns nil unless the slot is readable
const Slot *peekAtReader(const sfileno fileno) const;
}
void
-Ipc::StoreMap::closeForWriting(const sfileno fileno, bool lockForReading)
+Ipc::StoreMap::closeForWriting(const sfileno fileno)
{
Anchor &s = anchorAt(fileno);
assert(s.writing());
- if (lockForReading) {
- s.lock.switchExclusiveToShared();
- debugs(54, 5, "switched entry " << fileno <<
- " from writing to reading " << path);
- assert(s.complete());
- } else {
- s.lock.unlockExclusive();
- debugs(54, 5, "closed entry " << fileno << " for writing " << path);
- // cannot assert completeness here because we have no lock
- }
+ // TODO: assert(!s.empty()); // i.e., unlocked s becomes s.complete()
+ s.lock.unlockExclusive();
+ debugs(54, 5, "closed entry " << fileno << " for writing " << path);
+ // cannot assert completeness here because we have no lock
+}
+
+void
+Ipc::StoreMap::switchWritingToReading(const sfileno fileno)
+{
+ debugs(54, 5, "switching entry " << fileno << " from writing to reading " << path);
+ Anchor &s = anchorAt(fileno);
+ assert(s.writing());
+ s.lock.switchExclusiveToShared();
+ assert(s.complete());
}
Ipc::StoreMap::Slice &
/// restrict opened for writing entry to appending operations; allow reads
void startAppending(const sfileno fileno);
/// successfully finish creating or updating the entry at fileno pos
- void closeForWriting(const sfileno fileno, bool lockForReading = false);
+ void closeForWriting(const sfileno fileno);
+ /// stop writing (or updating) the locked entry and start reading it
+ void switchWritingToReading(const sfileno fileno);
/// unlock and "forget" openForWriting entry, making it Empty again
/// this call does not free entry slices so the caller has to do that
void forgetWritingEntry(const sfileno fileno);