<< " was " << cap_string(old_caps) << endl;
// did file size decrease?
- if ((old_caps & new_caps & CAP_FILE_RDCACHE) &&
+ if ((old_caps & (CAP_FILE_RD|CAP_FILE_WR)) == 0 &&
+ (new_caps & (CAP_FILE_RD|CAP_FILE_WR)) != 0 &&
in->inode.size > m->get_inode().size) {
- dout(10) << "**** file size decreased from " << in->inode.size << " to " << m->get_inode().size << " FIXME" << endl;
- // must have been a truncate() by someone.
- // trim the buffer cache
- // ***** fixme write me ****
+ dout(10) << "*** file size decreased from " << in->inode.size << " to " << m->get_inode().size << endl;
+
+ // trim filecache?
+ if (g_conf.client_oc)
+ in->fc.truncate(in->inode.size, m->get_inode().size);
- in->file_wr_size = m->get_inode().size; //??
+ in->inode.size = in->file_wr_size = m->get_inode().size;
}
// update inode
}
}
+// truncate
+
+void FileCache::truncate(off_t olds, off_t news)
+{
+ dout(5) << "truncate " << olds << " -> " << news << endl;
+
+ // map range to objects
+ list<ObjectExtent> ls;
+ oc->filer.file_to_extents(inode, news, olds-news, ls);
+ oc->truncate_set(inode.ino, ls);
+}
+
// caps
class C_FC_CheckCaps : public Context {
}
-
-void FileCache::check_caps()
+int FileCache::get_used_caps()
{
- // calc used
int used = 0;
if (num_reading) used |= CAP_FILE_RD;
if (oc->set_is_cached(inode.ino)) used |= CAP_FILE_RDCACHE;
if (num_writing) used |= CAP_FILE_WR;
if (oc->set_is_dirty_or_committing(inode.ino)) used |= CAP_FILE_WRBUFFER;
- dout(10) << "check_caps used " << cap_string(used) << endl;
+ return used;
+}
+
+void FileCache::check_caps()
+{
+ // calc used
+ int used = get_used_caps();
+ dout(10) << "check_caps used was " << cap_string(used) << endl;
// try to implement caps?
// BUG? latest_caps, not least caps i've seen?
(used & CAP_FILE_WRBUFFER))
flush_dirty(new C_FC_CheckCaps(this));
+ used = get_used_caps();
+ dout(10) << "check_caps used now " << cap_string(used) << endl;
+
// check callbacks
map<int, list<Context*> >::iterator p = caps_callbacks.begin();
while (p != caps_callbacks.end()) {
bool all_safe();// { return num_unsafe == 0; }
void add_safe_waiter(Context *c);
+
+ void truncate(off_t olds, off_t news);
// ...
void flush_dirty(Context *onflush=0);
void tear_down();
int get_caps() { return latest_caps; }
+ int get_used_caps();
void set_caps(int caps, Context *onimplement=0);
void check_caps();
} else if (strcmp(args[i],"optest") == 0) {
syn_modes.push_back( SYNCLIENT_MODE_OPTEST );
syn_iargs.push_back( atoi(args[++i]) );
+
+ } else if (strcmp(args[i],"truncate") == 0) {
+ syn_modes.push_back( SYNCLIENT_MODE_TRUNCATE );
+ syn_sargs.push_back(args[++i]);
+ syn_iargs.push_back(atoi(args[++i]));
} else {
cerr << "unknown syn arg " << args[i] << endl;
assert(0);
}
}
break;
+
+ case SYNCLIENT_MODE_TRUNCATE:
+ {
+ string file = get_sarg(0);
+ sargs.push_front(file);
+ int iarg1 = iargs.front(); iargs.pop_front();
+ if (run_me())
+ client->truncate(file.c_str(), iarg1);
+ }
+ break;
default:
assert(0);
continue;
}
+ // print
+ char *tm = ctime(&st.st_mtime);
+ tm[strlen(tm)-1] = 0;
+ printf("%c%c%c%c%c%c%c%c%c%c %2d %5d %5d %8d %12s %s\n",
+ S_ISDIR(st.st_mode) ? 'd':'-',
+ (st.st_mode & 0400) ? 'r':'-',
+ (st.st_mode & 0200) ? 'w':'-',
+ (st.st_mode & 0100) ? 'x':'-',
+ (st.st_mode & 040) ? 'r':'-',
+ (st.st_mode & 020) ? 'w':'-',
+ (st.st_mode & 010) ? 'x':'-',
+ (st.st_mode & 04) ? 'r':'-',
+ (st.st_mode & 02) ? 'w':'-',
+ (st.st_mode & 01) ? 'x':'-',
+ (int)st.st_nlink,
+ st.st_uid, st.st_gid,
+ (int)st.st_size,
+ tm,
+ file.c_str());
+
+
if ((st.st_mode & INODE_TYPE_MASK) == INODE_MODE_DIR) {
dirq.push_back(file);
}
#define SYNCLIENT_MODE_RANDOMSLEEP 61
#define SYNCLIENT_MODE_SLEEP 62
+#define SYNCLIENT_MODE_TRUNCATE 200
+
int play_trace(Trace& t, string& prefix);
void make_dir_mess(const char *basedir, int n);
-
};
#endif
#define LOCK_GLOCKR 2 // AR R . / C . . . . . . . / C . . . . .
// file lock states
-#define LOCK_GLOCKL 3 // A . . / . . . . . . loner -> lock
+#define LOCK_GLOCKL 3 // A . . / C . . . . . loner -> lock
#define LOCK_GLOCKM 4 // A . . / . . . . . .
#define LOCK_MIXED 5 // AR . . / . R W A . L . . / . R . . . L
#define LOCK_GMIXEDR 6 // AR R . / . R . . . L . . / . R . . . L
return CAP_FILE_RDCACHE | CAP_FILE_RD | CAP_FILE_LAZYIO;
case LOCK_LOCK:
case LOCK_GLOCKR:
+ case LOCK_GLOCKL:
return CAP_FILE_RDCACHE;
- case LOCK_GLOCKL:
case LOCK_GLOCKM:
return 0;
case LOCK_GLOCKR:
case LOCK_GLOCKM:
case LOCK_GLOCKL:
- if (issued == 0) {
+ if ((issued & ~CAP_FILE_RDCACHE) == 0) {
in->filelock.set_state(LOCK_LOCK);
// waiters
}
+void ObjectCacher::Object::truncate(off_t s)
+{
+ dout(10) << "truncate to " << s << endl;
+
+ while (!data.empty()) {
+ BufferHead *bh = data.rbegin()->second;
+ if (bh->end() <= s)
+ break;
+
+ // split bh at truncation point?
+ if (bh->start() < s) {
+ split(bh, s);
+ continue;
+ }
+
+ // remove bh entirely
+ assert(bh->start() >= s);
+ oc->bh_remove(this, bh);
+ delete bh;
+ }
+}
+
/*** ObjectCacher ***/
p != ob->data.end();
p++) {
BufferHead *bh = p->second;
- dout(0) << "purge forcibly removing " << *bh << endl;
+ if (!bh->is_clean())
+ dout(0) << "purge forcibly removing " << *ob << " " << *bh << endl;
bh_remove(ob, bh);
delete bh;
}
return unclean;
}
+void ObjectCacher::truncate_set(inodeno_t ino, list<ObjectExtent>& exls)
+{
+ if (objects_by_ino.count(ino) == 0) {
+ dout(10) << "truncate_set on " << ino << " dne" << endl;
+ return;
+ }
+
+ dout(10) << "truncate_set " << ino << endl;
+
+ for (list<ObjectExtent>::iterator p = exls.begin();
+ p != exls.end();
+ ++p) {
+ ObjectExtent &ex = *p;
+ if (objects.count(ex.oid) == 0) continue;
+ Object *ob = objects[ex.oid];
+
+ // purge or truncate?
+ if (ex.start == 0) {
+ dout(10) << "truncate_set purging " << *ob << endl;
+ purge(ob);
+ } else {
+ // hrm, truncate object
+ dout(10) << "truncate_set truncating " << *ob << " at " << ex.start << endl;
+ ob->truncate(ex.start);
+
+ if (ob->can_close()) {
+ dout(10) << "truncate_set trimming " << *ob << endl;
+ close_object(ob);
+ }
+ }
+ }
+}
+
void ObjectCacher::kick_sync_writers(inodeno_t ino)
{
map<off_t, BufferHead*>& rx);
BufferHead *map_write(Objecter::OSDWrite *wr);
+ void truncate(off_t s);
};
// ******* ObjectCacher *********
off_t release_set(inodeno_t ino); // returns # of bytes not released (ie non-clean)
+ void truncate_set(inodeno_t ino, list<ObjectExtent>& ex);
+
void kick_sync_writers(inodeno_t ino);
void kick_sync_readers(inodeno_t ino);